資料結構和演算法總結(二) 排序

2022-03-22 05:17:59 字數 3617 閱讀 4352

前言

複習各種排序演算法,並記錄下。

正文

1.氣泡排序

冒泡可以說是最簡單的排序演算法,它的排序過程就是每次遍歷陣列將最大的那個數往前頂,就好像氣泡上浮一樣。

過程可以參考如下圖

參考**

void bubblesort(vector& num)}}

複雜度分析冒泡的最壞情況下的時間複雜度為:o(n2),平均複雜度:o(n2) 。

優化

我們可以稍微優化下氣泡排序,增加乙個標識來確定乙個陣列是否有序,如果是那麼可以提前終止排序,參考**如下

//提前終止的氣泡排序

bool prestopbubble(vector& num,const int n)

}}void prestopbubblesort(vector&num)

這種情形下,氣泡排序的最好複雜度可以達到o(n)。

2.選擇排序

選擇排序和氣泡排序的思路類似,都是找到最大(或者最小)的數,只不過選擇排序需要額外的空間來儲存一次遍歷過程中最大(或者最小)的數字和它的位置,然後將它與首位(或者末位)交換。

過程可以參考如下圖

參考**

void selectionsort(vector& num)

}swap(num[index],num[i - 1]);}}

複雜度分析選擇排序的最壞情況下的時間複雜度為:o(n2),平均複雜度:o(n2) 。但是往往選擇排序效率優於氣泡排序(如果不是提前終止的冒泡),因為每一次遍歷選擇排序只需要發生一次交換,而氣泡排序可能發生了多次交換,然而,這是選擇排序犧牲了額外空間來儲存最值得來的。

3.計數排序

計數排序,也叫桶排序。這種排序方法適合已知一定範圍內的數字排序,每乙個數字都有乙個對應的桶,一次遍歷將陣列的數字放入到對應的桶中進行統計,然後遍歷每個桶將其輸出即可。

過程可以參考如下圖

參考**

void countsort(vector& num,const int maxnum)

int j = 0;

for(int i = 0;i < num.size();i++)}}

複雜度分析計數排序的平均時間複雜度為:o(n)。但是它的空間複雜度很差。這是一種犧牲空間換取時間的排序演算法。

4.歸併排序

有序陣列的合併

首先,我們要知道如何將兩個有序陣列合併。方法很簡單,從頭開始比較兩個陣列的數字,用乙個額外的陣列tmp儲存一次比較時的較小數字,然後較小者所在陣列的索引向後+1繼續和之前另乙個陣列的較大者比較。如果其中乙個陣列遍歷到末尾,那麼把另乙個陣列的剩餘元素依次新增到tmp陣列末尾即可,這樣tmp就是乙個合併後的有序陣列。

分治

而對於乙個無序陣列,我們可以將它劃分為兩個無序子陣列,子陣列又可以不停劃分,直到當乙個子陣列只有乙個數時,這時這個子陣列肯定是有序的,那麼我們就可以將乙個個有序子陣列合併成更大的有序子陣列,直到最終合併成乙個有序陣列,這就是歸併排序的思想。

排序過程可以參考如下圖

參考**

void mergearray(vector& num,int left,int right,int mid,vector& tmp)

while(l <= lm) tmp[k++] = num[l++];

while(mr <= r) tmp[k++] = num[mr++];

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

}void mergesort(vector& num,int left,int right,vector& tmp)

void mergesort_begin(vector& num) //歸併排序入口

複雜度分析歸併排序的最壞時間複雜度為:o(nlogn),平均複雜度為:o(nlogn)。

5.快速排序

快速排序的思想從本質來說與歸併排序類似,也是分治。只不過快速排序是在陣列中選定了乙個軸點,比軸點小的數字劃分到左邊,比軸點大的劃分到右邊,這樣乙個陣列就被劃分成了兩部分,然後在這兩部分基礎上繼續選擇乙個軸點劃分,如此直到無法劃分為止。

排序過程可以參考如下圖

參考**

注:這裡是選取每個陣列最左邊的數字為軸點

int qs_partition(vector& num,int left,int right)

num[l] = pivot;

return l;

}void quicksort(vector& num,int left,int right)

上述的為遞迴的快速排序,如果資料量非常大可能會導致棧記憶體爆掉,所以可以用乙個棧來實現非遞迴的快速排序。

非遞迴的快速排序參考**

int qs_partition(vector& num,int left,int right)

num[l] = pivot;

return l;

}void stack_quicksort(vector& num)}}

複雜度分析快速排序的最壞時間複雜度為:o(n2),即軸點的左側或者右側沒有數字。最好的情況是左右兩側數字大致相同,平均複雜度為:o(nlogn)。

補充

快速排序的軸點選擇對於該排序演算法的效率有很大的影響,最普通的選取最左或者最右的數字作為軸點的方法其實不太穩定,常用的選取軸點的方法是隨機取值或者三值取中。

三值取中:顧名思義,在最左、最右、中間三個位置選取三個數字,然後在三個數字中選取值居於中間的那個數字作為軸點。

參考資料

visualgo演算法視覺化**

資料結構 2 排序演算法

常見的排序演算法 氣泡排序 選擇排序 插入排序 歸併排序 快速排序 堆排序 includeusing namespace std void swap int a,int i,int j 冒泡法 平均時間複雜度 o n 2 void bubblosort int a,int n void bubblo...

資料結構3 排序演算法

氣泡排序 演算法描述 排序問題是基本演算法,主要有冒泡演算法 插入排序以及選擇排序演算法。冒泡演算法是對整個列進行多次遍歷迴圈,直至將所有的數都比較一遍,每次迴圈都能產生乙個最大數放置於後面,這樣需要兩層迴圈 外層控制次數,內層控制單次冒泡,內層針對的是相鄰裡兩個進行比較的迴圈。using syst...

資料結構與演算法(九)排序

演算法 時間複雜度 平均 時間複雜度 最壞 時間複雜度 最好 空間複雜度 穩定性氣泡排序 o n 2 o n 2 o n o 1 穩定選擇排序 o n 2 o n 2 o n 2 o 1 不穩定插入排序 o n 2 o n 2 o n o 1 穩定希爾排序 o nlogn o n 2 o n o 1...