c++ 不插入重复元素但也不排序_面试时写不出排序算法?看这篇就够了
小Hub領讀:
本文主要詳細講述常見的八種排序算法的思想、實現以及復雜度。包括冒泡排序、快速排序、插入排序、希爾排序等等,文章講解非常詳細!
作者:靜默虛空
https://juejin.im/post/5cb6b8f551882532c334bcf2
本文已歸檔到:「blog」:https://github.com/dunwu/blog/tree/master/source/_posts/algorithm
本文中的示例代碼已歸檔到:「algorithm-tutorial」:https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/test/java/io/github/dunwu/algorithm/sort/SortStrategyTest.java
冒泡排序
要點
冒泡排序是一種交換排序。
什么是交換排序呢?
交換排序:兩兩比較待排序的關鍵字,并交換不滿足次序要求的那對數,直到整個表都滿足次序要求為止。
算法思想
它重復地走訪過要排序的數列,一次比較兩個元素,如果他們的順序錯誤就把他們交換過來。走訪數列的工作是重復地進行直到沒有再需要交換,也就是說該數列已經排序完成。
這個算法的名字由來是因為越小的元素會經由交換慢慢 “浮” 到數列的頂端,故名。
假設有一個大小為 N 的無序序列。冒泡排序就是要每趟排序過程中通過兩兩比較,找到第 i 個小(大)的元素,將其往上排。
以上圖為例,演示一下冒泡排序的實際流程:
假設有一個無序序列 {4. 3. 1. 2, 5}
第一趟排序:通過兩兩比較,找到第一小的數值 1 ,將其放在序列的第一位。
第二趟排序:通過兩兩比較,找到第二小的數值 2 ,將其放在序列的第二位。
第三趟排序:通過兩兩比較,找到第三小的數值 3 ,將其放在序列的第三位。
至此,所有元素已經有序,排序結束。
要將以上流程轉化為代碼,我們需要像機器一樣去思考,不然編譯器可看不懂。
假設要對一個大小為 N 的無序序列進行升序排序(即從小到大)。
每趟排序過程中需要通過比較找到第 i 個小的元素。
所以,我們需要一個外部循環,從數組首端 (下標 0) 開始,一直掃描到倒數第二個元素(即下標 N - 2) ,剩下最后一個元素,必然為最大。
假設是第 i 趟排序,可知,前 i-1 個元素已經有序?,F在要找第 i 個元素,只需從數組末端開始,掃描到第 i 個元素,將它們兩兩比較即可。
所以,需要一個內部循環,從數組末端開始(下標 N - 1),掃描到 (下標 i + 1)。
核心代碼
public void bubbleSort(int[] list) {算法分析
冒泡排序算法的性能
| 排序類別 | 交換排序 |
| 排序方法 | 冒泡排序 |
| 時間復雜度平均情況 | O(N2) |
| 時間復雜度最壞情況 | O(N3) |
| 時間復雜度最好情況 | O(N) |
| 空間復雜度 | O(1) |
| 穩定性 | 穩定 |
| 復雜性 | 簡單 |
時間復雜度
若文件的初始狀態是正序的,一趟掃描即可完成排序。所需的關鍵字比較次數 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)。
總結起來,其實就是一句話:當數據越接近正序時,冒泡排序性能越好。
算法穩定性
冒泡排序就是把小的元素往前調或者把大的元素往后調。比較是相鄰的兩個元素比較,交換也發生在這兩個元素之間。
所以相同元素的前后順序并沒有改變,所以冒泡排序是一種穩定排序算法。
優化
對冒泡排序常見的改進方法是加入標志性變量 exchange,用于標志某一趟排序過程中是否有數據交換。
如果進行某一趟排序時并沒有進行數據交換,則說明所有數據已經有序,可立即結束排序,避免不必要的比較過程。
核心代碼
// 對 bubbleSort 的優化算法示例代碼
我的 Github 測試例
樣本包含:數組個數為奇數、偶數的情況;元素重復或不重復的情況。且樣本均為隨機樣本,實測有效。
快速排序
要點
快速排序是一種交換排序。
快速排序由 C. A. R. Hoare 在 1962 年提出。
算法思想
它的基本思想是:
通過一趟排序將要排序的數據分割成獨立的兩部分:分割點左邊都是比它小的數,右邊都是比它大的數。
然后再按此方法對這兩部分數據分別進行快速排序,整個排序過程可以遞歸進行,以此達到整個數據變成有序序列。
詳細的圖解往往比大堆的文字更有說明力,所以直接上圖:
上圖中,演示了快速排序的處理過程:
初始狀態為一組無序的數組:2、4、5、1、3。
經過以上操作步驟后,完成了第一次的排序,得到新的數組:1、2、5、4、3。
新的數組中,以 2 為分割點,左邊都是比 2 小的數,右邊都是比 2 大的數。
因為 2 已經在數組中找到了合適的位置,所以不用再動。
2 左邊的數組只有一個元素 1,所以顯然不用再排序,位置也被確定。(注:這種情況時,left 指針和 right 指針顯然是重合的。因此在代碼中,我們可以通過設置判定條件 left 必須小于 right,如果不滿足,則不用排序了)。
而對于 2 右邊的數組 5、4、3,設置 left 指向 5,right 指向 3,開始繼續重復圖中的一、二、三、四步驟,對新的數組進行排序。
核心代碼
public int division(int[] list, int left, int right) {算法分析
快速排序算法的性能
| 排序類別 | 交換排序 |
| 排序方法 | 快速排序 |
| 時間復雜度平均情況 | O(Nlog2N) |
| 時間復雜度最壞情況 | O(N2) |
| 時間復雜度最好情況 | O(Nlog2N) |
| 空間復雜度 | O(Nlog2N) |
| 穩定性 | 不穩定 |
| 復雜性 | 較復雜 |
時間復雜度
當數據有序時,以第一個關鍵字為基準分為兩個子序列,前一個子序列為空,此時執行效率最差。
而當數據隨機分布時,以第一個關鍵字為基準分為兩個子序列,兩個子序列的元素個數接近相等,此時執行效率最好。
所以,數據越隨機分布時,快速排序性能越好;數據越接近有序,快速排序性能越差。
空間復雜度
快速排序在每次分割的過程中,需要 1 個空間存儲基準值。而快速排序的大概需要 Nlog2N 次的分割處理,所以占用空間也是 Nlog2N 個。
算法穩定性
在快速排序中,相等元素可能會因為分區而交換順序,所以它是不穩定的算法。
示例代碼
我的 Github 測試例
樣本包含:數組個數為奇數、偶數的情況;元素重復或不重復的情況。且樣本均為隨機樣本,實測有效。
插入排序
要點
直接插入排序是一種最簡單的插入排序。
插入排序:每一趟將一個待排序的記錄,按照其關鍵字的大小插入到有序隊列的合適位置里,知道全部插入完成。
算法思想
在講解直接插入排序之前,先讓我們腦補一下我們打牌的過程。
先拿一張 5 在手里,
再摸到一張 4,比 5 小,插到 5 前面,
摸到一張 6,嗯,比 5 大,插到 5 后面,
摸到一張 8,比 6 大,插到 6 后面,
。。。
最后一看,我靠,湊到的居然是同花順,這下牛逼大了。
以上的過程,其實就是典型的直接插入排序,每次將一個新數據插入到有序隊列中的合適位置里。
很簡單吧,接下來,我們要將這個算法轉化為編程語言。
假設有一組無序序列 R0, R1, ... , RN-1。
我們先將這個序列中下標為 0 的元素視為元素個數為 1 的有序序列。
然后,我們要依次把 R1, R2, ... , RN-1 插入到這個有序序列中。所以,我們需要一個外部循環,從下標 1 掃描到 N-1 。
接下來描述插入過程。假設這是要將 Ri 插入到前面有序的序列中。由前面所述,我們可知,插入 Ri 時,前 i-1 個數肯定已經是有序了。
所以我們需要將 Ri 和 R0 ~ Ri-1 進行比較,確定要插入的合適位置。這就需要一個內部循環,我們一般是從后往前比較,即從下標 i-1 開始向 0 進行掃描。
核心代碼
public void insertSort(int[] list) {算法分析
直接插入排序的算法性能
| 排序類別 | 插入排序 |
| 排序方法 | 直接插入排序 |
| 時間復雜度平均情況 | O(N2) |
| 時間復雜度最壞情況 | O(N2) |
| 時間復雜度最好情況 | O(N) |
| 空間復雜度 | O(1) |
| 穩定性 | 穩定 |
| 復雜性 | 簡單 |
時間復雜度
當數據正序時,執行效率最好,每次插入都不用移動前面的元素,時間復雜度為?O(N)。
當數據反序時,執行效率最差,每次插入都要前面的元素后移,時間復雜度為?O(N2)。
所以,數據越接近正序,直接插入排序的算法性能越好。
空間復雜度
由直接插入排序算法可知,我們在排序過程中,需要一個臨時變量存儲要插入的值,所以空間復雜度為?1?。
算法穩定性
直接插入排序的過程中,不需要改變相等數值元素的位置,所以它是穩定的算法。
示例代碼
我的 Github 測試例
樣本包含:數組個數為奇數、偶數的情況;元素重復或不重復的情況。且樣本均為隨機樣本,實測有效。
希爾排序
要點
希爾 (Shell) 排序又稱為縮小增量排序,它是一種插入排序。它是直接插入排序算法的一種威力加強版。
該方法因 DL.Shell 于 1959 年提出而得名。
算法思想
希爾排序的基本思想是:
把記錄按步長 gap?分組,對每組記錄采用直接插入排序方法進行排序。隨著步長逐漸減小,所分成的組包含的記錄越來越多,當步長的值減小到?1?時,整個數據合成為一組,構成一組有序記錄,則完成排序。
我們來通過演示圖,更深入的理解一下這個過程。
在上面這幅圖中:
初始時,有一個大小為 10 的無序序列。
在第一趟排序中,我們不妨設 gap1 = N / 2 = 5,即相隔距離為 5 的元素組成一組,可以分為 5 組。
接下來,按照直接插入排序的方法對每個組進行排序。
在 ** 第二趟排序中 **,我們把上次的 gap 縮小一半,即 gap2 = gap1 / 2 = 2 (取整數)。這樣每相隔距離為 2 的元素組成一組,可以分為 2 組。
按照直接插入排序的方法對每個組進行排序。
在第三趟排序中,再次把 gap 縮小一半,即 gap3 = gap2 / 2 = 1。這樣相隔距離為 1 的元素組成一組,即只有一組。
按照直接插入排序的方法對每個組進行排序。此時,排序已經結束。
需要注意一下的是,圖中有兩個相等數值的元素?5?和?5?。我們可以清楚的看到,在排序過程中,兩個元素位置交換了。
所以,希爾排序是不穩定的算法。
核心代碼
public void shellSort(int[] list) {算法分析
希爾排序的算法性能
| 排序類別 | 插入排序 |
| 排序方法 | 希爾排序 |
| 時間復雜度平均情況 | O(Nlog2N) |
| 時間復雜度最壞情況 | O(N1.5) |
| 時間復雜度最好情況 | |
| 空間復雜度 | O(1) |
| 穩定性 | 不穩定 |
| 復雜性 | 較復雜 |
時間復雜度
步長的選擇是希爾排序的重要部分。只要最終步長為 1 任何步長序列都可以工作。
算法最開始以一定的步長進行排序。然后會繼續以一定步長進行排序,最終算法以步長為 1 進行排序。當步長為 1 時,算法變為插入排序,這就保證了數據一定會被排序。
Donald Shell 最初建議步長選擇為 N/2 并且對步長取半直到步長達到 1。雖然這樣取可以比 O(N2) 類的算法(插入排序)更好,但這樣仍然有減少平均時間和最差時間的余地??赡芟柵判蜃钪匾牡胤皆谟诋斢幂^小步長排序后,以前用的較大步長仍然是有序的。比如,如果一個數列以步長 5 進行了排序然后再以步長 3 進行排序,那么該數列不僅是以步長 3 有序,而且是以步長 5 有序。如果不是這樣,那么算法在迭代過程中會打亂以前的順序,那就不會以如此短的時間完成排序了。
已知的最好步長序列是由 Sedgewick 提出的 (1, 5, 19, 41, 109,...),該序列的項來自這兩個算式。
這項研究也表明 “比較在希爾排序中是最主要的操作,而不是交換?!?用這樣步長序列的希爾排序比插入排序和堆排序都要快,甚至在小數組中比快速排序還快,但是在涉及大量數據時希爾排序還是比快速排序慢。
算法穩定性
由上文的希爾排序算法演示圖即可知,希爾排序中相等數據可能會交換位置,所以希爾排序是不穩定的算法。
直接插入排序和希爾排序的比較
直接插入排序是穩定的;而希爾排序是不穩定的。
直接插入排序更適合于原始記錄基本有序的集合。
希爾排序的比較次數和移動次數都要比直接插入排序少,當 N 越大時,效果越明顯。
在希爾排序中,增量序列 gap 的取法必須滿足:** 最后一個步長必須是 1 。**
直接插入排序也適用于鏈式存儲結構;希爾排序不適用于鏈式結構。
示例代碼
我的 Github 測試例
樣本包含:數組個數為奇數、偶數的情況;元素重復或不重復的情況。且樣本均為隨機樣本,實測有效。
簡單選擇排序
要點
簡單選擇排序是一種選擇排序。
選擇排序:每趟從待排序的記錄中選出關鍵字最小的記錄,順序放在已排序的記錄序列末尾,直到全部排序結束為止。
算法思想
從待排序序列中,找到關鍵字最小的元素;
如果最小元素不是待排序序列的第一個元素,將其和第一個元素互換;
從余下的 N - 1 個元素中,找出關鍵字最小的元素,重復 1、2 步,直到排序結束。
如圖所示,每趟排序中,將當前 ** 第 i 小的元素放在位置 i ** 上。
核心代碼
算法分析
簡單選擇排序算法的性能
| 排序類別 | 選擇排序 |
| 排序方法 | 簡單選擇排序 |
| 時間復雜度平均情況 | O(N2) |
| 時間復雜度最壞情況 | O(N2) |
| 時間復雜度最好情況 | O(N2) |
| 空間復雜度 | O(1) |
| 穩定性 | 不穩定 |
| 復雜性 | 簡單 |
時間復雜度
簡單選擇排序的比較次數與序列的初始排序無關。假設待排序的序列有?N?個元素,則 ** 比較次數總是 N (N - 1) / 2 **。
而移動次數與序列的初始排序有關。當序列正序時,移動次數最少,為?0.
當序列反序時,移動次數最多,為?3N (N - 1) / 2。
所以,綜合以上,簡單排序的時間復雜度為?O(N2)。
空間復雜度
簡單選擇排序需要占用一個臨時空間,在交換數值時使用。
示例代碼
我的 Github 測試例
樣本包含:數組個數為奇數、偶數的情況;元素重復或不重復的情況。且樣本均為隨機樣本,實測有效。
堆排序
要點
在介紹堆排序之前,首先需要說明一下,堆是個什么玩意兒。
堆是一棵順序存儲的完全二叉樹。
其中每個結點的關鍵字都不大于其孩子結點的關鍵字,這樣的堆稱為小根堆。其中每個結點的關鍵字都不小于其孩子結點的關鍵字,這樣的堆稱為大根堆。舉例來說,對于 n 個元素的序列 {R0, R1, ... , Rn} 當且僅當滿足下列關系之一時,稱之為堆:
Ri <= R2i+1 且 Ri <= R2i+2 (小根堆)
Ri >= R2i+1 且 Ri >= R2i+2 (大根堆)
其中 i=1,2,…,n/2 向下取整;
如上圖所示,序列 R{3, 8,15, 31, 25} 是一個典型的小根堆。
堆中有兩個父結點,元素 3 和元素 8。
元素 3 在數組中以 R[0] 表示,它的左孩子結點是 R[1],右孩子結點是 R[2]。
元素 8 在數組中以 R[1] 表示,它的左孩子結點是 R[3],右孩子結點是 R[4],它的父結點是 R[0]。可以看出,它們滿足以下規律:
設當前元素在數組中以?R[i]?表示,那么,
它的左孩子結點是:R[2*i+1];
它的右孩子結點是:R[2*i+2];
它的父結點是:R[(i-1)/2];
R[i] <= R[2*i+1] 且 R[i] <= R[2i+2]。
算法思想
首先,按堆的定義將數組 R[0..n] 調整為堆(這個過程稱為創建初始堆),交換 R[0] 和 R[n];
然后,將 R[0..n-1] 調整為堆,交換 R[0] 和 R[n-1];
如此反復,直到交換了 R[0] 和 R[1] 為止。
以上思想可歸納為兩個操作:
根據初始數組去構造初始堆(構建一個完全二叉樹,保證所有的父結點都比它的孩子結點數值大)。
每次交換第一個和最后一個元素,輸出最后一個元素(最大值),然后把剩下元素重新調整為大根堆。
當輸出完最后一個元素后,這個數組已經是按照從小到大的順序排列了。
先通過詳細的實例圖來看一下,如何構建初始堆。
設有一個無序序列 {1, 3,4, 5, 2, 6, 9, 7, 8, 0}。
構造了初始堆后,我們來看一下完整的堆排序處理:
還是針對前面提到的無序序列 {1,3, 4, 5, 2, 6, 9, 7, 8, 0} 來加以說明。
相信,通過以上兩幅圖,應該能很直觀的演示堆排序的操作處理。
核心代碼
public void HeapAdjust(int[] array, int parent, int length) {算法分析
堆排序算法的總體情況
| 排序類別 | 選擇排序 |
| 排序方法 | 堆排序 |
| 時間復雜度平均情況 | O(nlog2n) |
| 時間復雜度最壞情況 | O(nlog2n) |
| 時間復雜度最好情況 | O(nlog2n) |
| 空間復雜度 | O(1) |
| 穩定性 | 不穩定 |
| 復雜性 | 較復雜 |
時間復雜度
堆的存儲表示是順序的。因為堆所對應的二叉樹為完全二叉樹,而完全二叉樹通常采用順序存儲方式。
當想得到一個序列中第?k?個最小的元素之前的部分排序序列,最好采用堆排序。
因為堆排序的時間復雜度是?O(n+klog2n),若?k ≤ n/log2n,則可得到的時間復雜度為?O(n)。
算法穩定性
堆排序是一種不穩定的排序方法。
因為在堆的調整過程中,關鍵字進行比較和交換所走的是該結點到葉子結點的一條路徑,
因此對于相同的關鍵字就可能出現排在后面的關鍵字被交換到前面來的情況。
示例代碼
我的 Github 測試例
樣本包含:數組個數為奇數、偶數的情況;元素重復或不重復的情況。且樣本均為隨機樣本,實測有效。
歸并排序
要點
歸并排序是建立在歸并操作上的一種有效的排序算法,該算法是采用 ** 分治法(Divide and Conquer)** 的一個非常典型的應用。
將已有序的子序列合并,得到完全有序的序列;即先使每個子序列有序,再使子序列段間有序。若將兩個有序表合并成一個有序表,稱為二路歸并。
算法思想
將待排序序列 R[0...n-1] 看成是 n 個長度為 1 的有序序列,將相鄰的有序表成對歸并,得到 n/2 個長度為 2 的有序表;將這些有序序列再次歸并,得到 n/4 個長度為 4 的有序序列;如此反復進行下去,最后得到一個長度為 n 的有序序列。
綜上可知:
歸并排序其實要做兩件事:
“分解”——將序列每次折半劃分。
“合并”——將劃分后的序列段兩兩合并后排序。
我們先來考慮第二步,如何合并?
在每次合并過程中,都是對兩個有序的序列段進行合并,然后排序。
這兩個有序序列段分別為 R[low, mid] 和 R[mid+1, high]。
先將他們合并到一個局部的暫存數組?R2 中,帶合并完成后再將 R2 復制回 R 中。
為了方便描述,我們稱 R[low, mid] 第一段,R[mid+1, high] 為第二段。
每次從兩個段中取出一個記錄進行關鍵字的比較,將較小者放入 R2 中。最后將各段中余下的部分直接復制到 R2 中。
經過這樣的過程,R2 已經是一個有序的序列,再將其復制回 R 中,一次合并排序就完成了。
核心代碼
public void Merge(int[] array, int low, int mid, int high) {掌握了合并的方法,接下來,讓我們來了解如何分解。
在某趟歸并中,設各子表的長度為?gap,則歸并前 R[0...n-1] 中共有?n/gap?個有序的子表:R[0...gap-1],?R[gap...2*gap-1], ... ,?R[(n/gap)*gap ... n-1]。
調用 Merge?將相鄰的子表歸并時,必須對表的特殊情況進行特殊處理。
若子表個數為奇數,則最后一個子表無須和其他子表歸并(即本趟處理輪空):若子表個數為偶數,則要注意到最后一對子表中后一個子表區間的上限為 n-1。
核心代碼
public void MergePass(int[] array, int gap, int length) {算法分析
歸并排序算法的性能
| 排序類別 | 歸并排序 |
| 排序方法 | 歸并排序 |
| 時間復雜度平均情況 | O(nlog2n) |
| 時間復雜度最壞情況 | O(nlog2n) |
| 時間復雜度最好情況 | O(nlog2n) |
| 空間復雜度 | O(n) |
| 穩定性 | 穩定 |
| 復雜性 | 較復雜 |
時間復雜度
歸并排序的形式就是一棵二叉樹,它需要遍歷的次數就是二叉樹的深度,而根據完全二叉樹的可以得出它的時間復雜度是?O(n*log2n)。
空間復雜度
由前面的算法說明可知,算法處理過程中,需要一個大小為?n?的臨時存儲空間用以保存合并序列。
算法穩定性
在歸并排序中,相等的元素的順序不會改變,所以它是穩定的算法。
歸并排序和堆排序、快速排序的比較
若從空間復雜度來考慮:首選堆排序,其次是快速排序,最后是歸并排序。
若從穩定性來考慮,應選取歸并排序,因為堆排序和快速排序都是不穩定的。
若從平均情況下的排序速度考慮,應該選擇快速排序。
示例代碼
我的 Github 測試例
樣本包含:數組個數為奇數、偶數的情況;元素重復或不重復的情況。且樣本均為隨機樣本,實測有效。
基數排序
要點
基數排序與本系列前面講解的七種排序方法都不同,它不需要比較關鍵字的大小。
它是根據關鍵字中各位的值,通過對排序的 N 個元素進行若干趟 “分配” 與“收集”來實現排序的。
不妨通過一個具體的實例來展示一下,基數排序是如何進行的。
設有一個初始序列為: R {50, 123, 543, 187, 49, 30,0, 2, 11, 100}。
我們知道,任何一個阿拉伯數,它的各個位數上的基數都是以 0~9 來表示的。
所以我們不妨把 0~9 視為 10 個桶。
我們先根據序列的個位數的數字來進行分類,將其分到指定的桶中。例如:R[0] = 50,個位數上是 0,將這個數存入編號為 0 的桶中。
分類后,我們在從各個桶中,將這些數按照從編號 0 到編號 9 的順序依次將所有數取出來。
這時,得到的序列就是個位數上呈遞增趨勢的序列。
按照個位數排序:{50, 30, 0, 100, 11, 2, 123,543, 187, 49}。
接下來,可以對十位數、百位數也按照這種方法進行排序,最后就能得到排序完成的序列。
算法分析
基數排序的性能
| 排序類別 | 基數排序 |
| 排序方法 | 基數排序 |
| 時間復雜度平均情況 | O(d(n+r)) |
| 時間復雜度最壞情況 | O(d(n+r)) |
| 時間復雜度最好情況 | O(d(n+r)) |
| 空間復雜度 | O(n+r) |
| 穩定性 | 穩定 |
| 復雜性 | 較復雜 |
時間復雜度
通過上文可知,假設在基數排序中,r 為基數,d 為位數。則基數排序的時間復雜度為?O(d(n+r))。
我們可以看出,基數排序的效率和初始序列是否有序沒有關聯。
空間復雜度
在基數排序過程中,對于任何位數上的基數進行 “裝桶” 操作時,都需要?n+r?個臨時空間。
算法穩定性
在基數排序過程中,每次都是將當前位數上相同數值的元素統一 “裝桶”,并不需要交換位置。所以基數排序是穩定的算法。
示例代碼
我的 Github 測試例
樣本包含:數組個數為奇數、偶數的情況;元素重復或不重復的情況。且樣本均為隨機樣本,實測有效。
(完)
MarkerHub文章索引:
https://github.com/MarkerHub/JavaIndex
【推薦閱讀】
圖解Spring解決循環依賴,認清IOC!
是真的猛!SQL 語法速成手冊
面試官:BigDecimal一定不會丟失精度嗎?
通俗易懂講布隆過濾器
高并發之API接口,分布式,防刷限流,如何做?
好文章!點個在看!總結
以上是生活随笔為你收集整理的c++ 不插入重复元素但也不排序_面试时写不出排序算法?看这篇就够了的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: diskfileitemfactory
- 下一篇: dev c++ 代码补全_zsh配置与代