假設,有20個隨機整數,取值範圍是0到10,須要對其排序。可能第一反應是使用快速排序啊,快排的時間複雜度是O(nlog n)!可是,可不能夠比O(nlog n)更快呢?這就是這篇文章要介紹的計數排序(從名字上來看,就是計算數字出現頻次的排序方法,很是的見名知意)。算法
由於取值範圍是0到10(整數的值在0,1,2,3,4,5,6,7,8,9,10裏),共有11個數值,因此須要11個坑,咱們定義一個長度是12的數組array,每一個元素的初始值是0,而後對20個隨機整數進行循環,對應的元素值加1。最後,輸出array,就是排好序的。數組
好比有20個整數,分別是 9,2,8,5,1,8,6,9,5,8,1,5,8,3,4,7,0,6,2,10優化
初始化數組arraycode
數組下標 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
頻率 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
要排序的隨機整數,第一個值是9,那數組下標是9的分佈值加1,因此array變成排序
數組下標 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
頻率 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 |
第二個值是2,數組下標是2的分佈值加1it
數組下標 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
頻率 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 |
後面的以此類推。最終輸出array,元素的值是幾,就輸出幾回。這個數組顯然是有序的了。 table
數組下標 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
頻率 | 1 | 2 | 2 | 1 | 1 | 3 | 2 | 1 | 4 | 2 | 1 |
代碼以下class
def sort(array): # 1.獲取數組內的最大值和最小值,來肯定數組的size max = array[0] min = array[0] for i in array: if i > max: max = i if i < min: min = i # 2.定義定長數組,數組的元素初始值是0(這裏偷懶使用了列表生成式) sort_array = [0 for i in range(max - min + 1)] # 3.計數 for i in array: sort_array[i - min] = sort_array[i - min] + 1 # 4.得到排序後的數組 sortArray = [0 for i in array] index = 0 for i, value in enumerate(countArray): for j in range(1, value + 1): sortArray[index] = i + min index = index + 1 return sortArray if __name__ == "__main__": array = [9, 2, 8, 5, 1, 8, 6, 9, 5, 8, 1, 5, 8, 3, 4, 7, 0, 6, 2, 10] sort_array = sort(array) print(sort_array)
下面是輸出結果循環
[0, 1, 1, 2, 2, 3, 4, 5, 5, 5, 6, 6, 7, 8, 8, 8, 8, 9, 9, 10] Process finished with exit code 0
從代碼實現來看,也不復雜,甚至很簡單。遍歷
上面的算法,由於有一個雙重fou循環,還能夠在優化下。
假設考試是十分制的,共有20個同窗,同窗的考試成績是上面的那20個數(9, 2, 8, 5, 1, 8, 6, 9, 5, 8, 1, 5, 8, 3, 4, 7, 0, 6, 2, 10),考試得到9分的有兩個同窗,那到底誰是第2、誰是第三呢?
上面的表格,須要升級一下,頻率一欄,須要變成「分佈值」了,它的值是上一格的值和自身的值之和
數組下標 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
分佈值 | 1 | 3(1+2) | 5(3+2) | 6(5+1) | 7(6+1) | 10(7+3) | 12(10+2) | 13(12+1) | 17(13+4) | 19(17+2) | 20(19+1) |
而後對分佈值數組輸出,第一個是下標10的,遍歷以後分佈值表格的下標10的分佈值就減1,它是第一名(總人數-分佈值+1)
數組下標 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
分佈值 | 1 | 3 | 5 | 6 | 7 | 10 | 12 | 13 | 17 | 19 | 19(20-1) |
假如得到9分的是張三和李四,遍歷張三以後,表格下標9的值減1,它是第二名(2 = 20-19 +1)
數組下標 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
分佈值 | 1 | 3 | 5 | 6 | 7 | 10 | 12 | 13 | 17 | 18(19-1) | 19 |
李四是第三名(3 = 20 -18 + 1)
數組下標 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
分佈值 | 1 | 3 | 5 | 6 | 7 | 10 | 12 | 13 | 17 | 17(18-1) | 19 |
這樣的話,相同分數的同窗,就分出分數排名了。
def sort2(array): # 1.獲取數組內的最大值和最小值,來肯定數組的size max = array[0] min = array[0] for i in array: if i > max: max = i if i < min: min = i # 2.定義定長數組,數組的元素初始值是0(這裏偷懶使用了列表生成式) countArray = [0 for i in range(max - min + 1)] # 3.計數 for i in array: countArray[i - min] = countArray[i - min] + 1 # 4.計數的數組變形 sum = 0 for i,value in enumerate(countArray): sum = sum + value countArray[i] = sum # 5.得到排序後的數組 sortArray = [0 for i in array] for i in array: sortArray[countArray[i - min] - 1] = i countArray[i - min] = countArray[i - min] - 1 return sortArray if __name__ == "__main__": array = [9, 2, 8, 5, 1, 8, 6, 9, 5, 8, 1, 5, 8, 3, 4, 7, 0, 6, 2, 10] sort_array = sort2(array) print(sort_array)
假設array元素有N個,取值範圍是M。
時間複雜度:3N(步驟一、步驟三、步驟5) + M(步驟4),去掉係數,時間複雜度是O(N+M)
空間複雜度:只考慮統計數組,那就是M