2、golang之快速排序


1、快速排序穩定性

快速排序是不穩定的算法,它不滿足穩定算法的定義。
算法穩定性 -- 假設在數列中存在a[i]=a[j],若在排序之前,a[i]在a[j]前面;並且排序之后,a[i]仍然在a[j]前面。則這個排序算法是穩定的!
 

2、快速排序時間復雜度

快速排序的時間復雜度在 最壞情況下是O(N²)平均的時間復雜度是O(N*lgN)
這句話很好理解:假設被排序的數列中有N個數。遍歷一次的時間復雜度是O(N),需要遍歷多少次呢? 至少lg(N+1)次,最多N次
(01) 為什么最少是lg(N+1)次?快速排序是采用的分治法進行遍歷的,我們將它看作一棵二叉樹,它需要遍歷的次數就是二叉樹的深度,而根據完全二叉樹的定義,它的深度至少是lg(N+1)。因此,快速排序的遍歷次數最少是lg(N+1)次。
(02) 為什么最多是N次?這個應該非常簡單,還是將快速排序看作一棵二叉樹,它的深度最大是N。因此,快讀排序的遍歷次數最多是N次。
 

3、示例

// golang
func quickSort(arr []int, start, end int) {
    if start < end {
        i, j := start, end
        key := arr[(start+end)/2]
        for i <= j {
            for arr[i] < key {
                i++
            }
            for arr[j] > key {
                j--
            }
            if i <= j {
                arr[i], arr[j] = arr[j], arr[i]
                i++
                j--
            }
        }

        if start < j {
            quickSort(arr, start, j)
        }
        if end > i {
            quickSort(arr, i, end)
        }
    }
}

4、算法流程分析

快速排序(Quick Sort)使用分治法策略。
它的基本思想是: 選擇一個基准數,通過一趟排序將要排序的數據 分割成獨立的兩部分;其中 一部分的所有數據都比另外一部分的所有數據都要小。然后,再按此方法對這兩部分數據分別進行快速排序,整個排序過程可以遞歸進行,以此達到整個數據變成有序序列。
快速排序流程:
  1. 從數列中挑出一個基准值。
  2. 將所有比基准值小的擺放在基准前面,所有比基准值大的擺在基准的后面(相同的數可以到任一邊);在這個分區退出之后,該基准就處於數列的中間位置。
  3. 遞歸地把"基准值前面的子數列"和"基准值后面的子數列"進行排序。
 
下面以數列a={30,40,60,10,20,50}為例,演示它的快速排序過程(如下圖)。
上圖只是給出了第1趟快速排序的流程。在第1趟中,設置x=a[i],即x=30。
(01) 從"右 --> 左"查找小於x的數:找到滿足條件的數a[j]=20,此時j=4;然后將a[j]賦值a[i],此時i=0;接着從左往右遍歷。
(02) 從"左 --> 右"查找大於x的數:找到滿足條件的數a[i]=40,此時i=1;然后將a[i]賦值a[j],此時j=4;接着從右往左遍歷。
(03) 從"右 --> 左"查找小於x的數:找到滿足條件的數a[j]=10,此時j=3;然后將a[j]賦值a[i],此時i=1;接着從左往右遍歷。
(04) 從"左 --> 右"查找大於x的數:找到滿足條件的數a[i]=60,此時i=2;然后將a[i]賦值a[j],此時j=3;接着從右往左遍歷。
(05) 從"右 --> 左"查找小於x的數:沒有找到滿足條件的數。當i>=j時,停止查找;然后將x賦值給a[i]。此趟遍歷結束!
按照同樣的方法,對子數列進行遞歸遍歷。最后得到有序數組!


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM