计数排序不是比较排序。由于用来计数的数组C的长度取决于待排序数组中数据的范围(等于待排序数组的最大值与最小值的差加上1),这使得计数排序对于数据范围很大的数组,需要大量时间和内存。例如:计数排序是用来排序0到100之间的数字的最好的算法,但是它不适合按字母顺序排序人名。但是,计数排序可以用在基数排序中的算法来排序数据范围很大的数组。

算法的步骤如下:

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]

3)记录每个元素的位置,其元素的最终位置都是在前一个元素的后面,所以将其中每个元素的次数更新为加上前一个元素的次数和,比如-3有两个站的位置就是2,-2有一个,位置就是2+1=3,-1没有,位置依然是3,0一个,位置是3+1=4,最终各元素的位置为:[2, 3, 3, 4, 4, 5, 6, 8, 9]

4)反向填充目标数组

 步骤如图:

排序之计数排序,基数排序和桶排序

 

 

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))
计数排序

相关文章: