1. 程式人生 > 其它 >一文搞定十大排序演算法(動畫圖解)

一文搞定十大排序演算法(動畫圖解)

排序的定義
排序,就是重新排列表中的元素,使表中的元素滿足按關鍵字遞增或遞減的過程。為了査找方便,通常要求計算機中的表是按關鍵字有序的。
排序的確切定義如下:
演算法的穩定性:
若待排序表中有兩個元素 Ri 和 Rj,其對應的關鍵字 keyi = kcyj , 且在排序前 Ri 在 Rj 的前面。使用某一排序演算法排序後,Ri 仍然在 Rj 的前面盡的前面,則稱這個排序演算法是穩定的。否則稱排序演算法是不穩定的。
需要注意的是,演算法是否具有穩定性並不能衡量—個演算法的優劣,它主要針對演算法的性質進行描述。只需舉出一組關徤字的例項,即可說明一個演算法是不穩定的。
時間複雜度:[1](來自百度百科)
分析:隨著模組n的增大,演算法執行的時間的增長率和 f(n) 的增長率成正比,所以 f(n) 越小,演算法的時間複雜度越低,演算法的效率越高。
空間複雜度:[2](來自百度百科)
類似於時間複雜度的討論,一個演算法的空間複雜度 S(n) 定義為該演算法所耗費的儲存空間,它也是問題規模n的函式。漸近空間複雜度也常常簡稱為空間複雜度。
空間複雜度(SpaceComplexity)是對一個演算法在執行過程中臨時佔用儲存空間大小的量度。一個演算法在計算機儲存器上所佔用的儲存空間,包括儲存演算法本身所佔用的儲存空間,演算法的輸入輸出資料所佔用的儲存空間和演算法在執行過程中臨時佔用的儲存空間這三個方面。
演算法的輸入輸出資料所佔用的儲存空間是由要解決的問題決定的,是通過引數表由呼叫函式傳遞而來的,它不隨本演算法的不同而改變。儲存演算法本身所佔用的儲存空間與演算法書寫的長短成正比,要壓縮這方面的儲存空間,就必須編寫出較短的演算法。
演算法在執行過程中臨時佔用的儲存空間隨演算法的不同而異,有的演算法只需要佔用少量的臨時工作單元,而且不隨問題規模的大小而改變,我們稱這種演算法是“就地"進行的,是節省儲存的演算法,有的演算法需要佔用的臨時工作單元數與解決問題的規模 n 有關,它隨著n的增大而增大,當n較大時,將佔用較多的儲存單元,例如快速排序和歸併排序演算法就屬於這種情況。
演算法的分類可以按照是否是比較類的演算法來分類,也可以按照排序過程中資料是否都存在於記憶體中來分類:
如下:
按照內部排序和外部排序分類:

按照是否為比較類的排序來分:


插入排序(Insertion-Sort)的演算法描述是一種簡單直觀的排序演算法。它的工作原理是通過構建有序序列,對於未排序資料,在已排序序列中從後向前掃描,找到相應位置並插入。
演算法描述
一般來說,插入排序都採用in-place在陣列上實現。具體演算法描述如下:

  • 從第一個元素開始,該元素可以認為已經被排序;
  • 取出下一個元素,在已經排序的元素序列中從後向前掃描;
  • 如果該元素(已排序)大於新元素,將該元素移到下一位置;
  • 重複步驟3,直到找到已排序的元素小於或者等於新元素的位置;
  • 將新元素插入到該位置後;
  • 重複步驟2~5。
    動圖演示

C程式碼實現
演算法分析
插入排序在實現上,通常採用in-place排序(即只需用到O(1)的額外空間的排序),因而在從後向前掃描過程中,需要反覆把已排序元素逐步向後挪位,為最新元素提供插入空間。
1959年Shell發明,第一個突破O(n2)的排序演算法,是簡單插入排序的改進版。它與插入排序的不同之處在於,它會優先比較距離較遠的元素。希爾排序又叫縮小增量排序。
演算法描述
先將整個待排序的記錄序列分割成為若干子序列分別進行直接插入排序,具體演算法描述:
1.選擇一個增量序列t1,t2,…,tk,其中ti > tj,tk=1;
2.按增量序列個數k,對序列進行k 趟排序;
3.每趟排序,根據對應的增量ti,將待排序列分割成若干長度為m 的子序列,分別對各子表進行直接插入排序。僅增量因子為1 時,整個序列作為一個表來處理,表長度即為整個序列的長度。
動圖演示
C程式碼實現
演算法分析
希爾排序是基於插入排序的以下兩點性質而提出改進方法的:

  • 插入排序在對幾乎已經排好序的資料操作時, 效率高, 即可以達到線性排序的效率
  • 但插入排序一般來說是低效的, 因為插入排序每次只能將資料移動一位
    時間複雜度:最壞情況下為O(n^2),平均時間複雜度為O(nlogn);
    空間複雜度:歸併排序需要一個大小為1的臨時儲存空間用以儲存合併序列,所以空間複雜度為O(1);
    演算法穩定性:從上面圖片中可以看出,數字5在排序後交換了位置,所以它是不穩定的演算法。
    選擇排序(Selection-sort)是一種簡單直觀的排序演算法。它的工作原理:首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置,然後,再從剩餘未排序元素中繼續尋找最小(大)元素,然後放到已排序序列的末尾。以此類推,直到所有元素均排序完畢。
    演算法描述
    n個記錄的直接選擇排序可經過n-1趟直接選擇排序得到有序結果。具體演算法描述如下:
    4.初始狀態:無序區為R[1…n],有序區為空;
    5.第i趟排序(i=1,2,3…n-1)開始時,當前有序區和無序區分別為R[1…i-1]和R(i…n)。該趟排序從當前無序區中-選出關鍵字最小的記錄 R[k],將它與無序區的第1個記錄R交換,使R[1…i]和R[i+1…n)分別變為記錄個數增加1個的新有序區和記錄個數減少1個的新無序區;
    6.n-1趟結束,陣列有序化了。
    動圖演示

    C語言實現
    演算法分析
    表現最穩定的排序演算法之一,因為無論什麼資料進去都是O(n2)的時間複雜度,所以用到它的時候,資料規模越小越好。唯一的好處可能就是不佔用額外的記憶體空間了吧。理論上講,選擇排序可能也是平時排序一般人想到的最多的排序方法了吧。
    堆排序(Heapsort)是指利用堆這種資料結構所設計的一種排序演算法。堆積是一個近似完全二叉樹的結構,並同時滿足堆積的性質:即子結點的鍵值或索引總是小於(或者大於)它的父節點。
    演算法描述
    7.將初始待排序關鍵字序列(R1,R2….Rn)構建成大頂堆,此堆為初始的無序區;
    8.將堆頂元素R[1]與最後一個元素R[n]交換,此時得到新的無序區(R1,R2,……Rn-1)和新的有序區(Rn),且滿足R[1,2…n-1]<=R[n];
    9.由於交換後新的堆頂R[1]可能違反堆的性質,因此需要對當前無序區(R1,R2,……Rn-1)調整為新堆,然後再次將R[1]與無序區最後一個元素交換,得到新的無序區(R1,R2….Rn-2)和新的有序區(Rn-1,Rn)。不斷重複此過程直到有序區的元素個數為n-1,則整個排序過程完成。
    動圖演示

    程式碼實現:
    演算法分析:
    堆排序是一種選擇排序,整體主要由構建初始堆+交換堆頂元素和末尾元素並重建堆兩部分組成。其中構建初始堆經推導複雜度為O(n),在交換並重建堆的過程中,需交換n-1次,而重建堆的過程中,根據完全二叉樹的性質,[log2(n-1),log2(n-2)…1]逐步遞減,近似為nlogn。所以堆排序時間複雜度一般認為就是O(nlogn)級。
    氣泡排序是一種簡單的排序演算法。它重複地走訪過要排序的數列,一次比較兩個元素,如果它們的順序錯誤就把它們交換過來。走訪數列的工作是重複地進行直到沒有再需要交換,也就是說該數列已經排序完成。這個演算法的名字由來是因為越小的元素會經由交換慢慢“浮”到數列的頂端。
    演算法描述
    10.比較相鄰的元素。如果第一個比第二個大,就交換它們兩個;
    11.對每一對相鄰元素作同樣的工作,從開始第一對到結尾的最後一對,這樣在最後的元素應該會是最大的數;
    12.針對所有的元素重複以上的步驟,除了最後一個;
    13.重複步驟1~3,直到排序完成。
    動圖演示

    C語言實現
    演算法分析
    若檔案的初始狀態是正序的,一趟掃描即可完成排序。所需的關鍵字比較次數C和記錄移動次數M均達到最小值:Cmin = N - 1, Mmin = 0。所以,氣泡排序最好時間複雜度為O(N)。
    若初始檔案是反序的,需要進行 N -1 趟排序。每趟排序要進行 N - i 次關鍵字的比較(1 ≤ i ≤ N - 1),且每次比較都必須移動記錄三次來達到交換記錄位置。在這種情況下,比較和移動次數均達到最大值:
    Cmax = N(N-1)/2 = O(N2)
    Mmax = 3N(N-1)/2 = O(N2)
    氣泡排序的最壞時間複雜度為O(N2)。因此,氣泡排序的平均時間複雜度為O(N2)。
    快速排序的基本思想:通過一趟排序將待排記錄分隔成獨立的兩部分,其中一部分記錄的關鍵字均比另一部分的關鍵字小,則可分別對這兩部分記錄繼續進行排序,以達到整個序列有序。
    演算法描述
    快速排序使用分治法來把一個串(list)分為兩個子串(sub-lists)。具體演算法描述如下:
    14.從數列中挑出一個元素,稱為 “基準”(pivot);
    15.重新排序數列,所有元素比基準值小的擺放在基準前面,所有元素比基準值大的擺在基準的後面(相同的數可以到任一邊)。在這個分割槽退出之後,該基準就處於數列的中間位置。這個稱為分割槽(partition)操作;
    16.遞迴地(recursive)把小於基準值元素的子數列和大於基準值元素的子數列排序。
    動圖演示
    C語言實現
    演算法分析:
    當資料有序時,以第一個關鍵字為基準分為兩個子序列,前一個子序列為空,此時執行效率最差。
    而當資料隨機分佈時,以第一個關鍵字為基準分為兩個子序列,兩個子序列的元素個數接近相等,此時執行效率最好。
    所以,資料越隨機分佈時,快速排序效能越好;資料越接近有序,快速排序效能越差。
    歸併排序是建立在歸併操作上的一種有效的排序演算法。該演算法是採用分治法(Divide and Conquer)的一個非常典型的應用。將已有序的子序列合併,得到完全有序的序列;即先使每個子序列有序,再使子序列段間有序。若將兩個有序表合併成一個有序表,稱為2-路歸併。
    演算法描述
    17.把長度為n的輸入序列分成兩個長度為n/2的子序列;
    18.對這兩個子序列分別採用歸併排序;
    19.將兩個排序好的子序列合併成一個最終的排序序列。
    動圖演示

    C語言實現
    演算法分析
    歸併排序是一種穩定的排序方法。和選擇排序一樣,歸併排序的效能不受輸入資料的影響,但表現比選擇排序好的多,因為始終都是O(nlogn)的時間複雜度。代價是需要額外的記憶體空間。
    計數排序不是基於比較的排序演算法,其核心在於將輸入的資料值轉化為鍵儲存在額外開闢的陣列空間中。作為一種線性時間複雜度的排序,計數排序要求輸入的資料必須是有確定範圍的整數。
    演算法描述
    20.找出待排序的陣列中最大和最小的元素;
    21.統計陣列中每個值為i的元素出現的次數,存入陣列C的第i項;
    22.對所有的計數累加(從C中的第一個元素開始,每一項和前一項相加);
    23.反向填充目標陣列:將每個元素i放在新陣列的第C(i)項,每放一個元素就將C(i)減去1。
    動圖演示
    C語言實現
    演算法分析
    計數排序是一個穩定的排序演算法。當輸入的元素是 n 個 0到 k 之間的整數時,時間複雜度是O(n+k),空間複雜度也是O(n+k),其排序速度快於任何比較排序演算法。當k不是很大並且序列比較集中時,計數排序是一個很有效的排序演算法。
    基數排序是按照低位先排序,然後收集;再按照高位排序,然後再收集;依次類推,直到最高位。有時候有些屬性是有優先順序順序的,先按低優先順序排序,再按高優先順序排序。最後的次序就是高優先順序高的在前,高優先順序相同的低優先順序高的在前。
    演算法描述
    24.取得陣列中的最大數,並取得位數;
    25.arr為原始陣列,從最低位開始取每個位組成radix陣列;
    26.對radix進行計數排序(利用計數排序適用於小範圍數的特點);
    動圖演示
    C語言實現
    演算法分析
    基數排序基於分別排序,分別收集,所以是穩定的。但基數排序的效能比桶排序要略差,每一次關鍵字的桶分配都需要O(n)的時間複雜度,而且分配之後得到新的關鍵字序列又需要O(n)的時間複雜度。假如待排資料可以分為d個關鍵字,則基數排序的時間複雜度將是O(d*2n) ,當然d要遠遠小於n,因此基本上還是線性級別的。
    基數排序的空間複雜度為O(n+k),其中k為桶的數量。一般來說n>>k,因此額外空間需要大概n個左右。
    桶排序是計數排序的升級版。它利用了函式的對映關係,高效與否的關鍵就在於這個對映函式的確定。桶排序 (Bucket sort)的工作的原理:假設輸入資料服從均勻分佈,將資料分到有限數量的桶裡,每個桶再分別排序(有可能再使用別的排序演算法或是以遞迴方式繼續使用桶排序進行排)。
    演算法描述
    27.設定一個定量的陣列當作空桶;
    28.遍歷輸入資料,並且把資料一個一個放到對應的桶裡去;
    29.對每個不是空的桶進行排序;
    30.從不是空的桶裡把排好序的資料拼接起來。
    動圖演示
    C語言實現
    演算法分析
    桶排序最好情況下使用線性時間O(n),桶排序的時間複雜度,取決與對各個桶之間資料進行排序的時間複雜度,因為其它部分的時間複雜度都為O(n)。很顯然,桶劃分的越小,各個桶之間的資料越少,排序所用的時間也會越少。但相應的空間消耗就會增大。(end)

掃碼加小助手微信,回覆「面試」,可加入測試開發面試群。

加小助手,回覆「面試」
群內交流 BAT 大廠測試開發工程師面試經驗,同步高薪 Offer 資訊,並不定期組織名企測試經理、測試高工大咖分享,以及其他福利。

點一下好看,就少一個 Bug!### ⬇️ 點選“下方連結”,提升測試核心競爭力!https://qrcode.ceba.ceshiren.com/link?name=article&project_id=qrcode&from=bokeyuan&timestamp=1650615798
>>更多技術文章分享和免費資料領取