定義 : 排序是計算機內常常進行的一種操做,其目的是將一組「無序」的記錄序列調整爲「有序」的記錄序列。份內部排序和外部排序,若整個排序過程不須要訪問外存便能完成,則稱此類排序問題爲內部排序。反之,若參加排序的記錄數量很大,整個序列的排序過程不可能在內存中完成,則稱此類排序問題爲外部排序。內部排序的過程是一個逐步擴大記錄的有序序列長度的過程。c++
分類 : 算法
算法描述: 數組
將數組分爲無序和有序兩部分,初始時無序數列的邊界下標爲總數組的長度減去一的位置,從無序數列的第一個數開始作交換,若是發現這個數比下一個數大則交換這兩個數,直至無序數列的最後一個數爲一輪交換,這輪交換使得無序數列的最大元素放到了它邊界值的下一個位置,每完成一輪交換都更新一次無序數列的邊界下標,直至整個數組都變爲有序則完成整個排序。ide
優劣:1 void Babble_Sort1(ElementType *array, int length) { 2 for(int i = 0; i < length - 1; i ++) 3 for(int j = 0; j < length - 1 - i; j ++) 4 if(array[j] > array[j + 1]) 5 swap(array[j], array[j + 1]); 6 }
1 void Babble_Sort2(ElementType *array, int length) { 2 bool IsSorted; 3 int LastPosition;//記錄每回合最後一次交換位置的元素的下標 4 int SortBorder = length - 1;//記錄無序數列的邊界 5 for(int i = 0; i < length - 1; i ++) { 6 IsSorted = true; 7 for(int j = 0; j < SortBorder; j ++) 8 if(array[j] < array[j + 1]) { 9 swap(array[j], array[j + 1]); 10 IsSorted = false; 11 LastPosition = j; 12 } 13 SortBorder = LastPosition; 14 if(IsSorted) 15 break; 16 } 17 }
算法描述: 性能
1.將原數組分爲未排序和已排序兩部分。優化
2.從第一個元素開始,該元素能夠認爲已經被排序;ui
3.取出下一個元素,在已經排序的元素序列中從後向前掃描;spa
4.若是該元素(已排序)大於新元素(待插入),將該元素移到下一位置;code
5.重複步驟4,直到找到已排序的元素小於或者等於新元素的位置;blog
6.將新元素插入到該位置後;
7.重複步驟3~6。
算法分析:
1 void Insertion_Sort(ElementType *array, int length) { 2 int i, j; 3 ElementType Tmp; 4 for(i = 1; i < length; i ++) { 5 Tmp = array[i]; 6 for(j = i; j > 0 && array[j-1] > Tmp; j --) 7 array[j] = array[j-1]; 8 array[j] = Tmp; 9 } 10 }
算法描述:
將數組分爲無序和有序兩個部分,起初視數組都爲無序,每次讓數組無序部分的第一個元素做爲擂主,讓其後的元素開始打擂,每次打至數組的最後一個元素,若是擂主變了(後續數組中存在比擂主小的元素)
,則將擂主歸併做爲有序部分的最後一個元素並按照上述規則繼續打擂,直至數組的最後一個元素。
優劣:
1 void Seletion_Sort(ElementType *array, int length) { 2 int index; 3 for(int i = 0; i < length - 1; i ++) { 4 index = i; 5 for(int j = i + 1; j < length; j ++) 6 if(array[j] > array[index]) 7 index = j; 8 if(index != i) 9 swap(array[index], array[i]); 10 } 11 }
改進思路:
每次打擂只能找出無序數組元素中最大(或最小)的元素,能夠考慮每次找出最大和最小的元素,減小循環的次數,從而提升查找的效率。
二元選擇排序
c++代碼:
1 void Double_Seletion_Sort(ElementType *array, int length) { 2 int MinPos, MaxPos;//這裏咱們將i看作是擂主,j看做是打擂者 3 for(int i = 0; i < length / 2; i ++) { 4 MinPos = MaxPos = i;//讓擂主同時與最大最小值打比賽 5 for(int j = i + 1; j < length - i; j ++) { 6 if(array[j] > array[MaxPos]) { 7 MaxPos = j; 8 continue;//若是發現array[j] > array[MaxPos]則其必定不會小於array[MinPos] 9 } 10 if(array[j] < array[MinPos]) 11 MinPos = j; 12 } 13 if(MinPos != i)//將新星擂主歸入有序序列的最後一位,若是擂主沒變則不用歸入 14 swap(array[i], array[MinPos]); 15 if(MaxPos == i)//若是擂主位置爲最大值,則剛剛交換最小值時已經將最大值換到了最小值打雷成功的打擂者身上即(MinPos) 16 MaxPos = MinPos; 17 if(MaxPos != length - 1 - i)//若是擂主不是無序部分最後一位則將其與最後一位交換,歸入有序序列 18 swap(array[length - 1 - i], array[MaxPos]); 19 } 20 }
定義:
歸併排序(MERGE-SORT)是創建在歸併操做上的一種有效的排序算法,該算法是採用分治法(Divide and Conquer)的一個很是典型的應用。將已有序的子序列合併,獲得徹底有序的序列;即先使每一個
子序列有序,再使子序列段間有序。若將兩個有序表合併成一個有序表,稱爲二路歸併。
算法描述:
1.把長度爲n的輸入序列分紅兩個長度爲n/2的子序列;
2.對這兩個子序列分別採用歸併排序;
3.將兩個排序好的子序列合併成一個最終的排序序列。
優劣:
1 void MergeSort(ElementType *array, ElementType *TmpArray, int Left, int Right) { 2 int Center; 3 if(Left < Right) { 4 Center = Left + (Right - Left) / 2; //避免數據類型溢出 5 MergeSort(array, TmpArray, Left, Center); 6 MergeSort(array, TmpArray, Center + 1, Right); 7 Merge(array, TmpArray, Left, Center + 1, Right); 8 } 9 } 10 11 void Merge(ElementType *array, ElementType *TmpArray, int LPos, int RPos, int RightEnd) { 12 int LeftEnd = RPos - 1, TmpPos = LPos, NumElements = RightEnd - LPos + 1; 13 while(LPos <= LeftEnd && RPos <= RightEnd) { 14 if(array[LPos] <= array[RPos]) 15 TmpArray[TmpPos ++] = array[LPos ++]; 16 else 17 TmpArray[TmpPos ++] = array[RPos ++]; 18 } 19 while(LPos <= LeftEnd) 20 TmpArray[TmpPos ++] = array[LPos ++]; 21 while(RPos <= RightEnd) 22 TmpArray[TmpPos ++] = array[RPos ++]; 23 for(int i = 0; i < NumElements; i ++, RightEnd --) //Copy TmpArray back 24 array[RightEnd] = TmpArray[RightEnd]; 25 }
基本思想:
經過一趟排序將要排序的數據分割成獨立的兩部分,其中一部分的全部數據都比另一部分的全部數據都要小,而後再按此方法對這兩部分數據分別進行快速排序,整個排序過程能夠遞歸進行,以此達到
整個數據變成有序序列。
算法描述:
1.若是需排序元素大於指定數目則執行快速排序,不然執行其它簡單排序。(通常元素多於10個時進入快速排序,事實證實,當元素個數過少時使用快速排序會比其它程序慢的多,而且這裏咱們選擇三值取
中法,若是元素個數過少會產生未預知的錯誤)。
2.利用三值取中法獲取一個樞紐元(於此同時將樞紐元放在待排序序列的最後一位)。
3.將數組分爲三個不相交的集合,即x < pivot , pivot , x > pivot 。
4.對x < pivot執行上述1,2,3操做, pivot, 對 x > pivot執行上述1,2,3操做。
優劣:ElementType Median3(ElementType *array, int Left, int Right) { int Center = Left + (Right - Left) / 2;//避免數據類型溢出 if(array[Left] > array[Center]) swap(array[Left], array[Center]); if(array[Left] > array[Right]) swap(array[Left], array[Right]); if(array[Center] > array[Right]) swap(array[Center], array[Right]); // Invariant : array[Left] <= array[Center] <= array[Right] swap(array[Center], array[Right - 1]);//Hide pivot return array[Right - 1];// Return pivot } #define CutoffRange (10) void QuicklySort(ElementType *array, int Left, int Right) { ElementType pivot; if(Left + CutoffRange <= Right) { //當待排序元素個數多於CutoffRange時採用快速排序 pivot = Median3(array, Left, Right);//選取樞紐元 //注意下方對i和j的操做爲++ i, ++ j操做,即跳過了第一個和最後一個元素,這是由於在進行三數取中法的時候待排序的第一個和最後一個數已經在它正確的位置上了 int i = Left, j = Right - 1; while(true) {//將數組中小於pivot的元素放到左邊,大於pivot的元素放到右邊 while(array[++ i] < pivot); while(array[-- j] > pivot); if(i < j)//當同時找到不知足上述條件的兩個值時,將其交換就是最好的選擇 swap(array[i], array[j]); else break; } swap(array[i], array[Right - 1]);//最後將樞紐元放到他在數組中的正確位置 QuicklySort(array, Left, i - 1); QuicklySort(array, i + 1, Right); } else Double_Seletion_Sort(array + Left, Right - Left + 1); }
1959年Shell發明,第一個突破O(n2)的排序算法,是簡單插入排序的改進版。它與插入排序的不一樣之處在於,它會優先比較距離較遠的元素。希爾排序又叫縮小增量排序。
算法思路:先將整個待排序的記錄序列分割成爲若干子序列分別進行直接插入排序。
算法描述:
1.選擇一個增量序列t1,t2,…,tk,其中ti>tj,tk=1;
2.按增量序列個數k,對序列進行k 趟排序;
3.每趟排序,根據對應的增量ti,將待排序列分割成若干長度爲m 的子序列,分別對各子表進行直接插入排序。僅增量因子爲1 時,整個序列做爲一個表來處理,表長度即爲整個序列的長度。
1 void ShellSort(ElementType *array, Length length) { 2 int i, j, Increment = 1; 3 ElementType Tmp; 4 while(Increment < length / 3) Increment = 3 * Increment + 1;//找到起初最大的間隔序列之首 5 while(Increment >= 1) { 6 for(i = Increment; i < length; i ++) { 7 Tmp = array[i];//用來保存待插入元素 8 for(j = i; 9 j >= Increment && array[j - Increment] > Tmp; 10 j -= Increment)//將原數組以Increment爲間隔分開,而後對每部分分別進行插入排序 11 array[j] = array[j - Increment]; 12 array[j] = Tmp; 13 } 14 Increment /= 3; 15 } 16 }