秋天是用來求職的季節 排序演算法篇

2021-08-22 10:14:04 字數 2863 閱讀 6738

最近mcosy在求職過程中經常被問到一類問題,就是各種各樣的排序演算法,時間久了不免就有一些忘卻,氣氛一時間尷尬下來。

為了讓各位朋友們避免尷尬,也為了讓自己重新複習一下這些排序演算法,特此推出排序演算法特別篇。

我們先看看常見的一些排序演算法以及他們的複雜度,直接上圖:

以下我將主要挑選幾個談一談

簡單說一下快排的原理,找乙個軸值(一般選擇第乙個或者中間值,本例中使用第乙個元素作為軸值),乙個i標記和乙個j標記,分別位於陣列的開始和末尾。

軸值右側先進行掃瞄,即從 j 開始向前掃瞄,直到遇到 r[j] < r[i] 的情況時停止,交換 r[i] 和 r[j] ,i++;

軸值左側開始掃瞄,即從 i 開始向後掃瞄,直到遇到 r[i] > r[j] 的情況時停止,交換 r[i] 和r[j] ,j--;

直到i=j時結束一次劃分;

此時軸值左側的數全部小於軸值,軸值右側的數全部大於軸值。

之後對左右兩側分別進行快速排序。

#include using namespace std;

//一次排序

int partitionn(int r,int fi, int ed)}}

也就是說,從前往後,兩兩比較,大數後移。這樣就保證了本次排序區間內最大的數一定會移動到區間最末端,並在下次排序時處於排序區間外。

以上兩種屬於交換排序,日常用的也比較多。

再來介紹乙個比較高效的排序演算法,堆排序。

先說說什麼是堆,我理解的堆就是一種特殊的完全二叉樹,並且每個結點的值都要大於其左右孩子結點(大根堆)或小於左右孩子結點(小根堆)。

這樣的結構,就保證了根節點,一定是所有結點中最大或最小的。將初始數列模擬成堆的格式,每次取根節點,這樣就能一步步將無序數列排序。

那麼,乙個完全二叉樹怎麼才能變成乙個堆呢?也就是如何對結點進行調整,使其由非堆結構變為乙個堆結構呢?

我們可以用篩選演算法進行:

void sift(int r,int k, int m)

}

}

堆排序需要解決三個問題:

1.初始無序數列如何轉化為乙個堆(初始建堆);

2.如何處理堆頂記錄也就是根節點;

3.如何調整剩餘記錄,使其成為乙個新的堆;

問題一解決方案:初見建堆的過程就是乙個反覆篩選的過程。乙個長度為n的無序數列,將其模擬成乙個完全二叉樹結構,則最後乙個非葉子結點為n/2。從該結點開始,依次向前進行篩選,直到根節點,則每次篩選結果都是乙個堆。演算法描述為:

for(int i=n/2;i>=1;i--)

問題二解決方案:在初始建堆之後,將待排序序列分為兩個區域,乙個無序區(對該部分篩選堆),乙個有序區。初始狀態時有序區為空。將堆頂記錄a與無序區最後乙個記錄b交換,然後將a從無序區移入有序區。剩餘部分的根節點為b。一般情況下,第i趟堆排序時,堆中有n-i+1個記錄。即在堆調整完成後,將r[1]與r[n-i+1]作交換。

問題三解決方案:在第i趟堆排序之後,此時堆中剩餘n-i個記錄,只需對剩餘記錄篩選根節點即可產生新堆,**為:

sift(r,1,n-i);
下面給出堆排序完整**:

#include using namespace std;

void sift(int r,int k, int m)

}}void heapsort(int r,int n)

cout<

cout完整**裡無序列表是從0到n-1這個區間內,之前將原理的時候為了方便,是放在1~n這個區間內的,大家可以自己轉化下。

排序過程見下圖:

歸併排序同樣也是一種比較好用的排序演算法,歸併的含義是將兩個或兩個以上的有序序列歸併成乙個有序序列的過程。歸併排序的思想是將若干有序序列逐步歸併成乙個有序序列。

我們一般常用的是二路歸併,也是歸併演算法中最簡單的排序演算法,其基本思想是:將若干個有序序列兩兩歸併,最終形成乙個大的有序序列。

在二路歸併排序中,有四個問題需要解決:

1.如何構造初始有序序列?

2.如何將兩個相鄰有序序列歸併成乙個有序序列(即一次歸併)

3.怎樣完成一趟歸併

4.怎樣控制二路歸併結束

問題一解決方案:將每乙個記錄都單獨看做乙個長度為1的有序序列。

問題二解決方案:因為在歸併過程中可能會破壞原有有序序列,所以我們需要借助乙個輔助陣列,用來存放兩個序列歸併而成的有序序列。例如,設兩個相鄰有序序列為r[s]~r[m]以及r[m+1]~r[t],將這兩個序列歸併為乙個序列r1[s]~r1[t]。

設i,j,k分別指向r中的s,m+1位置以及r1中的s位置,比較i和j所對應的值,若r[i]反之亦然,**如下:

void merge(int r, int r1,int s,int m,int t)

if(i<=n-h+1)

merge(r,r1,i,i+h-1,n);

else

for(int k=i;k<=n;k++)

r1[k]=r[k];

}

問題四解決方案:初始時有序序列長度為1,結束時有序序列長度為n。所以我們可以通過有序序列長度來控制排序過程的結束。

歸併排序**如下:

void mergesort(int r,int r1,int n)

{ int h=1;

while(h暫且就說這麼多,有什麼問題可以指出來,我寫的可能有些粗糙

希爾排序是一種穩定的排序演算法 排序演算法之希爾排序

希爾排序是希爾 donald shell 於1959年提出的一種排序演算法。希爾排序也是一種插入排序,它是簡單插入排序經過改進之後的乙個更高效的版本,也稱為縮小增量排序,同時該演算法是衝破o n2 的第一批演算法之一。簡單插入排序很循規蹈矩,不管陣列分布是怎麼樣的,依然一步一步的對元素進行比較,移動...

排序演算法原來是這麼排的

常用的排序演算法有以下幾類 插入排序 直接插入排序,希爾排序 選擇排序 簡單選擇排序,堆排序 交換排序 氣泡排序,快速排序 歸併排序,基數排序。排序方法選擇得當與否直接影響程式執行的速度和輔助儲存空間的占有量,進而影響整個軟體的效能。下面對這些演算法一一的介紹他們究竟是怎麼排的。插入排序 直接插入排...

演算法是如何影響程式編碼方式的 基本排序演算法

我們的目標是從乙個int的array中,找出最小值。作為demo程式,我們先增加乙個類,用來模擬array,如下定義 class carray public carray int capacity public void insert int value public void clear publ...