Table of Contents
本博客只用於自身學習,如有錯誤,虛心求教!!!
關於時間複雜度:
關於穩定性:
穩定的排序算法:冒泡排序、插入排序、歸併排序和基數排序。
不是穩定的排序算法:選擇排序、快速排序、希爾排序、堆排序。
名詞解釋:
n:數據規模
k:「桶」的個數
In-place:佔用常數內存,不佔用額外內存
Out-place:佔用額外內存
穩定性:排序後 2 個相等鍵值的順序和排序之前它們的順序相同
冒泡排序(Bubble Sort)也是一種簡單直觀的排序算法。它重複地走訪過要排序的數列,一次比較兩個元素,如果他們的順序錯誤就把他們交換過來。走訪數列的工作是重複地進行直到沒有再需要交換,也就是說該數列已經排序完成。這個算法的名字由來是因爲越小的元素會經由交換慢慢「浮」到數列的頂端。
作爲最簡單的排序算法之一,冒泡排序給我的感覺就像 Abandon 在單詞書裏出現的感覺一樣,每次都在第一頁第一位,所以最熟悉。冒泡排序還有一種優化算法,就是立一個 flag,當在一趟序列遍歷中元素沒有發生交換,則證明該序列已經有序。但這種改進對於提升性能來說並沒有什麼太大作用。
1. 算法步驟
2. 動圖演示
3.python代碼實現
# 冒泡排序 def bubble_sort(alist): # i 控制總共交換的輪數(每輪選出一個最大的移動最後) # if len(alist) = 9 的話,只需要 8 輪交換即可 for i in range(len(alist)-1): print('##############, i = %d' %i) # j控制: 選出最大的, 將最大移到最後 for j in range(len(alist)-1-i): if(alist[j] > alist[j+1]): # 前面 > 後面 交換 alist[j], alist[j+1] = alist[j+1], alist[j] print(alist)
out:
原列表爲:[54, 26, 93, 18, 17, 31, 44, 55, 20] ##############, i = 0 # 選出最大的 93 移到最後 [26, 54, 93, 18, 17, 31, 44, 55, 20] [26, 54, 93, 18, 17, 31, 44, 55, 20] [26, 54, 18, 93, 17, 31, 44, 55, 20] [26, 54, 18, 17, 93, 31, 44, 55, 20] [26, 54, 18, 17, 31, 93, 44, 55, 20] [26, 54, 18, 17, 31, 44, 93, 55, 20] [26, 54, 18, 17, 31, 44, 55, 93, 20] [26, 54, 18, 17, 31, 44, 55, 20, 93] ##############, i = 1 # # 選出次大的 55 [26, 54, 18, 17, 31, 44, 55, 20, 93] [26, 18, 54, 17, 31, 44, 55, 20, 93] [26, 18, 17, 54, 31, 44, 55, 20, 93] [26, 18, 17, 31, 54, 44, 55, 20, 93] [26, 18, 17, 31, 44, 54, 55, 20, 93] [26, 18, 17, 31, 44, 54, 55, 20, 93] [26, 18, 17, 31, 44, 54, 20, 55, 93] ##############, i = 2 [18, 26, 17, 31, 44, 54, 20, 55, 93] [18, 17, 26, 31, 44, 54, 20, 55, 93] [18, 17, 26, 31, 44, 54, 20, 55, 93] [18, 17, 26, 31, 44, 54, 20, 55, 93] [18, 17, 26, 31, 44, 54, 20, 55, 93] [18, 17, 26, 31, 44, 20, 54, 55, 93] ##############, i = 3 [17, 18, 26, 31, 44, 20, 54, 55, 93] [17, 18, 26, 31, 44, 20, 54, 55, 93] [17, 18, 26, 31, 44, 20, 54, 55, 93] [17, 18, 26, 31, 44, 20, 54, 55, 93] [17, 18, 26, 31, 20, 44, 54, 55, 93] ##############, i = 4 [17, 18, 26, 31, 20, 44, 54, 55, 93] [17, 18, 26, 31, 20, 44, 54, 55, 93] [17, 18, 26, 31, 20, 44, 54, 55, 93] [17, 18, 26, 20, 31, 44, 54, 55, 93] ##############, i = 5 [17, 18, 26, 20, 31, 44, 54, 55, 93] [17, 18, 26, 20, 31, 44, 54, 55, 93] [17, 18, 20, 26, 31, 44, 54, 55, 93] ##############, i = 6 [17, 18, 20, 26, 31, 44, 54, 55, 93] [17, 18, 20, 26, 31, 44, 54, 55, 93] ##############, i = 7 [17, 18, 20, 26, 31, 44, 54, 55, 93] 新列表爲:[17, 18, 20, 26, 31, 44, 54, 55, 93]
選擇排序是一種簡單直觀的排序算法,無論什麼數據進去都是 O(n²) 的時間複雜度。所以用到它的時候,數據規模越小越好。唯一的好處可能就是不佔用額外的內存空間了吧。
1. 算法步驟
2. 動圖演示
3. Python 代碼實現
def select_sort(alist): for i in range(len(alist)-1): min = i # 在未排序中 選出最小的 for j in range(i+1, len(alist)): if(alist[j] < alist[min]): min = j alist[min], alist[i] = alist[i], alist[min]
out:
原列表爲:[54, 26, 93, 18, 17, 31, 44, 55, 20] [17, 26, 93, 18, 54, 31, 44, 55, 20] [17, 18, 93, 26, 54, 31, 44, 55, 20] [17, 18, 20, 26, 54, 31, 44, 55, 93] [17, 18, 20, 26, 54, 31, 44, 55, 93] [17, 18, 20, 26, 31, 54, 44, 55, 93] [17, 18, 20, 26, 31, 44, 54, 55, 93] [17, 18, 20, 26, 31, 44, 54, 55, 93] [17, 18, 20, 26, 31, 44, 54, 55, 93] 新列表爲:[17, 18, 20, 26, 31, 44, 54, 55, 93]
插入排序的代碼實現雖然沒有冒泡排序和選擇排序那麼簡單粗暴,但它的原理應該是最容易理解的了,因爲只要打過撲克牌的人都應該能夠秒懂。插入排序是一種最簡單直觀的排序算法,它的工作原理是通過構建有序序列,對於未排序數據,在已排序序列中從後向前掃描,找到相應位置並插入。
插入排序和冒泡排序一樣,也有一種優化算法,叫做拆半插入。
1. 算法步驟
2. 動圖演示
3. Python 代碼實現
def insert_sort(alist): # i控制的是 未排序數組(角標) for i in range(1, len(alist)): # j 控制將拿到的元素放到前面有序序列中正確位置的過程 for j in range(i, 0, -1): # 如果比前面的元素小,則往前移動 if alist[j] < alist[j - 1]: alist[j], alist[j - 1] = alist[j - 1], alist[j] # 否則代表比前面的所有元素都小,不需要再移動 else: break
out:
原列表爲:[54, 26, 93, 18, 17, 31, 44, 55, 20] [26, 54, 93, 18, 17, 31, 44, 55, 20] [26, 54, 93, 18, 17, 31, 44, 55, 20] [18, 26, 54, 93, 17, 31, 44, 55, 20] [17, 18, 26, 54, 93, 31, 44, 55, 20] [17, 18, 26, 31, 54, 93, 44, 55, 20] [17, 18, 26, 31, 44, 54, 93, 55, 20] [17, 18, 26, 31, 44, 54, 55, 93, 20] [17, 18, 20, 26, 31, 44, 54, 55, 93] 新列表爲:[17, 18, 20, 26, 31, 44, 54, 55, 93]
希爾排序,也稱遞減增量排序算法,是插入排序的一種更高效的改進版本。但希爾排序是非穩定排序算法。
希爾排序是基於插入排序的以下兩點性質而提出改進方法的:
希爾排序的基本思想是:先將整個待排序的記錄序列分割成爲若干子序列分別進行直接插入排序,待整個序列中的記錄「基本有序」時,再對全體記錄進行依次直接插入排序。
1. 算法步驟
2. 排序過程
希爾排序的基本思想是:將數組列在一個表中並對列分別進行插入排序,重複這過程,不過每次用更長的列(步長更長了,列數更少了)來進行。最後整個表就只有一列了。將數組轉換至表是爲了更好地理解這算法,算法本身還是使用數組進行排序。
例如,假設有這樣一組數[ 13 14 94 33 82 25 59 94 65 23 45 27 73 25 39 10 ],如果我們以步長爲5開始進行排序,我們可以通過將這列表放在有5列的表中來更好地描述算法,這樣他們就應該看起來是這樣(豎着的元素是步長組成):
13 14 94 33 82
25 59 94 65 23
45 27 73 25 39
10
然後我們對每列進行排序:
10 14 73 25 23
13 27 94 33 39
25 59 94 65 82
45
將上述四行數字,依序接在一起時我們得到:[ 10 14 73 25 23 13 27 94 33 39 25 59 94 65 82 45 ]。這時10已經移至正確位置了,然後再以3爲步長進行排序:
10 14 73
25 23 13
27 94 33
39 25 59
94 65 82
45
排序之後變爲:
10 14 13
25 23 33
27 25 59
39 65 73
45 94 82
94
最後以1步長進行排序(此時就是簡單的插入排序了)
3. Python 代碼實現
# 希爾排序 def shell_sort(alist): ''' 分組之後更容易理解,對每列進行插入排序 ''' # 初始步長 gap = len(alist) // 2 while gap > 0: print('###############,gap爲:%d' %gap) for i in range(gap, len(alist)): # 每個步長進行插入排序 temp = alist[i] j = i # 插入排序 (分組,每組發生交換的執行) while j >= gap and alist[j - gap] > temp: alist[j] = alist[j - gap] j -= gap alist[j] = temp print(alist) # 得到新的步長 gap = gap // 2
out:
原列表爲:[54, 26, 93, 18, 17, 31, 44, 55, 20] ###############,gap爲:4 [17, 26, 93, 18, 54, 31, 44, 55, 20] # 54 > 17 交換 [17, 26, 93, 18, 54, 31, 44, 55, 20] # 26 < 31 不交換 [17, 26, 44, 18, 54, 31, 93, 55, 20] # 93 > 44 交換 [17, 26, 44, 18, 54, 31, 93, 55, 20] # 18 < 55 不交換 [17, 26, 44, 18, 20, 31, 93, 55, 54] # 17 > 20 > 54 交換 ###############,gap爲:2 [17, 26, 44, 18, 20, 31, 93, 55, 54] [17, 18, 44, 26, 20, 31, 93, 55, 54] [17, 18, 20, 26, 44, 31, 93, 55, 54] [17, 18, 20, 26, 44, 31, 93, 55, 54] [17, 18, 20, 26, 44, 31, 93, 55, 54] [17, 18, 20, 26, 44, 31, 93, 55, 54] [17, 18, 20, 26, 44, 31, 54, 55, 93] ###############,gap爲:1 [17, 18, 20, 26, 44, 31, 54, 55, 93] [17, 18, 20, 26, 44, 31, 54, 55, 93] [17, 18, 20, 26, 44, 31, 54, 55, 93] [17, 18, 20, 26, 44, 31, 54, 55, 93] [17, 18, 20, 26, 31, 44, 54, 55, 93] [17, 18, 20, 26, 31, 44, 54, 55, 93] [17, 18, 20, 26, 31, 44, 54, 55, 93] [17, 18, 20, 26, 31, 44, 54, 55, 93] 新列表爲:[17, 18, 20, 26, 31, 44, 54, 55, 93] [Finished in 0.0s]
歸併排序(Merge sort)是建立在歸併操作上的一種有效的排序算法。該算法是採用分治法(Divide and Conquer)的一個非常典型的應用。且各層分治遞歸可以同時進行。
採用 divide-and-conquer approach:
Divide: 把長度爲 n 的 array 分成兩半。
Conquer: 把左半邊 array 及右半邊 array 分別以 Merge Sort 進行 sorting。 (recursive)
Combine: merge 左半邊及右半邊 sorted array。
作爲一種典型的分而治之思想的算法應用,歸併排序的實現由兩種方法:
1. 算法步驟
遞歸法(Top-down)
迭代法(Bottom-up)
2. 動圖演示
當最左邊的分到最細之後無法再劃分左右然後開始進行合併。
第一次組合完成[4, 7]的合併
第二次組合完成[4, 7, 8]的合併
第三次組合完成[3, 5]的合併
第四次組合完成[3, 5, 9]的合併
第五次組合完成[3, 4, 5, 7, 8, 9]的合併結束排序。
3. Python 代碼實現
非遞歸實現:
def merge_sort(alist): for i in range(1, len(alist)): for low in range(0, len(alist)): mid = low + i height = min(low + 2 * i, len(alist)) if mid < height: left = seq[low:mid] right = seq[mid:height] alist[low:height] = merge(left, right) low += 2 * i i *= 2 return alist def merge(left, right): result = [] while left and right: if left[0] <= right[0]: result.append(left.pop(0)) else: result.append(right.pop(0)) if left: result += left if right: result += right return result if __name__ == '__main__': seq = [5, 4, 3, 0, 1, 2, 7, 5, 11,9] print(merge_sort(seq))
遞歸實現:
# 合併操作——遞歸實現 def merge_sort(alist): if len(alist) <= 1: return alist mid = len(alist) // 2 left = alist[:mid] right = alist[mid:] left = merge_sort(left) right = merge_sort(right) return merge(left, right) def merge(left, right): result = [] while left and right: if left[0] <= right[0]: result.append(left.pop(0)) else: result.append(right.pop(0)) if left: result += left if right: result += right return result
快速排序是由東尼·霍爾所發展的一種排序算法。在平均狀況下,排序 n 個項目要 Ο(nlogn) 次比較。在最壞狀況下則需要 Ο(n2) 次比較,但這種狀況並不常見。事實上,快速排序通常明顯比其他 Ο(nlogn) 算法更快,因爲它的內部循環(inner loop)可以在大部分的架構上很有效率地被實現出來。
快速排序使用分治法(Divide and conquer)策略來把一個串行(list)分爲兩個子串行(sub-lists)。
快速排序又是一種分而治之思想在排序算法上的典型應用。本質上來看,快速排序應該算是在冒泡排序基礎上的遞歸分治法。
快速排序的名字起的是簡單粗暴,因爲一聽到這個名字你就知道它存在的意義,就是快,而且效率高!它是處理大數據最快的排序算法之一了。雖然 Worst Case 的時間複雜度達到了 O(n²),但是人家就是優秀,在大多數情況下都比平均時間複雜度爲 O(n logn) 的排序算法表現要更好,可是這是爲什麼呢,我也不知道。好在我的強迫症又犯了,查了 N 多資料終於在《算法藝術與信息學競賽》上找到了滿意的答案:
快速排序的最壞運行情況是 O(n²),比如說順序數列的快排。但它的平攤期望時間是 O(nlogn),且 O(nlogn) 記號中隱含的常數因子很小,比複雜度穩定等於 O(nlogn) 的歸併排序要小很多。所以,對絕大多數順序性較弱的隨機數列而言,快速排序總是優於歸併排序。
1. 算法步驟
遞歸的最底部情形,是數列的大小是零或一,也就是永遠都已經被排序好了。雖然一直遞歸下去,但是這個算法總會退出,因爲在每次的迭代(iteration)中,它至少會把一個元素擺到它最後的位置去。
2. 動圖演示
快速排序採用的是一種分而治之的思想
平均時間複雜度:O(nlgn)
最差時間複雜度:O(n^2)
3. Python代碼實現
# 快排算法 def quick_sort(alist): if len(alist) < 2: # 基線條件 return alist else: # 遞歸條件 pivot = alist[0] less = [i for i in alist[1:] if i <= alist[0]] greater = [i for i in alist[1:] if i > alist[0]] print(less + [pivot] + greater) return quick_sort(less) + [pivot] + quick_sort(greater)
out:
alist = [11, 3, 14, 5, 21, 2, 2] print('alist快速排序之後:', quick_sort(alist)) # out: [3, 5, 2, 2, 11, 14, 21] [2, 2, 3, 5] [2, 2] [14, 21] alist快速排序之後: [2, 2, 3, 5, 11, 14, 21]
解法2:
#coding:utf-8 def quick_sort(lists, left, right): '''快速排序''' # 跳出遞歸判斷 if left >= right: return lists # 選擇參考點,該調整範圍的第1個值 key = lists[left] low = left high = right # 循環判斷直到遍歷全部 while left < right: # 從右邊開始查找大於(實際爲小於)參考點的值 while left < right and lists[right] >= key: right -= 1 lists[left] = lists[right] # 這個位置的值先挪到左邊 # 從左邊開始查找小於(實際爲大於)參考點的值 while left < right and lists[left] < key: left += 1 lists[right] = lists[left] # 這個位置的值挪到右邊 # 寫回改成的值 lists[left] = key # 遞歸,並返回結果 quick_sort(lists, low, left - 1) # 遞歸左邊部分 quick_sort(lists, left + 1, high) # 遞歸右邊部分 return lists
解法2-另寫
def partition(alist, left, right): '''快速排序''' # 選擇參考點,該調整範圍的第1個值 key = alist[left] # 循環判斷直到遍歷全部 while left < right: # 從右邊開始查找大於(實際爲小於)參考點的值 while left < right and alist[right] >= key: right -= 1 alist[left] = alist[right] # 這個位置的值先挪到左邊 # 從左邊開始查找小於(實際爲大於)參考點的值 while left < right and alist[left] < key: left += 1 alist[right] = alist[left] # 這個位置的值挪到右邊 # 寫回改成的值 alist[left] = key return left def quick_sort(alist, left, right): if left >= right: return alist j = partition(alist, left, right) quick_sort(alist, left, j - 1) # 遞歸左邊部分 quick_sort(alist, j + 1, right) # 遞歸右邊部分 return alist if __name__ == '__main__': seq = [5, 4, 3, 0, 1, 2, 7, 5, 11,9] print(quick_sort(seq, 0, len(seq)-1))
解法2-另寫
def partition(alist, left, right): '''快速排序''' # 選擇參考點,該調整範圍的第1個值 key = left # 循環判斷直到遍歷全部 while left < right: # 從右邊開始查找大於(實際爲小於)參考點的值 while left < right and alist[right] >= key: right -= 1 #alist[left] = alist[right] # 這個位置的值先挪到左邊 # 從左邊開始查找小於(實際爲大於)參考點的值 while left < right and alist[left] < key: left += 1 #alist[right] = alist[left] # 這個位置的值挪到右邊 alist[left], alist[right] = alist[right], alist[left] # 寫回改成的值 #alist[left] = key alist[left], alist[key] = alist[key], alist[left] return left def quick_sort(alist, left, right): if left >= right: return alist j = partition(alist, left, right) quick_sort(alist, left, j - 1) # 遞歸左邊部分 quick_sort(alist, j + 1, right) # 遞歸右邊部分 return alist if __name__ == '__main__': seq = [5, 4, 3, 0, 1, 2, 7, 5, 11,9] print(quick_sort(seq, 0, len(seq)-1))
快排的平均情況和最糟情況
參考:https://blog.csdn.net/minxihou/article/details/51850001
https://blog.csdn.net/dujiahaogod/article/details/79688331
堆排序(Heapsort)是指利用堆這種數據結構所設計的一種排序算法。堆積是一個近似完全二叉樹的結構,並同時滿足堆積的性質:即子結點的鍵值或索引總是小於(或者大於)它的父節點。堆排序可以說是一種利用堆的概念來排序的選擇排序。分爲兩種方法:
堆排序的平均時間複雜度爲 Ο(nlogn)。
其實我們的堆排序算法就是抓住了堆的這一特點,每次都取堆頂的元素,將其放在序列最後面,然後將剩餘的元素重新調整爲最大堆,依次類推,最終得到排序的序列。
堆可以分爲大根堆和小根堆,這裏用最大堆的情況來定義操作:
(1)最大堆調整(MAX_Heapify):將堆的末端子節點作調整,使得子節點永遠小於父節點。這是核心步驟,在建堆和堆排序都會用到。比較i的根節點和與其所對應i的孩子節點的值。當i根節點的值比左孩子節點的值要小的時候,就把i根節點和左孩子節點所對應的值交換,當i根節點的值比右孩子的節點所對應的值要小的時候,就把i根節點和右孩子節點所對應的值交換。然後再調用堆調整這個過程,可見這是一個遞歸的過程。
(2)建立最大堆(Build_Max_Heap):將堆所有數據重新排序。建堆的過程其實就是不斷做最大堆調整的過程,從len/2出開始調整,一直比到第一個節點。
(3)堆排序(HeapSort):移除位在第一個數據的根節點,並做最大堆調整的遞歸運算。堆排序是利用建堆和堆調整來進行的。首先先建堆,然後將堆的根節點選出與最後一個節點進行交換,然後將前面len-1個節點繼續做堆調整的過程。直到將所有的節點取出,對於n個數我們只需要做n-1次操作。
堆排序,顧名思義,就是基於堆。因此先來介紹一下堆的概念。
堆分爲最大堆和最小堆,其實就是完全二叉樹。最大堆要求節點的元素都要大於其孩子,最小堆要求節點元素都小於其左右孩子,兩者對左右孩子的大小關係不做任何要求,其實很好理解。有了上面的定義,我們可以得知,處於最大堆的根節點的元素一定是這個堆中的最大值。其實我們的堆排序算法就是抓住了堆的這一特點,每次都取堆頂的元素,將其放在序列最後面,然後將剩餘的元素重新調整爲最大堆,依次類推,最終得到排序的序列。
節點 i 的左孩子索引: 2*i+1
節點 i 的右孩子索引: 2*i+2
結點 i 的父節點索引 :(i-1)/2
1. 算法步驟
堆排序就是把堆頂的最大數取出,
將剩餘的堆繼續調整爲最大堆,以遞歸實現
剩餘部分調整爲最大堆後,再次將堆頂的最大數取出,再將剩餘部分調整爲最大堆,這個過程持續到剩餘數只有一個時結束
在堆的數據結構中,堆中的最大值總是位於根節點。堆中定義以下幾種操作:
2. 動圖演示
另一個堆排序動畫展示:https://bajdcc.github.io/html/heap.html
3. Python代碼實現(畫樹狀圖容易理解)
版本1
def heap_sort(lst): #生成最大堆 for start in range(len(lst)//2-1, -1, -1): shift_heap(lst, start, len(lst)-1) #最大堆調整 for end in range(len(lst)-1, 0, -1): lst[0], lst[end] = lst[end], lst[0] shift_heap(lst, 0, end - 1) return lst def shift_heap(lst, start, end): root = start while True: child = root * 2 + 1 if child > end: break if child + 1 <= end and lst[child] < lst[child + 1]: child = child + 1 if lst[root] < lst[child]: lst[root], lst[child] = lst[child], lst[root] root = child else: break lst = [1,2,3,5,4,2,3,5,6] # lst = [3,3,2,2,1,4,1,4] print(heap_sort(lst))
版本2
# 堆排序 def heap_sort(alist): def max_heapify(start, end): """最大堆調整""" root = start while True: child = 2 * root + 1 # child角標 超出角標最大值 if child > end: break # 左節點 < 右節點 child改爲右節點角標 if child + 1 <= end and alist[child] < alist[child + 1]: child += 1 # 根節點值 < child節點值 交換 if alist[root] < alist[child]: alist[root], alist[child] = alist[child], alist[root] root = child else: break # 創建最大堆(保證了 根節點 大於 子節點!!!!!!!!!!!) # (len(alist)-2)//2 = len(alist)//2 - 1 爲根節點,從最底層根節點開始 for start in range((len(alist) - 2) // 2, -1, -1): max_heapify(start, len(alist) - 1) print(alist) # 堆排序 for end in range(len(alist) - 1, 0, -1): alist[0], alist[end] = alist[end], alist[0] max_heapify(0, end - 1) print('########') print(alist) return alist
out:
原列表爲:[54, 26, 93, 18, 17, 31, 44, 55, 20] [54, 26, 93, 55, 17, 31, 44, 18, 20] #座標 3<->7 換,18<->55 [54, 26, 93, 55, 17, 31, 44, 18, 20] #座標 2<->5 換, [54, 55, 93, 26, 17, 31, 44, 18, 20] #座標 1<->3 換,26<->55 [93, 55, 54, 26, 17, 31, 44, 18, 20] #座標 0<->2 換,54<->93 ######## [55, 26, 54, 20, 17, 31, 44, 18, 93] ######## [54, 26, 44, 20, 17, 31, 18, 55, 93] ######## [44, 26, 31, 20, 17, 18, 54, 55, 93] ######## [31, 26, 18, 20, 17, 44, 54, 55, 93] ######## [26, 20, 18, 17, 31, 44, 54, 55, 93] ######## [20, 17, 18, 26, 31, 44, 54, 55, 93] ######## [18, 17, 20, 26, 31, 44, 54, 55, 93] ######## [17, 18, 20, 26, 31, 44, 54, 55, 93] 新列表爲:[17, 18, 20, 26, 31, 44, 54, 55, 93]
參考:https://blog.csdn.net/wardseptember/article/details/81434641
計數排序的核心在於將輸入的數據值轉化爲鍵存儲在額外開闢的數組空間中。作爲一種線性時間複雜度的排序,計數排序要求輸入的數據必須是有確定範圍的整數。
1. 算法步驟
2. 動圖演示
3. Python代碼實現
# 計數排序 def count_Sort(alist): alist_len = len(alist) alist_max = max(alist)#返回最大值 alist_min = min(alist)#返回最小值 #計算待排序列表的元素數值區域長度,如4-9共9+1-4=6個數 count_alist_length = alist_max + 1 - alist_min count_alist = [0] * count_alist_length #構造一個全爲0列表 for number in alist: count_alist[number - alist_min] += 1 #統計列表中每個值出現的次數, #使counting_arr[i]存放<=i的元素個數,就是待排序列表中比某個值小的元素有多少個 for i in range(1, count_alist_length): count_alist[i] = count_alist[i] + count_alist[i-1] order_list = [0] * alist_len #存放排序結果 #使每個元素被放在ordered中正確的位置,升序 for i in range(alist_len): order_list[count_alist[alist[i] - alist_min]-1] = alist[i]#-1是因爲下標從0開始的 count_alist[alist[i] - alist_min] -= 1 #每歸位一個元素,就少一個元素 return order_list
參考:https://github.com/hustcc/JS-Sorting-Algorithm
https://zh.wikipedia.org/wiki/%E6%8E%92%E5%BA%8F%E7%AE%97%E6%B3%95