八大排序演算法總結

2021-08-10 23:37:14 字數 3444 閱讀 3053

演算法一:氣泡排序

每次比較相鄰兩元素,若錯序則交換,多次遍歷,直至無交換,實質上需要排序k-1趟,每次找到未排序元素中的最大值放在已排序序列最後面,穩定。

void bubble_sort(int array, int n)}}

改進:增加狀態變數flag,若某趟迴圈無交換發生,則停止繼續迴圈時間複雜度分析:最好情況,全部有序,在已改進的基礎上,比較n-1次,故時間複雜度為o(n),最壞情況,逆序排列,則需要比較n(n-1)/2次,交換n(n-1)/2次,時間複雜度為o(n^2)。

缺點:一次迴圈內多次交換

演算法二:簡單選擇排序

進行n-1趟排序,每次尋找未排序所有元素的最小值放在已排序序列的最末端,穩定。

void selection_sort(int array,int n)

}

時間複雜度分析:最好情況,全部有序,需要比較n-1次,最好情況無交換,故時間複雜度為o(n),最壞情況比較(n+2)(n-1)/2次(注意j迴圈中有兩次比較),移動次數為(n+4)(n-1)/2次,時間複雜度為o(n^2),但效能上還是略優於氣泡排序和簡單選擇排序。優勢:在基本有序或者記錄數目較少的時候

缺點:共需n趟排序,效率低,並且每次迴圈只能將資料移動一位

演算法四:希爾排序

如上述演算法三,在記錄數目較少時,直接插入排序有優勢,若記錄數目較多,則可將記錄分割成多個子串行,在每個子串行(記錄數目較少)內直接插入排序。當整個序列基本有序時,再對全體進行一次直接插入排序。選擇乙個增量序列,按照增量序列進行k趟排序,每趟排序將整個待排序的記錄序列分割成為m個子序列分別進行直接插入排序,待整個序列中的記錄「基本有序」時(增量降為1),再對全體記錄進行依次直接插入排序,由於跳躍式移動

不穩定。

void shell_sort(int array, int n)

}

時間複雜度分析:取決於增量序列的選擇,對於上述序列複雜度為o(n^3/2),第乙個突破o(n^2)的演算法演算法五:堆排序

直接選擇排序並沒有把每趟的比較結果記錄下來,導致後一趟的比較中有許多前一趟已經做過了,因而比較次數較多,若能找到本趟迴圈要找的值的同時,對其他記錄進行相應的調整,則會提高整體效率。

大頂堆:每個節點的值都大於或等於左右孩子結點的值的完全二叉樹

小頂堆:每個節點的值都小於或等於左右孩子結點的值的完全二叉樹

將待排序的序列構造成乙個大頂堆,根結點則為最大值,將其與堆陣列末尾元素交換,再將剩餘n-1個序列重新構成乙個大頂堆,如此反覆迴圈,便能得到乙個有序序列。故需解決兩個問題:如何構建堆?輸出堆頂後,如何調整成新的堆?

void heapadjust(int *a, int start, int end)

a[start] = temp;

}void heapsort(int a, int n)

}

時間複雜度分析:時間消耗在初始建堆和重建堆的反覆篩選,從最下層最右邊非端點開始與左右孩子比較,最多兩次比較和互換,因此構建堆為o(n);正式排序時,第i次取堆頂記錄重建堆需要o(logi)的時間(完全二叉樹的某個結點到根結點距離為[logi]+1),並且需要取n-1次,因此重建堆複雜度為o(nlogn),整體時間複雜度為o(nlogn)特點:對原始記錄排序狀態不敏感,跳躍式交換不穩定。由於初始建堆所需比較次數較多,不適合待排序個數較少的情況

演算法六:歸併排序

採用分治思想,對任一串行,分成左右子列,子列內部排序,遞迴實現,然後用指標移動合併兩子列實現歸併操作,穩定。

**實現:

void merge(int array,int temparr, int startindex,int midindex,int endindex)

while (i != midindex + 1)  //未排完子列剩餘元素直接送人合併列

temparr[k++] = array[i++];

while (j != endindex + 1)

temparr[k++] = array[j++];

for (i = startindex; i <= endindex; i++) //將合併列放入原序列應有的位置

array[i] = temparr[i];

}void mergesort(intarray,inttemparr, intstartindex,intendindex)

#define cutoff 3

void quicksort(intarray,int left, int right)

//從兩側分別找到錯誤分組的元素

while (array[--j] > pivot) {}

if (i < j)  //若i,j尚未交錯

swap(&array[i], &array[j]);

else

break; //當前分組正確

}swap(array[i], array[right - 1]); //把樞紐元放到中間

quicksort(array, left, i - 1);

quicksort(array, i + 1,right);

}else

insertionsort(array + left, right - left + 1);//對於小陣列,插入排序更合適

}

*** 與歸併相比,同樣是遞迴,可是分成的兩個子問題並不一定相等(隱患),但分成兩組是在適當的位置進行且非常有效,故比遞迴更快。

演算法八:基數排序

基數排序用於對多關鍵字域資料(例如:一副撲克牌,大小可以看做乙個關鍵字域,花色也可以看做另乙個關鍵字域)進行排序,每次對資料按一種關鍵字域進行排序,然後將該輪排序結果按該關鍵字的大小順序堆放,依次進行其他關鍵字域的排序,最後實現序列的整體排序。

限制:

基數排序需要一種穩定的排序演算法作為子程式,在這裡使用計數排序。

時間複雜度:

(1)給定n個d位k進製數,使用計數排序(耗時:

(2)給定n個b位k進製數,若b太大,可考慮將b分成r段,這時得到n個b/r位k^r進製數,同樣使用計數排序(耗時:

缺點:

不是原址排序;雖然可以達到線性時間複雜度,但是常數因子較大。

八大排序演算法總結

1.直接插入排序 原理 將陣列分為無序區和有序區兩個區,然後不斷將無序區的第乙個元素按大小順序插入到有序區中去,最終將所有無序區元素都移動到有序區 完成排序。要點 設立哨兵,作為臨時儲存和判斷陣列邊界之用。實現 void insertsort node l,int length l i 1 l 0 ...

八大排序演算法總結

插入排序 1.直接插入排序 原理 將陣列分為無序區和有序區兩個區,然後不斷將無序區的第乙個元素按大小順序插入到有序區中去,最終將所有無序區元素都移動到有序區完成排序。要點 設立哨兵,作為臨時儲存和判斷陣列邊界之用。實現 void insertsort node l,int length int i,...

八大排序演算法總結

插入排序 1.直接插入排序 原理 將陣列分為無序區和有序區兩個區,然後不斷將無序區的第乙個元素按大小順序插入到有序區中去,最終將所有無序區元素都移動到有序區完成排序。要點 設立哨兵,作為臨時儲存和判斷陣列邊界之用。實現 void insertsort node l,int length int i,...