排序之計數排序,基數排序和桶排序

一.計數排序

計數排序不是比較排序。因爲用來計數的數組C的長度取決於待排序數組中數據的範圍(等於待排序數組的最大值與最小值的差加上1),這使得計數排序對於數據範圍很大的數組,須要大量時間和內存。例如:計數排序是用來排序0到100之間的數字的最好的算法,可是它不適合按字母順序排序人名。可是,計數排序能夠用在基數排序中的算法來排序數據範圍很大的數組。python

算法的步驟以下:git

1)找出待排序的數組中最大和最小的元素
2)統計數組中每一個值爲i的元素出現的次數,存入數組C的第i項
3)對全部的計數累加(從C中的第一個元素開始,每一項和前一項相加)
4)反向填充目標數組:將每一個元素i放在新數組的第C(i)項,每放一個元素就將C(i)減去1
用[-2,5,-3,0,-3,4,3,2,4]這組數來模擬一下過程:算法

1)這組數中最大的是5,最小的是-3,因此用來計數的數組C的長度是9,數組

2)數組C中每一個數出現的次數是2, 1, 0, 1, 0, 1, 1, 2, 1 新的數組C爲[2, 1, 0, 1, 0, 1, 1, 2, 1]app

3)記錄每一個元素的位置,其元素的最終位置都是在前一個元素的後面,因此將其中每一個元素的次數更新爲加上前一個元素的次數和,好比-3有兩個站的位置就是2,-2有一個,位置就是2+1=3,-1沒有,位置依然是3,0一個,位置是3+1=4,最終各元素的位置爲:[2, 3, 3, 4, 4, 5, 6, 8, 9]ide

4)反向填充目標數組spa

 步驟如圖:code

 

 

def countingSort(arr):  # the elements in the array are all integers maximum, minimum = max(arr), min(arr) countArr = [0] * (maximum - minimum + 1) #用0初始化countArr for i in arr: # record the number of times of every element in the array countArr[i - minimum] += 1 print('--------記錄每一個元素出現的次數',countArr) for i in range(1, len(countArr)): # calculate the position of every element countArr[i] += countArr[i-1]  #該元素的位置是這個元素前一個元素的位置+該元素的個數 print('---------記錄每一個元素的位置',countArr) targetArr = [None] * len(arr) #申請一個用來放排序結果的列表 for i in range(len(arr)-1, -1, -1): # reverse-order traversal is for the stability countIndex = arr[i] - minimum targetArr[countArr[countIndex] - 1] = arr[i] countArr[countIndex] -= 1
    return targetArr a = [-2,5,-3,0,-3,4,3,2,4] print(countingSort(a))
計數排序

 

二.基數排序blog

基數排序是一種非比較型整數排序算法,其原理是將整數按位數切割成不一樣的數字,而後按每一個位數分別比較。因爲整數也能夠表達字符串(好比名字或日期)和特定格式的浮點數,因此基數排序也不是隻能使用於整數。基數排序的方式能夠採用 LSD(Least significant digital)或 MSD(Most significant digital),LSD 的排序方式由鍵值的最右邊開始,而 MSD 則相反,由鍵值的最左邊開始。排序

算法基本步驟:

1)將全部待比較數值(正整數)統一爲一樣的數位長度,數位較短的數前面補零。

2)從最低位開始,依次進行一次排序。

3)從最低位排序一直到最高位排序完成之後,數列就變成一個有序序列。 

以[3,67,983,234,56,32,358,4,1]爲例來模擬過程:

 

 

 其中的每一輪排序用的是計數排序的方法

 

# !/usr/bin/python
def RadixSort(input_list): def MaxBit(input_list): # 得到最大數的位數的值
        max_data = max(input_list) bits_num = 0 while max_data: bits_num += 1 max_data //= 10  #整除結果
        return bits_num def digit(num, d): # 取數num上的第d(從右往左第d位)位數字
        p = 1
        while d > 1: d -= 1 p *= 10
        return num // p % 10

    if len(input_list) == 0: return [] sorted_list = input_list length = len(sorted_list) bucket = [0] * length for d in range(1, MaxBit(sorted_list) + 1): count = [0] * 10

        for i in range(0, length): count[digit(sorted_list[i], d)] += 1
        # count[i]表示針對全部數的第d位數,小於等於i的數的個數是count[i]
        for i in range(1, 10): count[i] += count[i - 1]   #這裏和基數排序很像
        # 針對全部數,按第d位數從小到大放入bucket裏
        for i in range(0, length)[::-1]: k = digit(sorted_list[i], d) bucket[count[k] - 1] = sorted_list[i] count[k] -= 1
        for i in range(0, length): sorted_list[i] = bucket[i] print("%dth" % d) print(sorted_list) return sorted_list if __name__ == '__main__': input_list = [3,67,983,234,56,32,358,4,1] print('input_list') print(input_list) sorted_list = RadixSort(input_list) print('sorted_list') print(sorted_list)
基數排序

 

三.桶排序

桶排序是一種基於計數的排序算法,工做的原理是將數據分到有限數量的桶子裏,而後每一個桶再分別排序(有可能再使用別的排序算法或是以遞迴方式繼續使用桶排序進行排序)。

固然桶排序更是對計數排序的改進,計數排序申請的額外空間跨度從最小元素值到最大元素值,若待排序集合中元素不是依次遞增的,則必然有空間浪費狀況。桶排序則是弱化了這種浪費狀況,將最小值到最大值之間的每個位置申請空間,更新爲最小值到最大值之間每個固定區域申請空間,儘可能減小了元素值大小不連續狀況下的空間浪費狀況。

算法步驟

1)根據待排序集合中最大元素和最小元素的差值範圍和映射規則,肯定申請的桶個數;

2)遍歷待排序集合,將每個元素移動到對應的桶中;

3)對每個桶中元素進行排序,並移動到已排序集合中。

以[23,45,6,7,9,12,3,10]爲例來模擬過程:

 

def bucket_sort(array): maxer, miner = max(array), min(array) gap = (maxer - miner) // len(array) + 1
    #桶的數量
    bucket_num =  (maxer - miner) // gap + 1
    print('桶的數量',bucket_num) # 注意這裏要+1
    bucket_size = (maxer - miner + 1) / bucket_num print('桶的大小',bucket_size) bucket = [[] for _ in range(bucket_num)]   #初始化桶
    # print(bucket)
    #將數放入桶中
    for num in array: bucket[int((num - miner) / bucket_size)].append(num) print('將數按照映射關係放到桶中',bucket) result = [] #對每一個桶內的數調用排序,將拍好序的數組連接起來就能獲得最後結果
    for i in range(len(bucket)): result += sorted(bucket[i]) print('第 %i 個桶的排序結果 '%i,sorted(bucket[i])) print('最終結果:',result) arr = [23,45,6,7,9,12,3,10] bucket_sort(arr) ##################運行結果###############
 桶的數量 8 桶的大小 5.375 將數按照映射關係放到桶中 [[6, 7, 3], [9, 12, 10], [], [23], [], [], [], [45]] 第 0 個桶的排序結果 [3, 6, 7] 第 1 個桶的排序結果  [9, 10, 12] 第 2 個桶的排序結果 [] 第 3 個桶的排序結果  [23] 第 4 個桶的排序結果 [] 第 5 個桶的排序結果 [] 第 6 個桶的排序結果 [] 第 7 個桶的排序結果  [45] 最終結果: [3, 6, 7, 9, 10, 12, 23, 45]

 

總結:

 

 

計數排序、基數排序、桶排序都屬於非比較排序。非比較排序是經過肯定每一個元素以前,應該有多少個元素來排序。針對數組arr,計算arr[i]以前有多少個元素,則惟一肯定了arr[i]在排序後數組中的位置。

計數排序須要佔用大量空間,它僅適用於數據比較集中的狀況。好比 [0~100],[10000~19999] 這樣的數據。

桶排序可用於最大最小值相差較大的數據狀況,好比[9012,19702,39867,68957,83556,102456]。
但桶排序要求數據的分佈必須均勻,不然可能致使數據都集中到一個桶中。好比[104,150,123,132,20000], 這種數據會致使前4個數都集中到同一個桶中。致使桶排序失效。

基數排序通常用於長度相同的元素組成的數組。基數排序能夠看作是進行多趟桶排序。每一個有效數字都在0-9之間,很適合桶排序,建10個桶很方便

相關文章
相關標籤/搜索