十大经典排序算法及比较与分析 ( 动画演示 ) ( 可视化工具 )
可視化工具及動(dòng)畫展示:舊金山大學(xué) (usfca)|數(shù)據(jù)結(jié)構(gòu)可視化工具
排序算法概念及描述:1.0 十大經(jīng)典排序算法(文章部分內(nèi)容引用自改文章)
參考:鄧俊輝 的數(shù)據(jù)結(jié)構(gòu)
本文未對(duì)排序算法概念進(jìn)行詳細(xì)說(shuō)明,只是提供已經(jīng)驗(yàn)證過(guò)的代碼及對(duì)算法核心進(jìn)行簡(jiǎn)要說(shuō)明
常用八種排序算法: 插入排序、希爾排序、選擇排序、冒泡排序、歸并排序、快速排序、堆排序、基數(shù)排序
·
全部代碼(github) C#版本
0X00 前言
排序算法是《數(shù)據(jù)結(jié)構(gòu)與算法》中最基本的算法之一。
排序算法可以分為內(nèi)部排序和外部排序,內(nèi)部排序是數(shù)據(jù)記錄在內(nèi)存中進(jìn)行排序,而外部排序是因排序的數(shù)據(jù)很大,一次不能容納全部的排序記錄,在排序過(guò)程中需要訪問(wèn)外存。常見的內(nèi)部排序算法有:插入排序、希爾排序、選擇排序、冒泡排序、歸并排序、快速排序、堆排序、基數(shù)排序等。用一張圖概括:
關(guān)于時(shí)間復(fù)雜度
平方階 (O(n2)) 排序 各類簡(jiǎn)單排序:直接插入、直接選擇和冒泡排序。
線性對(duì)數(shù)階 (O(nlog2n)) ( log2n 是以2為底數(shù)的n的對(duì)數(shù))排序: 快速排序、堆排序和歸并排序;
O(n1+§)) 排序 ( § 是介于 0 和 1 之間的常數(shù) ): 希爾排序
線性階 (O(n)) 排序: 基數(shù)排序,此外還有桶、箱排序。
關(guān)于穩(wěn)定性
穩(wěn)定的排序算法:冒泡排序、插入排序、歸并排序和基數(shù)排序。
不是穩(wěn)定的排序算法:選擇排序、快速排序、希爾排序、堆排序。
名詞解釋:
- n:數(shù)據(jù)規(guī)模
- k:"桶"的個(gè)數(shù)
- In-place:占用常數(shù)內(nèi)存,不占用額外內(nèi)存
- Out-place:占用額外內(nèi)存
- 穩(wěn)定性:排序后 2 個(gè)相等鍵值的順序和排序之前它們的順序相同
0X01 冒泡排序(起泡排序)
可視化工具及動(dòng)畫演示
/// <summary>/// 冒泡排序(A版本)/// 從后往前掃描待排序序列,如果前一個(gè)元素比后一個(gè)元素大,就交換它們兩個(gè),對(duì)每一對(duì)相鄰元素作同樣的工作;這樣,第一次掃描待排序的序列會(huì)找到一個(gè)最小值并將其放置在第一位,第二次掃描待排序的序列會(huì)找到一個(gè)第二小的值并將其放置在第二位,第三次掃描待排序的序列會(huì)找到一個(gè)第三小的值并將其放置在第三位,以此類推,直到將所有元素排序完畢;排序的過(guò)程就像泡泡不斷的往上冒,總是小的泡泡在最上面,大的泡泡在最下面。/// 時(shí)間復(fù)雜度:/// 雙層循環(huán)次數(shù):內(nèi)循環(huán)次數(shù) i=0(n-1),i=1(n-2),i=2(n-3),...,i=n-3(2),i=n-2(1)為等差數(shù)列,總次數(shù)=n*(0+n-1)/2=n*(n-1)/2/// 假設(shè)每次比較都需要交換,執(zhí)行內(nèi)循環(huán)一次時(shí)復(fù)雜度為2(比較一次+交換一次),所以復(fù)雜度=2*n(n-1)/2=n(n-1)/// 當(dāng)n非常大時(shí),多項(xiàng)式以冪次方最大的為標(biāo)準(zhǔn)所以復(fù)雜度O=n(n-1)=O(n*n)/// </summary>/// <param name="A"></param>void BubbleSort(int[] A){int n = A.Length;for (int i = 0; i < n - 1; i++){for (int j = 0; j < n - 1 - i; j++){if (A[j] > A[j + 1]){Swap(ref A[j + 1], ref A[j]);}}}}/// <summary>/// 冒泡排序(E版本)(最優(yōu)版本)/// 時(shí)間復(fù)雜度:/// 最優(yōu)的時(shí)間復(fù)雜度:當(dāng)數(shù)據(jù)本身是有序的時(shí)候,只會(huì)比較但是不會(huì)交換,內(nèi)循環(huán)執(zhí)行一圈就結(jié)束了,復(fù)雜度O=n-1=O(n)/// 最壞的時(shí)間復(fù)雜度:O=n(n-1)=O(n*n)/// </summary>/// <param name="A"></param>void BubbleSort_E(int[] A){int n = A.Length;bool sorted = false; //整體排序標(biāo)志,首先假定尚未排序while (!sorted){sorted = true;//假定有序for (int i = 0; i < n - 1; i++){if (A[i] > A[i + 1]){Swap(ref A[i + 1], ref A[i]);sorted = false;}}n--;//因整體排序不能保證,需要清除排序標(biāo)志}}0X02 選擇排序(直接選擇排序)
可視化工具及動(dòng)畫演示
/// <summary>/// 選擇排序(直接選擇排序)/// 一次從待排序的序列中選出最小(或最大)的一個(gè)元素,存放在已排好序的序列的后一個(gè)位置,直到全部待排序的數(shù)據(jù)元素排完;/// 時(shí)間復(fù)雜度:/// 雙層循環(huán)次數(shù):內(nèi)循環(huán)次數(shù) i=0(n),i=1(n-1),i=2(n-2),...,i=n-2(2),i=n-1(1)為等差數(shù)列,總次數(shù)=(n-1)*(0+n)/2=n*(n-1)/2/// 最壞情況每次比較都需要交換,執(zhí)行內(nèi)循環(huán)一次時(shí)復(fù)雜度為2(比較一次+交換一次),所以復(fù)雜度=2*n(n-1)/2=n(n-1),O=n(n-1)=O(n*n)/// 最優(yōu)情況每次比較都不需要交換,執(zhí)行內(nèi)循環(huán)一次時(shí)復(fù)雜度為1(比較一次),,所以復(fù)雜度=n(n-1)/2,O=n(n-1)/2=O(n*n)/// </summary>/// <param name="A"></param>void SelectionSort(int[] A){int n = A.Length;int min;for (int i = 0; i < n - 1; i++){min = i;for (int j = i; j < n; j++){if (A[min] > A[j]){min = j;}}Swap(ref A[min], ref A[i]);//Console.Write($"{i},{min}"); PrintArray(A, i, min+1);}}0X03 插入排序(直接插入排序)
適合少量元素排序
可視化工具及動(dòng)畫演示
0X04 希爾排序
基于插入排序
參考學(xué)習(xí):https://baijiahao.baidu.com/s?id=1644158198885715432&wfr=spider&for=pc
可視化工具及動(dòng)畫演示
0X05 歸并排序
可視化工具及動(dòng)畫演示
/// <summary>/// 歸并排序/// 首先兩個(gè)子序列分別是有序的(遞歸后最小數(shù)組長(zhǎng)度為1,認(rèn)為數(shù)組長(zhǎng)度為1時(shí)數(shù)組本身是有序的),這里對(duì)兩個(gè)子序列合并,挑選兩個(gè)子序列中最小的放入reg臨時(shí)序列中,直到兩個(gè)子序列中一個(gè)子序列被完全放入后結(jié)束,然后將另一個(gè)子序列復(fù)制到reg臨時(shí)序列中,最后臨時(shí)序列是合并后的有序序列了,將reg復(fù)制到A中/// 時(shí)間復(fù)雜度:假設(shè)遞歸一次的時(shí)間復(fù)雜度為T()/// 執(zhí)行1次遞歸的時(shí)間復(fù)雜度為T(n)=2*T(n/2)+n(兩個(gè)子序列合并,一共長(zhǎng)度為n)/// 執(zhí)行2次遞歸的時(shí)間復(fù)雜度為T(n)=4*T(n/2)+2n/// 執(zhí)行3次遞歸的時(shí)間復(fù)雜度為T(n)=8*T(n/8)+3n/// 類似二叉樹的層數(shù),層級(jí)=log2(n)+1/// 代入得T(n)=nT(1)+log2(n)*n/// 時(shí)間復(fù)雜度O=T(n)=nT(1)+log2(n)*n=O(nlog2(n))=(nlogn)/// /// </summary>/// <param name="A"></param>public void MergeSort(int[] A){int n = A.Length;int[] reg = new int[n];MergeSort(A, reg, 0, n - 1);}void MergeSort(int[] A, int[] reg, int start, int end){if (start >= end){return;}int mid = (start + end) >> 1;int start1 = start;int end1 = mid;int start2 = mid + 1;int end2 = end;MergeSort(A, reg, start1, end1);MergeSort(A, reg, start2, end2);int k = start;//首先兩個(gè)子序列分別是有序的,這里對(duì)兩個(gè)子序列合并,挑選兩個(gè)子序列中最小的放入reg臨時(shí)序列中,直到兩個(gè)子序列中一個(gè)子序列被完全放入后結(jié)束,然后將另一個(gè)子序列復(fù)制到reg臨時(shí)序列中,最后臨時(shí)序列是合并后的有序序列了,復(fù)制會(huì)A中while (start1 <= end1 && start2 <= end2){reg[k++] = A[start1] < A[start2] ? A[start1++] : A[start2++]; //}while (start1 <= end1){reg[k++] = A[start1++];}while (start2 <= end2){reg[k++] = A[start2++];}Array.Copy(reg, start, A, start, end - start + 1);}/// <summary>/// 歸并排序(非遞歸版)/// </summary>/// <param name="A"></param>public void MergeSort_E(int[] A){int n = A.Length;int[] a = A;int[] b = new int[n];int seg, start;for (seg = 1; seg < n; seg += seg){for (start = 0; start < n; start += seg + seg){int low = start, mid = Math.Min(start + seg, n), high = Math.Min(start + seg + seg, n);int k = low;int start1 = low, end1 = mid;int start2 = mid, end2 = high;while (start1 < end1 && start2 < end2)b[k++] = a[start1] < a[start2] ? a[start1++] : a[start2++];while (start1 < end1)b[k++] = a[start1++];while (start2 < end2)b[k++] = a[start2++];}Array.Copy(b, a, n);}}0X06 快速排序
可視化工具及動(dòng)畫演示
/// <summary>/// 快速排序/// 簡(jiǎn)單說(shuō)是給基準(zhǔn)數(shù)找正確索引位置的過(guò)程./// 快速排序是對(duì)冒泡排序的一種改進(jìn)。/// 首先選取一個(gè)初始值(一般選取待排序序列的第一個(gè)值),通過(guò)一趟排序?qū)⒋判蛐蛄蟹殖蓛蓚€(gè)子序列,使左子序列的所有數(shù)據(jù)都小于這個(gè)初始值,右子序列的所有數(shù)據(jù)都大于這個(gè)初始值,然后再按此方法分別對(duì)這兩個(gè)子序列進(jìn)行排序,遞歸的進(jìn)行上面的步驟,直至每一個(gè)數(shù)據(jù)項(xiàng)都有如下性質(zhì):該數(shù)據(jù)項(xiàng)左邊的數(shù)據(jù)都小于它,右邊的數(shù)據(jù)都大于它,這樣,整個(gè)序列就有序了。/// 時(shí)間復(fù)雜度:O=O(nlogn)和歸并排序推理類似,不再展開推理了/// /// </summary>/// <param name="A"></param>public void QuickSort(int[] A){int n = A.Length;QuickSort(A, 0, n - 1);}void QuickSort(int[] A, int low, int high){if (low >= high) return;int pivot = Partition(A, low, high);QuickSort(A, low, pivot - 1);QuickSort(A, pivot + 1, high);}int Partition(int[] A, int low, int high){int pivot = A[low]; //基準(zhǔn)數(shù)選取數(shù)組第一個(gè)元素(哨兵元素)while (low < high){while (low < high && A[high] >= pivot) --high;A[low] = A[high];while (low < high && A[low] <= pivot) ++low;A[high] = A[low];}A[low] = pivot;return low;}public void QuickSort_V(int[] A){Stack<int> stack = new Stack<int>();int pivot;int low = 0;int high = A.Length - 1;int start, end;stack.Push(high);stack.Push(low);while (stack.Count > 0){start = low = stack.Pop();end = high = stack.Pop();if (low >= high)continue;pivot = A[low];while (low < high){while (low < high && A[high] >= pivot) high--;A[low] = A[high];while (low < high && A[low] <= pivot) low++;A[high] = A[low];}A[low] = pivot;stack.Push(low - 1);stack.Push(start);stack.Push(end);stack.Push(low + 1);}}0X07 堆排序
可視化工具及動(dòng)畫演示
時(shí)間復(fù)雜度參考:堆排序的時(shí)間復(fù)雜度分析
0X08 計(jì)數(shù)排序
可視化工具及動(dòng)畫演示
/// <summary>/// 計(jì)數(shù)排序/// 計(jì)數(shù)排序不是一個(gè)比較排序算法/// 計(jì)數(shù)排序的核心在于將輸入的數(shù)據(jù)值轉(zhuǎn)化為鍵存儲(chǔ)在額外開辟的數(shù)組空間中。作為一種線性時(shí)間復(fù)雜度的排序,計(jì)數(shù)排序要求輸入的數(shù)據(jù)必須是有確定范圍的整數(shù)。/// 計(jì)數(shù)排序類似與桶排序,也是用空間換取了時(shí)間,計(jì)數(shù)排序要求數(shù)組必須在一個(gè)確定的區(qū)間內(nèi)。/// 過(guò)程1:1. 首先找出數(shù)組的最大值和最小值;2. 遍歷數(shù)組,以數(shù)字作為鍵,該數(shù)字出現(xiàn)的次數(shù)作為值插入哈希表中;3. 在最小值到最大值這個(gè)區(qū)間內(nèi)遍歷哈希表,將數(shù)字反向插入數(shù)組中。/// 過(guò)程2:/// 根據(jù)待排序集合中最大元素和最小元素的差值范圍,申請(qǐng)額外空間;/// 遍歷待排序集合,將每一個(gè)元素出現(xiàn)的次數(shù)記錄到元素值對(duì)應(yīng)的額外空間內(nèi);/// 對(duì)額外空間內(nèi)數(shù)據(jù)進(jìn)行計(jì)算,得出每一個(gè)元素的正確索引位置;/// 將待排序集合每一個(gè)元素移動(dòng)到計(jì)算得出的正確索引位置上。/// 時(shí)間復(fù)雜度:/// 如果原始數(shù)列的規(guī)模是n,最大最小整數(shù)的差值是m,由于代碼中第1、2、4步都涉及到遍歷原始數(shù)列,運(yùn)算量都是n,第3步遍歷統(tǒng)計(jì)數(shù)列,運(yùn)算量是m,所以總體運(yùn)算量是3n+m,去掉系數(shù),時(shí)間復(fù)雜度是O(n+m)。/// /// 空間復(fù)雜度:/// 如果不考慮結(jié)果數(shù)組,只考慮統(tǒng)計(jì)數(shù)組的話,空間復(fù)雜度是O(m)/// 計(jì)數(shù)排序的局限性:/// 當(dāng)數(shù)組最大和最小差值過(guò)大時(shí),并不適合計(jì)數(shù)排序/// 當(dāng)數(shù)組元素不是整數(shù)(不能轉(zhuǎn)化成整數(shù)計(jì)算的,浮點(diǎn)(用指數(shù)和浮點(diǎn)分部轉(zhuǎn)化)、字符等等)時(shí),也不適合用計(jì)數(shù)排序/// </summary>/// <param name="A"></param>public void CountingSort(int[] A){int n = A.Length;int[] sorting = new int[n];//1.找出數(shù)組中最大值、最小值int max = int.MinValue;int min = int.MaxValue;for (int i = 0; i < n; i++){max = Math.Max(max, A[i]);min = Math.Min(min, A[i]);}//初始化計(jì)數(shù)數(shù)組count,設(shè)長(zhǎng)度為mint[] counting = new int[max - min + 1];//2. 對(duì)計(jì)數(shù)數(shù)組各元素賦值,設(shè)長(zhǎng)度為mfor (int i = 0; i < n; i++)counting[A[i] - min]++;//3. 計(jì)數(shù)數(shù)組變形,新元素的值是前面元素累加之和的值for (int i = 1; i < counting.Length; i++)counting[i] += counting[i - 1];//4. 遍歷A中的元素,填充到結(jié)果數(shù)組中去,從后往前遍歷for (int i = n - 1; i >= 0; i--)sorting[--counting[A[i] - min]] = A[i];//5. 將結(jié)果復(fù)制到原始數(shù)組中Array.Copy(sorting, A, n);}0X09 桶排序
可視化工具及動(dòng)畫演示
/// <summary>/// 桶排序(Bucket Sort)(箱排序)/// 桶排序是計(jì)數(shù)排序的擴(kuò)展版本,計(jì)數(shù)排序可以看成每個(gè)桶只存儲(chǔ)相同元素,而桶排序每個(gè)桶存儲(chǔ)一定范圍的元素,通過(guò)映射函數(shù),將待排序數(shù)組中的元素映射到各個(gè)對(duì)應(yīng)的桶中,對(duì)每個(gè)桶中的元素進(jìn)行排序,最后將非空桶中的元素逐個(gè)放入原序列中。/// 算法過(guò)程:/// 根據(jù)待排序集合中最大元素和最小元素的差值范圍和映射規(guī)則,確定申請(qǐng)的桶個(gè)數(shù);/// 遍歷待排序集合,將每一個(gè)元素移動(dòng)到對(duì)應(yīng)的桶中;/// 對(duì)每一個(gè)桶中元素進(jìn)行排序,并移動(dòng)到已排序集合中。/// 時(shí)間復(fù)雜度:設(shè)桶內(nèi)比較排序?yàn)榭焖倥判?復(fù)雜度nlogn)/// 第一個(gè)循環(huán)為O(N),設(shè)桶的數(shù)量為M,平均每個(gè)桶的元素?cái)?shù)量為N/M,桶內(nèi)以快速排序?yàn)槔秊镹logN,復(fù)雜度為O(M*N/M*log2(N/M)+N)=O(N+N(log2(N)-log2(M)))/// 第二個(gè)循環(huán)為O(2N)/// 總復(fù)雜度為O(3N+N(log2(N)-log2(M)))=O(N+N(logN-LogM))/// 當(dāng)M=N時(shí) 復(fù)雜度為O(N)/// 當(dāng)M=1時(shí) 復(fù)雜度為O(N+Nlog(N))///這里桶內(nèi)排序使用的是鏈表指針?lè)绞?#xff0c;桶內(nèi)復(fù)雜度為O(1),可以忽略,總復(fù)雜度為O(N)/// </summary>/// <param name="A"></param>/// <param name="bucketSize">每個(gè)桶內(nèi)數(shù)據(jù)的預(yù)期數(shù)量</param>public void BucketSort(int[] A, int bucketSize = 1000){int n = A.Length;int index;//1.找出數(shù)組中最大值、最小值int max = int.MinValue;int min = int.MaxValue;for (int i = 0; i < n; i++){max = Math.Max(max, A[i]);min = Math.Min(min, A[i]);}int bucketCount = (max - min) / bucketSize + 1;LinkedList<int>[] bucket = new LinkedList<int>[bucketCount];for (int i = 0; i < n; i++){index = (A[i]-min) / bucketSize;if (bucket[index] == null)bucket[index] = new LinkedList<int>();BucketInsertSort(bucket[index], A[i]);}index = 0;for (int i = 0; i < bucket.Length; i++){LinkedList<int> linkedList = bucket[i];if (linkedList == null) continue;var current = linkedList.First;while (current != null){A[index++] = current.Value;current = current.Next;}}}/// <summary>/// 桶排序的桶內(nèi)排序,這里用的是指針選擇排序,還可使用快速排序/// </summary>/// <param name="list"></param>/// <param name="a"></param>void BucketInsertSort(LinkedList<int> list, int a){var current = list.First;if (current == null || current.Value > a){list.AddFirst(a);return;}while (current != null){if (current.Next == null || current.Next.Value > a){list.AddAfter(current, a);return;}current = current.Next;}}0X10 基數(shù)排序
可視化工具及動(dòng)畫演示
/// <summary>/// 基數(shù)排序/// 概念1:基數(shù)排序是一種非比較型整數(shù)排序算法,其原理是將整數(shù)按位數(shù)切割成不同的數(shù)字,然后按每個(gè)位數(shù)分別比較。由于整數(shù)也可以表達(dá)字符串(比如名字或日期)和特定格式的浮點(diǎn)數(shù),所以基數(shù)排序也不是只能使用于整數(shù)。/// 概念2:將所有待排序的數(shù)統(tǒng)一為相同的數(shù)位長(zhǎng)度,數(shù)位較短的數(shù)前面補(bǔ)零,然后從低位到高位按位比較,位數(shù)字小的排在前面,大的排在后面,這樣當(dāng)比較第N位時(shí)前N-1位都是有序的,如此循環(huán)的比較,直到最高位比較完成,整個(gè)序列就是有序的了。/// 時(shí)間復(fù)雜度:/// 設(shè)待排序列為n個(gè)記錄,序列中最大值的位數(shù)為d,數(shù)字的基數(shù)為 r,則進(jìn)行鏈?zhǔn)交鶖?shù)排序的時(shí)間復(fù)雜度為O(d(n+r))。當(dāng)分配數(shù)字時(shí)要對(duì)每一個(gè)數(shù)字進(jìn)行按位比較, 而收集數(shù)字時(shí)要進(jìn)行r次收集(如十進(jìn)制數(shù)字就要進(jìn)行從0到9共10次收集操作), 故一趟分配時(shí)間復(fù)雜度為O(n),一趟收集時(shí)間復(fù)雜度為O(r),共進(jìn)行d趟分配和收集。/// /// 基數(shù)排序 vs 計(jì)數(shù)排序 vs 桶排序/// 這三種排序算法都利用了桶的概念,但對(duì)桶的使用方法上有明顯差異:/// 基數(shù)排序:根據(jù)鍵值的每位數(shù)字來(lái)分配桶;/// 計(jì)數(shù)排序:每個(gè)桶只存儲(chǔ)單一鍵值;/// 桶排序:每個(gè)桶存儲(chǔ)一定范圍的數(shù)值;/// </summary>/// <param name="A"></param>public void RadixSort(int[] A){int n = A.Length;const int BASE = 10;int exp = 1;int max = int.MinValue;int[] tmp = new int[n];for (int i = 0; i < n; i++)if (A[i] > max) max = A[i];while (max / exp > 0){int[] bucket = new int[n];for (int i = 0; i < n; i++){bucket[A[i] / exp % BASE]++;}for (int i = 1; i < n; i++){bucket[i] += bucket[i - 1];}for (int i = n - 1; i >= 0; i--){tmp[--bucket[A[i] / exp % BASE]] = A[i];}Array.Copy(tmp, A, n);exp *= BASE;}}0X11 全部代碼(C#)
全部代碼(github)
0X12 排序算法耗時(shí)測(cè)試
全部代碼(github)
測(cè)試環(huán)境:(.Net4.6.1,win10)
數(shù)組長(zhǎng)度50,數(shù)組元素(0–1000).
BubbleSort總共花費(fèi)0.3393ms.
BubbleSort_E總共花費(fèi)0.1743ms.
SelectionSort總共花費(fèi)0.1832ms.
InsertionSort總共花費(fèi)0.1752ms.
InsertionSort_E總共花費(fèi)0.1461ms.
ShellSort總共花費(fèi)0.2367ms.
MergeSort總共花費(fèi)0.4245ms.
MergeSort_E總共花費(fèi)0.4201ms.
QuickSort總共花費(fèi)0.3644ms.
QuickSort_V總共花費(fèi)0.4239ms.
HeapSort總共花費(fèi)0.2615ms.
CountingSort總共花費(fèi)0.2181ms.
BucketSort總共花費(fèi)3.492ms.
RadixSort總共花費(fèi)0.3766ms.
數(shù)組長(zhǎng)度500,數(shù)組元素(0–1000).
BubbleSort總共花費(fèi)1.4969ms.
BubbleSort_E總共花費(fèi)1.7962ms.
SelectionSort總共花費(fèi)0.4618ms.
InsertionSort總共花費(fèi)1.2992ms.
InsertionSort_E總共花費(fèi)0.2969ms.
ShellSort總共花費(fèi)0.4273ms.
MergeSort總共花費(fèi)0.4269ms.
MergeSort_E總共花費(fèi)0.2781ms.
QuickSort總共花費(fèi)0.2806ms.
QuickSort_V總共花費(fèi)0.3587ms.
HeapSort總共花費(fèi)0.3837ms.
CountingSort總共花費(fèi)0.2465ms.
BucketSort總共花費(fèi)1.3181ms.
RadixSort總共花費(fèi)0.2294ms.
數(shù)組長(zhǎng)度1000,數(shù)組元素(0–1000).
BubbleSort總共花費(fèi)4.9505ms.
BubbleSort_E總共花費(fèi)4.669ms.
SelectionSort總共花費(fèi)1.2467ms.
InsertionSort總共花費(fèi)3.395ms.
InsertionSort_E總共花費(fèi)1.3513ms.
ShellSort總共花費(fèi)1.3414ms.
MergeSort總共花費(fèi)0.5231ms.
MergeSort_E總共花費(fèi)0.4844ms.
QuickSort總共花費(fèi)0.3366ms.
QuickSort_V總共花費(fèi)0.3937ms.
HeapSort總共花費(fèi)0.4446ms.
CountingSort總共花費(fèi)0.2668ms.
BucketSort總共花費(fèi)2.6375ms.
RadixSort總共花費(fèi)0.5076ms.
數(shù)組長(zhǎng)度5000,數(shù)組元素(0–1000).
BubbleSort總共花費(fèi)134.6438ms.
BubbleSort_E總共花費(fèi)141.5785ms.
SelectionSort總共花費(fèi)32.566ms.
InsertionSort總共花費(fèi)82.5932ms.
InsertionSort_E總共花費(fèi)17.178ms.
ShellSort總共花費(fèi)22.8029ms.
MergeSort總共花費(fèi)1.0649ms.
MergeSort_E總共花費(fèi)0.7582ms.
QuickSort總共花費(fèi)0.7838ms.
QuickSort_V總共花費(fèi)0.8333ms.
HeapSort總共花費(fèi)1.5709ms.
CountingSort總共花費(fèi)0.2693ms.
BucketSort總共花費(fèi)1.7872ms.
RadixSort總共花費(fèi)0.4634ms.
數(shù)組長(zhǎng)度10000,數(shù)組元素(0–1000).
BubbleSort總共花費(fèi)556.6481ms.
BubbleSort_E總共花費(fèi)528.7346ms.
SelectionSort總共花費(fèi)116.9845ms.
InsertionSort總共花費(fèi)306.6125ms.
InsertionSort_E總共花費(fèi)68.4407ms.
ShellSort總共花費(fèi)88.4968ms.
MergeSort總共花費(fèi)1.8969ms.
MergeSort_E總共花費(fèi)1.3673ms.
QuickSort總共花費(fèi)1.4713ms.
QuickSort_V總共花費(fèi)1.4491ms.
HeapSort總共花費(fèi)3.3177ms.
CountingSort總共花費(fèi)0.3216ms.
BucketSort總共花費(fèi)2.9245ms.
RadixSort總共花費(fèi)0.7497ms.
數(shù)組長(zhǎng)度30000,數(shù)組元素(0–1000).
BubbleSort總共花費(fèi)4702.0921ms.
BubbleSort_E總共花費(fèi)4660.4316ms.
SelectionSort總共花費(fèi)952.3607ms.
InsertionSort總共花費(fèi)2763.3749ms.
InsertionSort_E總共花費(fèi)610.9831ms.
ShellSort總共花費(fèi)777.4363ms.
MergeSort總共花費(fèi)5.3142ms.
MergeSort_E總共花費(fèi)3.806ms.
QuickSort總共花費(fèi)4.2744ms.
QuickSort_V總共花費(fèi)4.4204ms.
HeapSort總共花費(fèi)10.0902ms.
CountingSort總共花費(fèi)0.5658ms.
BucketSort總共花費(fèi)18.1321ms.
RadixSort總共花費(fèi)1.8263ms.
數(shù)組長(zhǎng)度100000,數(shù)組元素(0–1000).
BubbleSort總共花費(fèi)52096.3052ms.
BubbleSort_E總共花費(fèi)52299.5447ms.
SelectionSort總共花費(fèi)10567.5827ms.
InsertionSort總共花費(fèi)30973.0239ms.
InsertionSort_E總共花費(fèi)6888.8287ms.
ShellSort總共花費(fèi)8548.7395ms.
MergeSort總共花費(fèi)17.985ms.
MergeSort_E總共花費(fèi)13.3151ms.
QuickSort總共花費(fèi)19.1267ms.
QuickSort_V總共花費(fèi)18.6859ms.
HeapSort總共花費(fèi)36.055ms.
CountingSort總共花費(fèi)1.3793ms.
BucketSort總共花費(fèi)195.1004ms.
RadixSort總共花費(fèi)6.1907ms.
通過(guò)測(cè)試數(shù)據(jù)得出:
- 沒有空間開銷的算法中(不考慮原始數(shù)據(jù)局部有序) 小數(shù)據(jù)量(<500) 直接插入排序最優(yōu)(E版本) ;大數(shù)據(jù)量(>500) 快速排序最優(yōu)(遞歸版本,不考慮遞歸開銷)。
- 有空間開銷的算法中 (不考慮空間開銷大小,大數(shù)據(jù)量>1000)基數(shù)排序和計(jì)數(shù)排序最優(yōu),其次是歸并排序(E版本非遞歸)。
桶排序的耗時(shí)不是最優(yōu)的,這里的桶排序沒有設(shè)置桶的size,所以桶排序耗時(shí)不考慮。
如果有出入或者錯(cuò)誤望各位留言指正
0X13 十大算法比較與分析
- 這里是參考其他文章的結(jié)論進(jìn)行了羅列,我自己的測(cè)試結(jié)論參考上一節(jié)( 0X13 )節(jié)
-
直接插入排序 是對(duì)冒泡排序的改進(jìn),比冒泡排序快,但是只適用于數(shù)據(jù)量較小(1000 ) 的排序
-
希爾排序 比較簡(jiǎn)單,適用于小數(shù)據(jù)量(5000以下)的排序,比直接插入排序快、冒泡排序快,因此,希爾排序適用于小數(shù)據(jù)量的、排序速度要求不高的排序。
-
直接選擇排序 和冒泡排序算法一樣,適用于n值較小的場(chǎng)合,而且是排序算法發(fā)展的初級(jí)階段,在實(shí)際應(yīng)用中采用的幾率較小。
-
堆排序 比較適用于數(shù)據(jù)量達(dá)到百萬(wàn)及其以上的排序,在這種情況下,使用遞歸設(shè)計(jì)的快速排序和歸并排序可能會(huì)發(fā)生堆棧溢出的現(xiàn)象。
-
冒泡排序 是最慢的排序算法,是排序算法發(fā)展的初級(jí)階段,實(shí)際應(yīng)用中采用該算法的幾率比較小。
-
快速排序 是遞歸的、速度最快的排序算法,但是在內(nèi)存有限的情況下不是一個(gè)好的選擇;而且,對(duì)于基本有序的數(shù)據(jù)序列排序,快速排序反而變得比較慢。
-
歸并排序 比堆排序要快,但是需要的存儲(chǔ)空間增加一倍。
-
基數(shù)排序 適用于規(guī)模n值很大的場(chǎng)合,但是只適用于整數(shù)的排序,如果對(duì)浮點(diǎn)數(shù)進(jìn)行基數(shù)排序,則必須明確浮點(diǎn)數(shù)的存儲(chǔ)格式,然后通過(guò)某種方式將其映射到整數(shù)上,最后再映射回去,過(guò)程復(fù)雜。
摘自常用排序算法比較與分析
冒泡排序:
效率太低,通過(guò)冒泡可以掌握swap。
選擇排序:
效率較低,但經(jīng)常使用它內(nèi)部的循環(huán)方式來(lái)找最大值和最小值。
插入排序:
雖然平均效率低,但在序列基本有序時(shí),它很快,所以也有其適用范圍。
希爾排序:
是插入排序的改良,對(duì)空間思維訓(xùn)練有幫助。
快速排序:
快排是軟件工業(yè)中最常見的常規(guī)排序法,其雙向指針掃描和分區(qū)算法是核心。
往往用于解決類似問(wèn)題,特別地partition算法用來(lái)劃分不同性質(zhì)的元素,
partition->selectK,也用于著名的top問(wèn)題
O(NlgN),但是如果主元不是中位數(shù)的話,特別地如果每次主元都在數(shù)組區(qū)間的一側(cè),復(fù)雜度將退化為N2
工業(yè)優(yōu)化:三點(diǎn)取中法,絕對(duì)中值法,小數(shù)據(jù)量用插入排序
快排重視子問(wèn)題拆分
歸并排序:
空間換時(shí)間——逆序?qū)?shù),
歸并重視子問(wèn)題的解的合并
堆排序:
用到了二叉堆數(shù)據(jù)結(jié)構(gòu),是繼續(xù)掌握樹結(jié)構(gòu)的起手式。=插排+二分查找
上面7種都是基于比較的排序,可證明它們?cè)谠仉S機(jī)順序情況下最好是NlgN的,用決策樹證明
下面三個(gè)是非比較排序,在特定情況下會(huì)比基于比較的排序要快:
計(jì)數(shù)排序:
可以說(shuō)是最快的:O(N+k),k=maxOf(sourceArr),用它來(lái)解決問(wèn)題時(shí)必須注意如果序列中的值分布非常廣(最大值很大,元素分布很稀疏),
空間將會(huì)浪費(fèi)很多
所以計(jì)數(shù)排序的適用范圍是:序列的關(guān)鍵字比較集中,已知邊界,且邊界較小
桶排序:
先分桶,再用其他排序方法對(duì)桶內(nèi)元素排序,按桶的編號(hào)依次檢出。(分配-收集)
用它解決問(wèn)題必須注意序列的值是否均勻地分布在桶中。
如果不均勻,那么個(gè)別桶中的元素會(huì)遠(yuǎn)多于其他桶,桶內(nèi)排序用比較排序,極端情況下,全部元素在一個(gè)桶內(nèi),還是會(huì)退化成NlgN。
其時(shí)間復(fù)雜度是:時(shí)間復(fù)雜度: O(N+C),其中C=N(logN-logM),約等于NlgN
N是元素個(gè)數(shù),M是桶的個(gè)數(shù)。
基數(shù)排序:
kN級(jí)別(k是最大數(shù)的位數(shù))是整數(shù)數(shù)值型排序里面又快又穩(wěn)的,無(wú)論元素分布如何,
只開辟固定的輔助空間(10個(gè)桶)
對(duì)比桶排序,基數(shù)排序每次需要的桶的數(shù)量并不多。而且基數(shù)排序幾乎不需要任何“比較”操作,而桶排序在桶相對(duì)較少的情況下,桶內(nèi)多個(gè)數(shù)據(jù)必須進(jìn)行基于比較操作的排序。因此,在實(shí)際應(yīng)用中,對(duì)十進(jìn)制整數(shù)來(lái)說(shuō),基數(shù)排序更好用。
摘自10種排序算法的對(duì)比分析
0X14 數(shù)據(jù)結(jié)構(gòu)可視化工具
可視化工具及動(dòng)畫展示地址:舊金山大學(xué)|數(shù)據(jù)結(jié)構(gòu)可視化
十大排序算法可視化工具及動(dòng)畫演示展示
選擇上面的按鈕就可以播放啦
選擇上面的按鈕就可以播放啦
點(diǎn)擊向后跳就然后點(diǎn)上面的某個(gè)排序按鈕就可以重新播放啦
總結(jié)
以上是生活随笔為你收集整理的十大经典排序算法及比较与分析 ( 动画演示 ) ( 可视化工具 )的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 城市被淹,全都在家
- 下一篇: 学计算机去旧金山,旧金山大学的计算机专业