本文由 簡悅 SimpRead 轉碼, 原文地址 https://www.toutiao.com/i6732720817001464327/html
做者:郭耀華 來源:https://www.cnblogs.com/guoyaohua/p/8600214.html
最近幾天在研究排序算法,看了不少博客,發現網上有的文章中對排序算法解釋的並非很透徹,並且有不少代碼都是錯誤的,例若有的文章中在 「桶排序」 算法中對每一個桶進行排序直接使用了 Collection.sort()函數,這樣雖然能達到效果,但對於算法研究來說是不能夠的。算法
因此我根據這幾天看的文章,整理了一個較爲完整的排序算法總結,本文中的全部算法均有 JAVA 實現,經本人調試無誤後才發出,若有錯誤,請各位前輩指出。數組
0、排序算法說明數據結構
0.1 排序的定義ide
對一序列對象根據某個關鍵字進行排序。函數
0.2 術語說明性能
0.3 算法總結ui
圖片名詞解釋:設計
0.4 算法分類3d
0.5 比較和非比較的區別
常見的快速排序、歸併排序、堆排序、冒泡排序等屬於比較排序。在排序的最終結果裏,元素之間的次序依賴於它們之間的比較。每一個數都必須和其餘數進行比較,才能肯定本身的位置。
在冒泡排序之類的排序中,問題規模爲 n,又由於須要比較 n 次,因此平均時間複雜度爲 O(n²)。在歸併排序、快速排序之類的排序中,問題規模經過分治法消減爲 logN 次,因此時間複雜度平均 O(nlogn)。
比較排序的優點是,適用於各類規模的數據,也不在意數據的分佈,都能進行排序。能夠說,比較排序適用於一切須要排序的狀況。
計數排序、基數排序、桶排序則屬於非比較排序。非比較排序是經過肯定每一個元素以前,應該有多少個元素來排序。針對數組 arr,計算 arr[i] 以前有多少個元素,則惟一肯定了 arr[i] 在排序後數組中的位置。
非比較排序只要肯定每一個元素以前的已有的元素個數便可,全部一次遍歷便可解決。算法時間複雜度 O(n)。
非比較排序時間複雜度底,但因爲非比較排序須要佔用空間來肯定惟一位置。因此對數據規模和數據分佈有必定的要求。
一、冒泡排序(Bubble Sort)
冒泡排序是一種簡單的排序算法。它重複地走訪過要排序的數列,一次比較兩個元素,若是它們的順序錯誤就把它們交換過來。走訪數列的工做是重複地進行直到沒有再須要交換,也就是說該數列已經排序完成。
這個算法的名字由來是由於越小的元素會經由交換慢慢 「浮」 到數列的頂端。冒泡排序介紹:冒泡排序
1.1 算法描述
1.2 動圖演示
1.3 代碼實現
1.4 算法分析
最佳狀況:T(n) = O(n) 最差狀況:T(n) = O(n2) 平均狀況:T(n) = O(n2)
二、選擇排序(Selection Sort)
表現最穩定的排序算法之一,由於不管什麼數據進去都是 O(n2) 的時間複雜度,因此用到它的時候,數據規模越小越好。惟一的好處可能就是不佔用額外的內存空間了吧。理論上講,選擇排序可能也是平時排序通常人想到的最多的排序方法了吧。
選擇排序 (Selection-sort) 是一種簡單直觀的排序算法。它的工做原理:首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置,而後,再從剩餘未排序元素中繼續尋找最小(大)元素,而後放到已排序序列的末尾。以此類推,直到全部元素均排序完畢。
2.1 算法描述
n 個記錄的直接選擇排序可通過 n-1 趟直接選擇排序獲得有序結果。具體算法描述以下:
2.2 動圖演示
2.3 代碼實現
2.4 算法分析
最佳狀況:T(n) = O(n2) 最差狀況:T(n) = O(n2) 平均狀況:T(n) = O(n2)
三、插入排序(Insertion Sort)
插入排序(Insertion-Sort)的算法描述是一種簡單直觀的排序算法。它的工做原理是經過構建有序序列,對於未排序數據,在已排序序列中從後向前掃描,找到相應位置並插入。插入排序在實現上,一般採用 in-place 排序(即只需用到 O(1) 的額外空間的排序),於是在從後向前掃描過程當中,須要反覆把已排序元素逐步向後挪位,爲最新元素提供插入空間。
3.1 算法描述
通常來講,插入排序都採用 in-place 在數組上實現。具體算法描述以下:
3.2 動圖演示
3.2 代碼實現
3.4 算法分析
最佳狀況:T(n) = O(n) 最壞狀況:T(n) = O(n2) 平均狀況:T(n) = O(n2)
四、希爾排序(Shell Sort)
希爾排序是希爾(Donald Shell)於 1959 年提出的一種排序算法。希爾排序也是一種插入排序,它是簡單插入排序通過改進以後的一個更高效的版本,也稱爲縮小增量排序,同時該算法是衝破 O(n2)的第一批算法之一。它與插入排序的不一樣之處在於,它會優先比較距離較遠的元素。希爾排序又叫縮小增量排序。
希爾排序是把記錄按下表的必定增量分組,對每組使用直接插入排序算法排序;隨着增量逐漸減小,每組包含的關鍵詞愈來愈多,當增量減至 1 時,整個文件恰被分紅一組,算法便終止。
4.1 算法描述
咱們來看下希爾排序的基本步驟,在此咱們選擇增量 gap=length/2,縮小增量繼續以 gap = gap/2 的方式,這種增量選擇咱們能夠用一個序列來表示,{n/2,(n/2)/2…1},稱爲增量序列。希爾排序的增量序列的選擇與證實是個數學難題,咱們選擇的這個增量序列是比較經常使用的,也是希爾建議的增量,稱爲希爾增量,但其實這個增量序列不是最優的。此處咱們作示例使用希爾增量。
先將整個待排序的記錄序列分割成爲若干子序列分別進行直接插入排序,具體算法描述:
4.2 過程演示
4.3 代碼實現
4.4 算法分析
最佳狀況:T(n) = O(nlog2 n) 最壞狀況:T(n) = O(nlog2 n) 平均狀況:T(n) =O(nlog2n)
五、歸併排序(Merge Sort)
和選擇排序同樣,歸併排序的性能不受輸入數據的影響,但表現比選擇排序好的多,由於始終都是 O(n log n)的時間複雜度。代價是須要額外的內存空間。
歸併排序是創建在歸併操做上的一種有效的排序算法。該算法是採用分治法(Divide and Conquer)的一個很是典型的應用。歸併排序是一種穩定的排序方法。將已有序的子序列合併,獲得徹底有序的序列;即先使每一個子序列有序,再使子序列段間有序。若將兩個有序表合併成一個有序表,稱爲 2 - 路歸併。
5.1 算法描述
5.2 動圖演示
5.3 代碼實現
5.4 算法分析
最佳狀況:T(n) = O(n) 最差狀況:T(n) = O(nlogn) 平均狀況:T(n) = O(nlogn)
六、快速排序(Quick Sort)
快速排序的基本思想:經過一趟排序將待排記錄分隔成獨立的兩部分,其中一部分記錄的關鍵字均比另外一部分的關鍵字小,則可分別對這兩部分記錄繼續進行排序,以達到整個序列有序。
6.1 算法描述
快速排序使用分治法來把一個串(list)分爲兩個子串(sub-lists)。具體算法描述以下:
6.2 動圖演示
6.3 代碼實現
6.4 算法分析
最佳狀況:T(n) = O(nlogn) 最差狀況:T(n) = O(n2) 平均狀況:T(n) = O(nlogn)
七、堆排序(Heap Sort)
堆排序(Heapsort)是指利用堆這種數據結構所設計的一種排序算法。堆積是一個近似徹底二叉樹的結構,並同時知足堆積的性質:即子結點的鍵值或索引老是小於(或者大於)它的父節點。
7.1 算法描述
7.2 動圖演示
7.3 代碼實現
注意:這裏用到了徹底二叉樹的部分性質:
7.4 算法分析
最佳狀況:T(n) = O(nlogn) 最差狀況:T(n) = O(nlogn) 平均狀況:T(n) = O(nlogn)
八、計數排序(Counting Sort)
計數排序的核心在於將輸入的數據值轉化爲鍵存儲在額外開闢的數組空間中。做爲一種線性時間複雜度的排序,計數排序要求輸入的數據必須是有肯定範圍的整數。
計數排序 (Counting sort) 是一種穩定的排序算法。計數排序使用一個額外的數組 C,其中第 i 個元素是待排序數組 A 中值等於 i 的元素的個數。而後根據數組 C 來將 A 中的元素排到正確的位置。它只能對整數進行排序。
8.1 算法描述
8.2 動圖演示
8.3 代碼實現
8.4 算法分析
當輸入的元素是 n 個 0 到 k 之間的整數時,它的運行時間是 O(n + k)。計數排序不是比較排序,排序的速度快於任何比較排序算法。因爲用來計數的數組 C 的長度取決於待排序數組中數據的範圍(等於待排序數組的最大值與最小值的差加上 1),這使得計數排序對於數據範圍很大的數組,須要大量時間和內存。
最佳狀況:T(n) = O(n+k) 最差狀況:T(n) = O(n+k) 平均狀況:T(n) = O(n+k)
九、桶排序(Bucket Sort)
桶排序是計數排序的升級版。它利用了函數的映射關係,高效與否的關鍵就在於這個映射函數的肯定。
桶排序 (Bucket sort) 的工做的原理:假設輸入數據服從均勻分佈,將數據分到有限數量的桶裏,每一個桶再分別排序(有可能再使用別的排序算法或是以遞歸方式繼續使用桶排序進行排
9.1 算法描述
注意,若是遞歸使用桶排序爲各個桶排序,則當桶數量爲 1 時要手動減少 BucketSize 增長下一循環桶的數量,不然會陷入死循環,致使內存溢出。
9.2 圖片演示
9.3 代碼實現
9.4 算法分析
桶排序最好狀況下使用線性時間 O(n),桶排序的時間複雜度,取決與對各個桶之間數據進行排序的時間複雜度,由於其它部分的時間複雜度都爲 O(n)。很顯然,桶劃分的越小,各個桶之間的數據越少,排序所用的時間也會越少。但相應的空間消耗就會增大。
最佳狀況:T(n) = O(n+k) 最差狀況:T(n) = O(n+k) 平均狀況:T(n) = O(n2)
十、基數排序(Radix Sort)
基數排序也是非比較的排序算法,對每一位進行排序,從最低位開始排序,複雜度爲 O(kn), 爲數組長度,k 爲數組中的數的最大的位數;
基數排序是按照低位先排序,而後收集;再按照高位排序,而後再收集;依次類推,直到最高位。有時候有些屬性是有優先級順序的,先按低優先級排序,再按高優先級排序。最後的次序就是高優先級高的在前,高優先級相同的低優先級高的在前。基數排序基於分別排序,分別收集,因此是穩定的。基數排序:基數排序
10.1 算法描述
10.2 動圖演示
10.3 代碼實現
10.4 算法分析
最佳狀況:T(n) = O(n * k) 最差狀況:T(n) = O(n * k) 平均狀況:T(n) = O(n * k)
基數排序有兩種方法:
基數排序 vs 計數排序 vs 桶排序
這三種排序算法都利用了桶的概念,但對桶的使用方法上有明顯差別: