快速、歸併、堆排、冒泡、選擇、插入詳解
阿新 • • 發佈:2019-12-31
快速排序
分割槽(partition)
給一個陣列arr和一個num,要求大於num的在左邊,小於num的在右邊,要求時間複雜度是O(N),空間複雜度是O(1)。
虛擬碼:
1、給一個指標i,初始位置是0,表示當前指向的位置
2、進行分割槽操作,初始化 <= 區的位置在 -1
3、當前數 <= num 時,把當前數和 <= 區的下一個數交換,<= 往前走一個位置,當前數往前跳一個。
4、當前數 > num 時,直接往前跳一個。
5、重複3、4步驟,直到整個陣列遍歷完成。
複製程式碼
荷蘭國旗問題
現有紅白藍三個不同顏色的小球,亂序排列在一起,請重新排列這些小球,使得紅白藍三色的同顏色的球在一起。這個問題之所以叫荷蘭國旗問題,是因為我們可以將紅白藍三色小球想象成條狀物,有序排列後正好組成荷蘭國旗。
<==>其實這個問題等價於
給你一個陣列 arr和一個num。要求大於 num 在左邊,等於 num 在中間,小於 num 的在右邊。要求時間複雜度是 O(N)。空間複雜度是 O(1)
虛擬碼:
1、分割槽為 <區、>區
2、用指標 i 表示當前值,指標 less 表示 < 區的值(初始是 -1),指標 more 表示 > 區的值(初始是arr.length)
3、當前值 < num。把 i和 < 區的後一個數交換,i往前走,<區往前走
4、當前值 > num。把 i和 > 區的前一個樹交換,< 區往前走,i 不動
5、當前值 = num。i++
6、重複3、4、5直到遍歷完成
複製程式碼
經典快排
主要應用了partiton的思想。
時間複雜度
O(N^2)
因為會出現最壞情況。比如 1,2,3,4,5,6,7,8,9
第一次parition。 1,9 其中partition中迴圈是9次
第二次parition 8作為哨兵 1,9 8
這是個等差數列 N + N-1 + .... + 1
(N+1)*N/2 ~ O(N^2)
所以時間複雜度是 O(N^2)
最好的時候是通過partition分割槽的值是數值的中位數
這樣通過master公式得出時間複雜度是 O(Nlog N)
T(N) = 2T(N/2) + O(N) ~ O(N)
改進方式:
在通過隨機性最後讓陣列中別的值取代,這樣時間複雜度是 O(NlogN)
綜上:
經典快排的時間複雜度是 **O(N^2)**
改進的快排時間複雜度是 **O(NlogN)**
複製程式碼
空間複雜度
O(logN)
因為在操作中要把左右位置記住,下次partition時才能從相應的位置開始,
而這些位置是的數量就是一個樹的高度,所以時間複雜度是 O(logN)。
複製程式碼
穩定性
[ 2,1] 由演演算法思想得知,在排序過程中兩個2是會互換位置的,這個演演算法是不穩定的。
複製程式碼
優化
1、在哨兵處增加隨機性,可以使得快排的時間複雜度降到O(NlogN)
2、partition 時使用荷蘭國旗方式分成三段分割槽
3、快排數量較少時,使用其他普通的排序方式(在快排的過程是使用其他排序方式)。
複製程式碼
歸併排序
merge
給兩個陣列各自都是有序的,如何使得全部有序?
虛擬碼:
[2,7] [5,9,10]
1、準備兩個指標i、j,分別指向兩個陣列的頭部。再準備一個輔助陣列help,臨時儲存排好序的部分陣列。指標 n 指向輔助陣列0位置。
2、把 i 指標指向的值和 j 指標指向的值進行比較,誰小複製誰到輔助陣列help。同時 n 和 更小的指標往前走一步。直到指標i或者指標j到陣列的末尾
3、指標i 或者 指標 j 退出迴圈。把還沒跑到指標尾部的資料複製到 help 陣列中。
4、返回 help
複製程式碼
歸併排序邏輯
思想:
歸併排序是藉助上面 merge 的思想: 先把陣列分成左右兩部分,先讓左邊有序,
再讓右邊有序,最後整體有序。在 merge 中依次比較左右兩部分的值,
誰小 copy 誰到 help 陣列。然後在把 help 陣列複製到原陣列相應的位置。
複製程式碼
時間複雜度是 O(NlogN),因為這個排序可以表示成 T(N) = T(N/2) + O(N)。
根據 master 公式這個時間複雜度是 O(NlogN)。
空間複雜度是 O(N)。因為在 merge 中有個 help 陣列申請。
下面問題是歸併排序思想的應用。
小和問題
在一個陣列中, 每一個數左邊比當前數小的數累加起來, 叫做這個陣列的小和。 求一個陣列的小和。
例子:
對於[1,5]
1左邊比1小的數, 沒有;
3左邊比3小的數, 1;
4左邊比4小的數, 1、 3;
2左邊比2小的數, 1;
5左邊比5小的數, 1、 3、 4、 2
所以小和為1+1+3+1+1+3+4+2=16
複製程式碼
逆序對問題
在陣列中的兩個數字,如果前面一個數字大於後面的數字,則這兩個數字組成一個逆序對,輸入一個陣列,求出這個陣列中的逆序對的總數P。
比如在陣列 [1,5] 中總共有這兩個逆序對[3,2]、[4、2]
複製程式碼
逆序對問題2
與上題一樣,也是在 merge 中過程中操作
堆排序
氣泡排序
氣泡排序思想程式碼
比較前一個位置的數如果比後一個大,就交換,否則不交換。
複製程式碼
氣泡排序複雜度分析
- 演演算法時間是時間複雜度為O(n²)
- 空間複雜度為O(1)
- 選擇排序是穩定的(如果有相等元素,不交換,就可以做到穩定)
選擇排序
選擇排序思想程式碼
1、從待排序序列中,找到關鍵字最小的元素;起始假定第一個元素為最小
2、如果最小元素不是待排序序列的第一個元素,將其和第一個元素互換
3、從餘下的 N - 1 個元素中,找出關鍵字最小的元素,重複1,2步,直到排序結束。
複製程式碼
選擇排序複雜度分析
- 演演算法時間是時間複雜度為O(n²)
- 空間複雜度為O(1)
- 選擇排序是不穩定的( 不穩定演演算法,比如陣列 [5,1],依次排序過後,1,5交換位置。兩個5的相對次序發生了變化,因此是不穩定性的)
插入排序
插入排序思想程式碼
1、從第一個元素開始,該元素可以認為已經被排序
2、取出下一個元素,在已經排序的元素序列中從後向前掃描
3、如果下一個元素比掃描的元素小,交換。否則,跳出迴圈,繼續下次迴圈的排序
複製程式碼
插入排序複雜度分析
- 時間是時間複雜度為O(n²)。
- 空間複雜度為O(1)
- 插入排序是穩定的(對於陣列[2,4],當4插入有序陣列2,4,6時,當相等時,就停止,不做處理,可以做到穩定性)
總結
排序方法 | 時間複雜度 | 空間複雜度 | 穩定性 |
---|---|---|---|
快排 | O(NlogN) |