计数排序不是比较排序。由于用来计数的数组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))