排序算法總結

基本概念

1. 時間復雜度

  • 定義:一個算法流程中,常數操作數量的指標,這個指標叫做O,big O。具體為,如果常數操作數量的表達式中,只要高階項,不要低階項,也不要高階項系數之后,剩下的部分記為f(N),那么該算法的時間復雜度為O(f(N))
  • 常數操作與數據量沒有關系,時間復雜度和數據量有關,只要高階項,且不要系數。

2. 空間復雜度

  • 定義:給的數組不占額外空間,額外空間是為了完成排序還需要多少輔助的空間。
  • 有限的幾個變量是O(1),長度為N的數組為O(N)。

3. 穩定性

  • 定義:一個數組在排完序后,相等的值的相對次序不發生變化。
  • 穩定性的作用:對引用類型的數據進行排序

4. 測試用例

隨機生成數組,用自帶的sort函數進行結果驗證。引用類型數據還要寫比對函數。

5. 遞歸和迭代

  • 所有遞歸都可以改為迭代。遞歸是系統自己壓棧,迭代就是自己壓棧。
  • 遞歸是自己調用自己,迭代是用while循環。
  • 生產環境里不要用遞歸。

基于比較的的排序

時間復雜度不可能低于O(N*logN)

一、冒泡排序

  • 時間復雜度:O(N^2)
  • 額外空間復雜度:O(1)
  • 是否可實現穩定性:是

1. 原理

從第一個數開始,比較相鄰的兩個數,大的數往下沉,每次排好未排序序列中的最大數。

2. 交換兩個數據的方法

(1)用temp變量保存。

var temp=a;
a=b;
b=temp;

(2)異或運算(XOR)。
異或滿足交換律和結合律,就是無進位相加,1+0=1,0+1=1,1+1=0。
缺點:float類型且引用地址相同不能用該方法。

a=a^b;
b=a^b;
a=a^b;

3. 時間復雜度

N+N-1+....+1=N(N+1)/2;只要高階項,不要低階項,也不要高階項系數,因此為O(N2)。

4. 空間復雜度

冒泡排序只需要幾個有限的變量空間,所以是O(1)。

5. 穩定性

相等的不交換,大于時交換,就可以保證穩定性。

二、插入排序

  • 時間復雜度O(N^2)
  • 額外空間復雜度O(1)
  • 是否可實現穩定性:是

1. 原理(類似撲克牌)

插入排序就是,在有序區中,從后往前,遇到大于自身的數就進行交互換,看什么時候停下來。直到最后一個數加入有序區。

2.空間復雜度

最差情況下1+...+N-1=(N-1)N/2,因此為O(N2)。

3. 空間復雜度

只需要幾個有限的變量空間,所以是O(1)。

4. 穩定性

相等的不交換,只有大于時交換,就可以保證穩定性。

三、選擇排序

  • 時間復雜度O(N^2)
  • 額外空間復雜度O(1)
  • 是否可實現穩定性:否

1. 原理

每次從無序區中選擇最小的數加入到有序區的末尾。與相應位置的數據進行交換

2.空間復雜度

每次遍歷找最小值:N+N-1+....+1=N(N+1)/2,因此為O(N2)。

3. 空間復雜度

只需要幾個有限的變量空間,所以是O(1)。

四、快速排序

  • 時間復雜度O(N*logN)
  • 額外空間復雜度必須為O(logN)
  • 是否可實現穩定性:額外空間復雜度為O(logN)的情況下不可以,增加額外空間可以,但快排要求的就是空間復雜度為O(logN)。

logN默認以2為底,代表長度為N的數組可以二分多少次。

1、求M([3,1,5,4,2])中不在N([9,2,7])中的數的集合,即求M-N的差集

(1)暴力搜索

將M中每個數依次與N中的數進行遍歷對比,不在N中就打印,在N中就直接跳過。
時間復雜度O(MN)。

(2)先排序再二分
  • N先排序,M中每個數通過二分搜索的方式確定有沒有。
  • 排序時間復雜度為O(A),二分搜索時間復雜度為O(MlogN)。該方法的總時間復雜度為O(A)+O(MlogN),化簡后為其中的大者。
  • L+(R-L)/2 = L+(R-L)>>1,位運算比除法快

2、隨機快排原理

  • 經典快排:將小于等于劃分為一個區域。
  • 改進快排:將小于和等于分為兩個區域。隨機找一個數作為基準,小于這個數的放左邊,等于的放中間,大于的放右邊,然后再遞歸將左右邊進行排序
3、代碼實現

(1)如果為null或者length<2,直接返回
(2)隨機選擇一個數作為基準數,交換至數組末尾
(3)partition返回等于基準數的左右邊界下標,再遞歸的對小于區和大于區進行快排。

4、時間復雜度

(1)選一個隨機的劃分數,為O(1)。
(2)partition過程,將數組劃分為三個區間,就是遍歷一次數組的過程為O(N)。
(3)左側和右側分別進行了遞歸。

  • 最差情況下,每次O(N)只能搞定一個數(1,2,3,4,5,6選擇第一個數為劃分數),最終復雜度為O(N2)。因此通過隨機選擇劃分值可以在概率上盡量避免出現最差的情況。
  • 最好情況下,左右差不多都是N/2,2T(N/2),用master公式計算,a=b=2,d=1,因此T(N)=N*logN。master公式只能用于遞歸規模一樣的情況。
  • 概率累加得到的期望值也為N*logN。

5、空間復雜度

因為左右需要遞歸排序,過程中需要不斷記錄劃分值的位置,因此空間復雜度為斷點樹的高度,即log(2)(N)

五、歸并排序

  • 時間復雜度O(N*logN)
  • 額外空間復雜度O(N)
  • 實現可以做到穩定性

1、原理

  • 遞歸法:將數組二分直至不能劃分,即每個組都只有一個數值,然后不斷合并排序。
  • 迭代法:room=1、2、4、8....不足就保持不變,不斷排序合并

2、小和問題

  • 問題:將每個數的左邊所有比它小的數進行累加,得到的和為小和。
  • 思路:對每個數而言,只需要知道我的右邊有多少個數比我大,我就累加幾次。通過歸并排序,在merge的的過程中,會依次遇到所有右邊比我 大的數。

3、求逆序對

  • 問題:存在多少對數對,數對中前面的數比后面的數大。
  • 思路:和小和問題同理,即對每個數而言,只需要知道我的右邊有多少個數比我小,在我這個位置就產生了多少對逆序對。

六、堆排序

  • 時間復雜度O(N*logN)
  • 額外空間復雜度O(1)
  • 實現不能做到穩定性

關鍵步驟:heapInsert, heapify,堆的擴大和縮小操作

1、堆的概念

  • 完全二叉樹:葉節點只能出現在最下層和次下層,并且最下面一層的結點都集中在該層最左邊的若干位置的二叉樹。
  • 平衡二叉樹(AVL樹):它是一棵空樹或它的左右兩個子樹的高度差的絕對值不超過1,并且左右兩個子樹都是一棵平衡二叉樹,同時,平衡二叉樹必定是二叉搜索樹,反之則不一定。
  • (算法上的堆,不是系統中的堆)就是一個完全二叉樹,可以把一個數組在邏輯上對應成一顆完全二叉樹,左孩子2i+1,右孩子2i+2,父(i-1)/2。
  • 大根堆:一定是一個完全二叉樹結構,任何一個根節點都是其所在數樹(子樹)中的最大值。

2、原理

(1)將數組變換為大根堆。每個數和父節點的值進行比較,如果大于父節點,就交換。時間復雜度=log1+log2+log3+...+logN=O(N)。
(2)此時根節點的值最大,然后交換根節點和最后一個節點,保持最后一個節點不動,size--,超過size就代表越界。然后再構建大根堆,以此往復,每次找打最大值,直至所有數據排完序。

最重要的heapinsert(初始化構建大根堆),heapify(下沉函數),size。優先級隊列的題目就是堆,建立堆的過程和任何一個堆沉下去的過程重要。

4、時間復雜度

(1)建立大根堆的過程為O(N)。
(2)heapify的過程就是樹的高度,為O(logN)。
(3)N個數的時間復雜度就是O(NlogN),但常數項很大。

5、堆排和快排對比

  • 空間復雜度:堆排的空間復雜度可以做到O(1)是因為它的父子節點是通過公式的方式找到的,而快排需要記錄斷點的位置。
  • 時間復雜度:堆排的常數項很大,不存在最好和最壞情況;快排的常數項小。

七、希爾排序

插入排序,就是步長為1的希爾排序。

八、系統中的排序原理

  • 數據量<60,插入排序,復雜度高,常數項少;
  • 數據量大的情況下,快速排序。

不基于比較的的排序

不基于比較的排序是有瓶頸的,對數據的位數和范圍有限制。

桶排序

桶排序只是一個概念,基數排序和計數排序是桶排序的具體實現。

一、計數排序

先準備好相應數量的桶,然后遍歷數據,將其放入對應的桶中,最后將桶中的數依次倒出來。

二、基數排序

  1. 取位數最多的記錄,其他不足該位數的補0。
  2. 按照個位數字依次放入桶中。
  3. 從0號桶開始,依次倒出來。先入桶的先倒(隊列結構)。
  4. 按照十位數進桶,再倒出來,如此反復,直到最高位,結束。

三、擴展

1、求排序后的最大相鄰數差值

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容