1 排序思想:算法
將排序表的n個記錄按照關鍵字建成堆,堆頂元素就是選擇出的最大(或最小)記錄,這樣就獲得排序的第一個記錄。再將剩下的n-1個記錄建成堆,獲得次大(或者次小)的記錄。如此反覆,直到執行n-1次後,排序結束。shell
大頂堆的性質:R[i]>=R[2i]且R[i]>=R[2i+1]數組
2 算法實現:ide
// 堆排序 void heap_sort(int num[], int n){ int i; // 將num[]調整成大頂堆 // 即num[i]>=num[2i]&&num[i]>=num[2i+1] for(i=n/2;i>=0;i--){ heap_adjust(num,i,n); } for(i=n-1;i>0;i--){ // 將每一輪的堆頂放在i SWAP(num[0],num[i]); // 再將剩下的i個記錄調整成大頂堆 heap_adjust(num,0,i); } } // 將num[s,q)段調整成大頂堆 // num[s]>=num[2s]且num[s]>=num[2s+1] void heap_adjust(int num[],int s,int q){ int rc=num[s]; int i; for(i=2*s;i<q;i*=2){ if(i<q-1&&num[i]<num[i+1]) i++; if(rc>=num[i]) break; // rc應當放在位置s num[s]=num[i]; s=i; } num[s]=rc; } #define SWAP(x,y) {int t; t = x; x = y; y = t;}
3 性能分析:性能
3.1 空間複雜度:O(1)ui
3.2 時間複雜度:平均和最壞時間複雜度是O(nlogn)spa
3.3 穩定性:不穩定.net
1 排序思想:blog
經過一趟排序,將待排序記錄分紅兩個部分,其中一部分的關鍵字都比另外一部分的關鍵字小。再分別對這兩部分進行排序,直到整個序列有序。排序
以整型數組爲例,一趟快速排序的方法:
待排序序列爲R[low...high],取一個基準,通常爲R[low]
設i=low,j=high-1
①從j向前搜索,直到j<=i或者R[j]< R[low],將R[j]與R[i]交換
②從i向後搜索,直到j<=i或者R[i]> R[low],將R[i]與R[j]交換
重複①、②步,直到j<=i,這樣完成一趟排序,i就是最終基準所放置的位置
2 算法實現:
// 對num[]的[low,high)段執行快速排序 void quick_sort(int num[],int low,int high){ if(low<high){ int pivotloc=partion(num,low,high); quick_sort(num,low,pivotloc); quick_sort(num,pivotloc+1,high); } } // 對num[]的[low,high)段,按照num[low]分割成兩部分 // 並返回最終num[low]所放置位置 int partion(int num[],int low,int high){ int i=low,j=high-1; int key=num[low]; while(i<j){ while(i<j&&key<=num[j]) j--; SWAP(num[i],num[j]); while(i<j&&key>=num[i]) i++; SWAP(num[i],num[j]); } return i; } // 交換 #define SWAP(x,y) {int t; t = x; x = y; y = t;}
3 性能分析:
3.1 空間複雜度:在理想狀態下是O(logn),最壞狀況下是O(n)
3.2 時間複雜度:
最好狀況:一趟排序須要對記錄進行比較約n次,則總的時間複雜度要看執行劃分的次數。理想狀況下,每次劃分都將序列分紅兩個等長的部分,則時間複雜度是O(nlogn)。最壞狀況下,每次劃分都只將序列分紅一部分,時間複雜度是O(n^2)。
平均時間複雜度是O(nlogn)
當序列已是正序,快速排序退化爲冒泡排序。
3.3 穩定性:不穩定
1 排序思想:
第1趟:取一正整數d1(d1<n)做爲第一個增量,對全部間隔爲d1的記錄進行直接插入排序。例如,對{a[k],a[k+d1],a[k+2d1],……}執行直接插入排序,其中,k=0,1,2,……,d1-1
第2趟:取一正整數d2(d2<d1),重複上一步的操做
直到所取的增量爲1
例如,原始數據:
第1趟排序,取增量爲5,如上圖,顏色相同的在同一組,對每組進行直接插入排序:
第2趟排序,取增量爲3,如上圖,顏色相同的在同一組,對每組進行直接插入排序:
第3趟排序,取增量爲1,即對上一步的結果進行直接插入排序:
2 算法實現:
// 根據增量序列dk[]對num[]進行希爾排序 void shell_sort(int num[],int num_len,int dk[],int dk_len){ int k; for(k=0;k<dk_len;k++) shell_pass(num,num_len,dk[k]); } // 根據增量d對num[]進行一次希爾排序 // 即對全部間隔爲d的記錄進行直接插入排序 void shell_pass(int num[],int num_len,int d){ int i,j,k,key; for(i=d;i<num_len;i++){ // 將num[i]插入到指定位置 key=num[i]; j=i-d; while(j>=0&&num[j]>key){ num[j+d]=num[j]; j-=d; } num[j+d]=key; } }
3 性能分析:
3.1 空間複雜度:如上代碼,僅在交換數據時使用一個輔助空間,空間複雜度是O(1)
3.2 時間複雜度:O(nlogn)-O(n^2)
3.3 穩定性:不穩定
1 排序思想:
第1趟:從第0個到第(n-1)個記錄中選擇關鍵字最小的記錄,與第0個記錄交換
第2趟:從第1個到第(n-1)個記錄中選擇關鍵字最小的記錄,與第1個記錄交換
……
第i趟:從第(i-1)和到第(n-1)個記錄中選擇關鍵字最小的記錄,與第(i-1)個記錄交換
……
直到第(n-1)趟,在最後兩個記錄中選擇關鍵字最小的,與第(n-2)個記錄交換
2 算法實現:
// 選擇排序 void select_sort(int num[], int n){ int i,j,min_index,tmp; // 要進行n-1趟排序 for(i=0;i<n-1;i++){ // min_index爲這一趟關鍵字最小的記錄的下標 min_index=i; // 從num[j,n-1]中找到關鍵字最小的 for(j=i+1;j<n;j++){ if(num[min_index]>num[j]) min_index=j; } // 交換 if(min_index!=i){ tmp=num[min_index]; num[min_index]=num[i]; num[i]=tmp; } } }
3 性能分析:
3.1 空間複雜度:如上代碼,僅在交換數據時使用一個輔助空間,空間複雜度是O(1)
3.2 時間複雜度:不論原始記錄如何,每一趟要進行的比較操做都是肯定的。以上面代碼爲例,第i趟排序,須要比較(n-i-1)次(從i+1到n-1),整個排序過程的比較次數爲
記錄移動的次數,最小是0次,最可能是3(n-1)次。
於是簡單排序算法的最好、最差和平均時間複雜度都是O(n^2)
3.3 穩定性:關於簡單排序的穩定性,有必定的爭議,通常認爲是不穩定的。可是上面的代碼,明顯是穩定的。要是遇到筆試題,仍是選擇不穩定吧。
1 排序思想:
將待排序表R一、R二、R三、……、R(n)當作是n個長度爲1的有序子表,對相鄰的兩個有序子表兩兩合併,獲得每兩個元素有序的表;再將長度爲2的有序子表兩兩合併,獲得每四個元素有序的表;直到獲得一個長度爲n的有序表。排序過程以下:
原始數據:
第1趟排序後:
第2趟排序後:
第3趟排序後:
第4趟排序後:
2 算法實現:
// 歸併排序 void merge_sort(int num[], int p, int r){ if(r-p>1){ int q=(p+r)/2; merge_sort(num, p, q); merge_sort(num, q, r); merge(num, p, q, r); } } // 將兩個列表歸併的過程,這裏表示將 // 列表num[]的num[p,q-1]和num[q,r-1]兩段有序子表歸併 void merge(int num[], int p, int q, int r){ int n1=q-p; int n2=r-q; // 建立兩個列表,分別存儲num[p,q-1]和num[q,r-1] int *left=new int[n1]; int *right=new int[n2]; int i,j,k; // 列表賦值 for(i=0;i<n1;i++) left[i]=num[p+i]; for(j=0;j<n2;j++) right[j]=num[q+j]; i=0; j=0; // 將兩個列表left和right的內容按順序放在num[p,r-1] for(k=p;k<r;k++){ if(i<n1&&left[i]<=right[j]){ num[k]=left[i]; i++; } else if(j<n2){ num[k]=right[j]; j++; } } delete []left; delete []right; }
3 性能分析:
3.1 空間複雜度:如上代碼,每一輪的歸併操做使用的輔助元素數組空間長度與原始表等長,爲n,而每一輪歸併以後,這些輔助空間均可以釋放掉,所以空間複雜度是O(n)
3.2 時間複雜度:
對於歸併排序,不論原始列表排序狀況如何,時間複雜度都是同樣的。由於每一輪要進行的比較次數爲n,賦值操做次數爲2n
要進行logn輪歸併操做,則時間複雜度是O(nlogn)
3.3 穩定性:穩定
1 排序思想:
依次比較相鄰的兩個元素,若逆序,則交換位置。直到沒有反序的記錄。
第1趟:依次比較並交換R1與R二、R2與R三、……、R(n-1)與R(n),此次排序以後,第n個記錄就是最終記錄;
第2趟:對前(n-1)個記錄進行上述操做,則第(n-1)個記錄就在其最終位置;
而後依次對前(n-2)、前(n-3)、……、前2個記錄進行上述操做。共需(n-1)趟排序。
若是某一趟沒有進行交換記錄,則說明已經完成排序,應當中止排序。
冒泡排序每趟排序操做均可以將一個元素放到最終位置。
2 算法實現:
// 冒泡排序 void bubble_sort(int num[], int len){ int i,j,tmp; bool flag; // 共需進行len-1趟排序 for(j=0;j<len-1;j++){ flag=true; // 每趟排序對前len-j個元素進行處理 for(i=0;i<len-j-1;i++){ if(num[i]>num[i+1]){ tmp=num[i]; num[i]=num[i+1]; num[i+1]=tmp; flag=false; } } // 若是flag等於true,表示這一趟沒有進行交換 // 即前len-j個元素是有序的,能夠中止比較 if(flag) break; } }
3 性能分析:
3.1 空間複雜度:如上代碼,使用了一個輔助單元tmp,空間複雜度爲O(1)
3.2 時間複雜度:
3.2.1 最好狀況:待排序記錄已是有序的,則只要進行一趟排序,關鍵字比較(n-1)次,記錄移動0次。
時間複雜度O(n)
3.2.2 最壞狀況:待排序記錄已是逆序的,則一趟排序,關鍵字比較次數(n-i-1)次,記錄移動3(n-i-1)次。整個過程
比較次數爲
記錄移動次數爲
時間複雜度O(n^2)
3.2.3 平均時間複雜度:O(n^2)
3.3 穩定性:穩定
1 排序思想:
直接排序的基礎上,將待排序的記錄Ri插入到已經排好序的記錄R1,R2,……,R(N-1)中,因爲記錄R1,R2,……,R(N-1)已經排好序,因此在查找插入位置時可採用「折半查找」。
2 算法實現:
// 折半插入排序 void binary_insert_sort(int num[], int len){ int i,j,key,low,high,mid; for(i=1;i<len;i++){ key=num[i]; low=0; high=i-1; mid=(low+high)/2; // 尋找插入點,最終插入點在low while(low<=high){ if(key<num[mid]) high=mid-1; else low=mid+1; mid=(low+high)/2; } // 移動記錄 for(j=i;j>low;j--){ num[j]=num[j-1]; } // 插入記錄 num[low]=key; } }
3 性能分析:
3.1 空間複雜度:如上代碼,使用了一個輔助單元key,空間複雜度爲O(1)
3.2 時間複雜度:雖然折半查找減小了記錄比較次數,但沒有減小移動次數,所以時間複雜度同直接查找算法。
3.2.1 最好狀況:時間複雜度O(n)
3.2.2 最壞狀況:時間複雜度O(n^2)
3.2.3 平均時間複雜度:O(n^2)
3.3 穩定性:穩定
1 排序思想:
將待排序的記錄Ri插入到已經排好序的記錄R1,R2,……,R(N-1)中。
對於一個隨機序列而言,就是從第二個元素開始,依次將這個元素插入到它以前的元素中的相應位置。它以前的元素已經排好序。
第1次排序:將第2個元素插入到前邊的有序列表(此時前邊只有一個元素,固然是有序的),以後,這個序列的前2個元素就是有序的了。
第2次排序:將第3個元素插入到前邊長度爲2的有序列表,使得前2個元素是有序的。
以此類推,直到將第N個元素插入到前面長度爲(N-1)的有序列表中。
2 算法實現:
// 直接插入排序 void straight_insert_sort(int num[], int len){ int i,j,key; for(j=1;j<len;j++){ key=num[j]; i=j-1; while(i>=0&&num[i]>key){ num[i+1]=num[i]; i--; } num[i+1]=key; } }
3 性能分析:
3.1 空間複雜度:如上代碼,使用了一個輔助單元key,空間複雜度爲O(1)
3.2 時間複雜度:
3.2.1 最好狀況:待排序記錄已是有序的,則一趟排序,關鍵字比較1次,記錄移動2次。則整個過程
比較次數爲
記錄移動次數爲
時間複雜度O(n)
3.2.2 最壞狀況:待排序記錄已是逆序的,則一趟排序,關鍵字比較次數i次(從i-1到0),記錄移動(i+2)次。整個過程
比較次數爲
記錄移動次數爲
時間複雜度O(n^2)
3.2.3 平均時間複雜度:O(n^2)
3.3 穩定性:穩定