排序演算法總結

2021-06-23 06:58:28 字數 4137 閱讀 4852

1. 簡單選擇排序

簡單選擇排序的思想:將陣列看作兩段,左邊已經排好序,右邊待排序,左邊元素都小於等於右邊元素,用sorted_index 指向排序元素的下乙個位置,用unsorted_index指向sorted_index的下乙個元素,向後移動unsorted_index找到待排序中最小的乙個元素,與sorted_index的元素交換。直到sorted_index==n-1.

void ******_select_sort(item a,int n)

} if(min_index != sorted_index)

}}

這個**內層迴圈中為了找最小的元素,做了n-sorted_index-1 次比較,交換次數為1或0。外層迴圈遍歷了n-1次。排序的複雜度最壞情況,平均情況,最好情況都是o(n^2)。

並且,可以看出簡單選擇排序是穩定的。

2.  堆排序

為什麼叫堆排序,堆是用來實現優先佇列的,優先佇列具有這樣的性質:當你從優先佇列中取乙個元素,總是取到具有最高優先順序的。通常用最大堆來實現堆排序,堆陣列中,第乙個元素總是最大的。

堆排序不是乙個穩定的排序,因為每次調整的時候,總是要將第乙個元素和最後乙個元素交換。

我們先來看看最大堆的重要性質,假設有n個元素。

1) 堆對應的二叉樹是完全二叉樹。

2) 第i個(i>=1)個結點的如果有左右子結點,則左右子結點為a[i*2]和a[i*2+1],並且a[i]>=a[i*2] && a[i] >= a[i*2]。

堆排序的步驟如下:

1 .對於乙個陣列,先調整為乙個最大堆,第乙個元素就是最大元素。

2. 我們交換堆頂(最大元素)與堆中最後乙個元素,並且將交換後的最後乙個元素從堆中剔除。

3. 剩下的元素重新調整為堆結構。

重複2&3,直至堆中元素個數為0。

其中第1步是從第floor(n/2)個元素起一直調整至根元素。已經證明這一步是線性時間。第三步複雜度為o(logn),因此總體複雜度為o(nlogn)。

現在開始解決每一步。首先根據乙個陣列構造堆,假如我們的陣列為,起初:

顯然不滿足堆結構,我們從第floor(7/2)=3個元素開始調整,由於滿足堆結構,再到第3-1=2個元素,由於不滿組堆結構,調整成,再到第2-1=1個元素,由於滿足堆結構,不需要調整,至此,將原始陣列調整成堆結束:

這一步的**:

void build_heap(int a,int n)   //陣列a index是從1開始的

if(a[i] < a[child_bigger_index]) }}

有了最大堆之後,我們進行第2步,和第3步。

先將第乙個元素和第7個元素(最後乙個元素)交換,並將交換後的最後乙個元素從堆中剔除。現在剩下的元素不是堆了,我們需要用第3步進行調整成堆:

重複上面兩步:

直到最終陣列排好序。

這兩步**如下:

void fixdown(int a,int k,int n)

if(a[child_bigger_index] > a[k])

else

}}void heapsort(int a,int n)

}

link: 

heap sort

3. 直接插入排序

插入排序背後的思想很簡單:

* 調整一下前2個元素,讓他們處在相對排好序的位置

* 將第3個元素插入到前2個元素中,使他們相對排好序

* 將第4個元素插入到前3個元素中,使他們相對排好序

插入排序和選擇排序一樣,排序的時候都是分為兩段,第一段為已經排好序的,第二段為沒有排好序的。但是和選擇排序不同的是,第一段中已經排好序的不是最終排序結果,只是相對排好序。在內迴圈中,通常要挪動已經排好序的元素位置。**如下:

void insert_sort(int a,int n) // index from 1

a[sorted_index+1] = tmp;}}

插入排序是穩定的,並且插入排序適合幾乎排好序的陣列,因為幾乎排好序的陣列移動次數較少,最好的情況是o(n),最壞的情況是o(n^2)

4. 希爾排序

我們直到插入排序在陣列幾乎排序的情況下效率很高,如果乙個小元素在很後面,需要挪動前面很多元素來空出位置來讓希爾這個元素插入,這樣效率不高。希爾排序是在插入排序的基礎上做了改進,其基本思想是:

將陣列元素分成多個子串行,每個子串行index以某乙個增量增加,假如當前增量為gap,則每個子串行元素個數為ceil(n/gap)。對於每個子串行,進行插入排序。然後遞減gap,直到gap減為1,排序結果即為最終結果。

void shell_sort(int a,int n)  // index from 1

a[k+gap] = tmp;}}

}}

希爾排序不是穩定的,因為是跳躍的。

5. 氣泡排序

插入排序是基於「逐個記錄插入」的,選擇排序是基於「選擇」的,氣泡排序是基於"交換"的,氣泡排序也是將陣列看作兩段,左邊是待排序的,右邊是已經排好序的,並且右邊已經排好序的比左邊元素都大,並且遞增,氣泡排序是將大元素逐漸沉到陣列底部。

void bubule_sort(int a,int n) //index from 1}}

}

相對於簡單選擇排序,氣泡排序交換次數明顯更多。它是通過不斷地交換把最大的數冒出來。氣泡排序平均時間和最壞情況下(逆序)時間為o(n^2)。最佳情況下雖然不用交換,但比較的次數沒有減少,時間複雜度仍為o(n^2)。此外氣泡排序是穩定的。

6.  快速排序

快速排序用的是歸併的思想,為了排序乙個陣列,我們先將它分成兩部分,分別排序這兩部分,這樣整個陣列就排好序了,不過與歸併排序不同的是,快排用元素來劃分數組成兩部分,將小於劃分點的元素放在左邊,大於等於劃分點的元素放到右邊,然後遞迴地對兩部分進行排序。

比如乙個陣列有8個元素:

我們用第乙個元素55來進行劃分:

如果我們遞迴的對1到3的元素和5到8的元素進行排序,最終整個陣列就排好序了。

假如我們以第乙個元素作為劃分點,劃分的某乙個過程為:

一趟劃分完成。

**如下:

int partition(int a,int l,int u)

}a[l] = a[m];

a[m] = povit;

return m;

}void quick_sort(int a,int l, int u)

還可以對快排進行調優,當l與u之差很小,也就是遞迴排序的元素很少的時候,可以用插入排序進行排序

void quick_sort(int a,int l, int u)	}}

void merge(item a,item t,int l,int m,int r)

void mergesort(item a,item t,int l,int r)

}

排序演算法總結

1 直接插入排序 1 穩定性 穩定 2 適用情況 待排記錄規模較小,或者記錄已經基本有序 2 希爾排序 1 穩定性 不穩定 2 特點 希爾排序的執行時間依賴於增量序列,它的效率比直接插入排序有較大的改進。3 氣泡排序 1 穩定性 穩定 2 特點 當待排記錄基本有序是,氣泡排序是不錯的選擇 但由於氣泡...

排序演算法總結

1 選擇排序 選擇排序的思想是依次從待排序數列中選擇最大 小 的 第二大 小 的等等,然後依次重新排列為有序數列。void selectionsort int a,int n if min i 時間複雜度o n 2 2 歸併排序 void merge int a,int left,int mid,i...

排序演算法總結

學習了這麼多的排序演算法,還沒有做個總結,呵呵 氣泡排序 氣泡排序是最慢的排序演算法。在實際運用中它是效率最低的演算法。它通過一趟又一趟地比較陣列中的每乙個元素,使較大的資料下沉,較小的資料上公升。它是 o n 2 的演算法。快速排序 快速排序是乙個就地排序,分而治之,大規模遞迴的演算法。從本質上來...