插入排序: 算法簡介:接插入排序(Insertion Sort)的基本思想是:每次將一個待排序的記錄,按其關鍵字大小插入到前面已經排好序的子序列中的適當位置,直到全部記錄插入完成爲止。時間複雜度爲O(n^2)。 最穩定的排序算法但是效率很低 代碼實現: void InsertSort(int *arr,int n) { for (int index = 0; index < n-1; ++index) { int end = index+1; int tmp = arr [end]; while (end>0&&tmp<arr [end - 1]) { arr[end] = arr [end - 1]; end--; } arr[end] = tmp; } } 顯然當最小的數字在數組的最右端時,此時需要將整個數組進行移位,效率很低,而希爾排序可以有效的改善這個問題 希爾排序:希爾排序(Shell Sort)是插入排序的一種。也稱縮小增量排序,是直接插入排序算法的一種更高效的改進版本。希爾排序是非穩定排序算法 先將整個待排元素序列分割成若干個子序列(由相隔某個“增量”的元素組成的)分別進行直接插入排序,然後依次縮減增量再進行排序,待整個序列中的元素基本有序(增量足夠小)時,再對全體元素進行一次直接插入排序。因爲直接插入排序在元素基本有序的情況下(接近最好情況),效率是很高的,因此希爾排序在時間效率上比前兩種方法有較大提高。 代碼實現: void ShellSort(int *arr, int n)//希爾排序 { int gap = n ; while (gap>1)//由於gap=gap/3+1 最小值爲1 則在gap=1時跳出循環 { gap = gap / 3 + 1; //{ 2, 8, 9, 6, 1, 3, 4, 5, 7, 0 ,-1,-2}//注意這裏的+1 當gap=1時此時排序等同於插入排序 但是由於之前將最小的數據已經移到最左邊所以效率 //高於插入排序 for (int index = 0; index <n-gap; ++index) { int end = index; int tmp = arr [end+gap]; while (end>= 0 && arr [end]>tmp) { arr[end+gap] = arr [end]; end -=gap;//此時插入間距爲end } arr[end+gap] = tmp; } } } 附註:上面希爾排序的步長選擇都是從n/3+1開始,每次再取上一次的三分之一加1,直到最後爲1。關於希爾排序步長參見維基百科:http://zh.wikipedia.org/wiki/%E5%B8%8C%E5%B0%94%E6%8E%92%E5%BA%8F 冒泡排序:20世紀經典算法之一, 原理是臨近的數字兩兩進行比較,按照從小到大或者從大到小的順序進行交換,這樣一趟過去後,最大或最小的數字被交換到了最後一位,再進行第二趟冒泡,由此我們可以寫出以下代碼: void BubbleSort(int *arr, int n) { for (int i = 0; i < n; ++i) { for (int j = 0; j < n - i - 1; ++j) { if (arr [j]>arr[j + 1]) swap( arr[j], arr [j + 1]); } } } 這裏我們設立一個標記變量 flag用來標記數列中的數是否在循環結束前就已經排好序 代碼改進如下: void BubbleSort(int *arr, int n) { bool flag = true ; int k = n ; while (flag) { flag = false; for (int i = 1; i < k; ++i) { if (arr [i - 1]<arr[i]) { swap( arr[i - 1], arr [i]); flag = true;//有發生交換 繼續冒泡 否則說明已經有序 } } k--; } } 如果這一趟發生了交換,這flag爲rrue,則還需要繼續進行冒泡,否則說明數組已經有序,後面的不必進行下去。 那麼這裏給出這樣一種情況:(2,1,3,4,5,6,7,8,9,10)第一次循環交換之後我們會發現,後面的數組已經有序,不再需要我們進行冒泡,後面的操作都是不必要的 這裏我們只需要記錄下最後一次進行交換的位置,那麼下次遍歷只要遍歷到這個位置就可以結束。 代碼進一步優化如下: void BubbleSort(int *arr, int n) { int flag = n ;//第一次遍歷終點爲數組尾 while (flag > 0) { int k = flag; flag = 0; for (int j = 1; j < k; ++j) { if (arr [j - 1] > arr[j]) { swap( arr[j - 1], arr [j]); flag = j;//後面的已經排序好 記錄下下一次排序的終點 } } } } 雖然有了這麼多優化,但是冒泡排序總體還是一種效率很低的排序,數據規模過大時不適合使用這種排序 堆排序: 堆的定義: 1.堆是一顆完全二叉樹 2.父結點總是大於或等於(小於或等於)任何一個子節點 3每個結點的左子樹和右子樹都是一個二叉堆 當父結點總是大於或等於任何一個子節點值時爲最大堆。反之則爲最小堆 堆的結構示意圖如下: 存儲方式: 我們使用數組來存儲一個堆,可以看出設父節點下標值爲i 其左孩子下標值爲2*i+1,右孩子爲2*1+2; 代碼實現如下: void AdJust_down(int *arr, int parent, int size ) { int child = 2 * parent +1; while (child<size ) { if (child+1<size &&arr[child+1]> arr[child]) { ++child; } if (arr [parent]> arr[child]) break; swap( arr[parent ], arr[child]); parent = child; child = 2 * parent; } } void HeapSort(int *arr,int n) { for (int i = n/2-1; i >= 0; --i) { AdJust_down( arr, i, n ); } for (int i = n - 1; i >= 1; --i) { swap( arr[0], arr [i]); AdJust_down( arr, 0, i); } } 思路分析: 1.如果要對數字進行升序,我們首先首先將數組初始化爲原始大堆 for (int i = n/2-1; i >= 0; --i) { AdJust_down( arr, i, n );//從最後一個非葉子節點開始調整 } 2.進行排序(以升序爲例) 大堆的性質爲:最大的數據一定在堆頂將堆頂和堆最後一個元素進行交換,則最大的數字此時在數字尾部,再將堆頂元素下調,且堆的大小減1,知道堆大小爲1循環結束,排序完成。 代碼如下: for (int i = n - 1; i >= 1; --i) { swap( arr[0], arr [i]); AdJust_down( arr, 0, i); } 選擇排序 選擇排序(Selection sort)是一種簡單直觀的排序算法。它的工作原理是每一次從待排序的數據元素中選出最小(或最大)的一個元素,存放在序列的起始位置,直到全部待排序的數據元素排完。 選擇排序是不穩定的排序方法 爲了減少比較的次數,我們一次遍歷同時選出最大值和最小值,代碼實現如下: void SelectSort(int *arr, int n) { int i = 0, j = n - 1; int max = j; int min = i; int left = 0; int right = n - 1; while (left<=right) { min = left; max = right; ///!!!!!!!!!!!重點 for (i = left, j = right; i <= j; i++) { if (arr [min]>arr[i]) min = i; if (arr [max] < arr[i]) ////{ 2, 9, 6, 1, 3, 4, 5, 7, 0 ,-8,1,-2} max = i; } if (left != min) { swap( arr[left], arr [min]); if (max == left) max = min; } if (right != max) swap( arr[right], arr [max]); left++; right--; } } 這裏我們必須注意到,以升序爲例,如果一次遍歷找到的最大值剛好在數組左邊,此時肯定會先被移走,此時就最大值得下標就得更新爲轉移後的位置 快速排序: 該方法的基本思想是: 1.先從數列中取出一個數作爲key。 2.分區過程,將比這個數大的數全放到它的右邊,小於或等於它的數全放到它的左邊。 3.再對左右區間重複第二步,直到各區間只有一個數。 代碼實現如下: int PartSort(int *arr, int left, int right) { int key = arr [right]; //{ 10,2, 8, 9, 6, 1, 3, 4, 5, 7, 0 ,-1,-2,-100}; int begin = left ; int end = right - 1; while (begin<end) { while (begin<end&&arr [begin]<=key) { begin++; } while (begin<end&&arr [end]>=key) { end--; } if (begin < end) swap( arr[begin], arr [end]); } if (arr [begin]>arr[right]) { swap( arr[begin], arr [right]); return begin; } return right ; } void QuickSort(int *arr, int left,int right) { if (left >= right) return; int div = PartSort(arr , left, right); QuickSort( arr, div + 1, right ); QuickSort( arr, left , div - 1); }
常見經典排序算法
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.