计数排序(Counting Sort)是一种非比较排序算法,该算法的核心思想就是将输入的数值转化为键存储在一个数组中,然后确定每个数值在输入序列中的出现次数,最后根据每个数值的出现次数,将输入的序列排列成有序序列。
计数排序的特点是:最优时间复杂度O(n),最坏时间复杂度O(n),平均时间复杂度O(n+k),空间复杂度O(n+k),稳定排序。
基本思想
计数排序的基本思想是:对于给定的输入序列中的每一个元素x,确定该序列中值小于x的元素的个数。有了这个信息,就可以将x直接存放到输出序列的正确位置上了。
算法步骤
- 统计数组中每个值出现的次数,存放到计数数组中。
- 对计数数组进行累加,这样计数数组中的第i位就存储的是小于等于i的数的个数。
- 新建一个临时数组,从后往前扫描原数组,将每个元素放到临时数组中的正确位置上,并依此修改计数数组中的数值,以保证同样数值的元素放置时是从后往前放。
- 将新数组复制到原数组中,排序完成。
代码示例
Python 代码示例:
def countingSort(arr):
count = [0] * (max(arr) + 1) # 初始化计数数组
n = len(arr)
result = [0] * n # 初始化输出数组
for i in range(n):
count[arr[i]] += 1 # 统计每个值出现的次数
for i in range(1, len(count)):
count[i] += count[i-1] # 计算小于等于i的数的个数
for i in range(n-1, -1, -1):
result[count[arr[i]] - 1] = arr[i] # 将arr[i]放到输出数组中的正确位置上
count[arr[i]] -= 1 # 修改计数数组中的数值
for i in range(n):
arr[i] = result[i] # 将新数组复制到原数组中
return arr
Java 代码示例:
public static void countingSort(int[] arr) {
int max = Arrays.stream(arr).max().getAsInt(); // 获取数组中的最大值
int[] count = new int[max+1]; // 初始化计数数组
int n = arr.length;
int[] result = new int[n]; // 初始化输出数组
for (int i = 0; i < n; i++) {
count[arr[i]]++; // 统计每个值出现的次数
}
for (int i = 1; i < count.length; i++) {
count[i] = count[i-1] + count[i]; // 计算小于等于i的数的个数
}
for (int i = n-1; i >= 0; i--) {
result[count[arr[i]]-1] = arr[i]; // 将arr[i]放到输出数组中的正确位置上
count[arr[i]]--; // 修改计数数组中的数值
}
System.arraycopy(result, 0, arr, 0, n); // 将新数组复制到原数组中
}
使用示例
计数排序适用于一定范围内的整数序列排序,对于可以使用整数类型存储的数据类型(如字符串),可以使用ASCII码进行转换。以下是两个使用示例。
示例一:对于给定的整数数组进行排序
arr = [3, 7, 10, 2, 9, 4, 12, 6]
countingSort(arr)
print(arr)
# 结果:[2, 3, 4, 6, 7, 9, 10, 12]
示例二:对于给定的字符串数组进行排序
arr = ['def', 'abc', 'jkl', 'ghi', 'mno']
ascii_arr = [sum([ord(c) for c in word]) for word in arr] # 将字符串转换为ASCII码
countingSort(ascii_arr)
sorted_arr = [chr(i) for i in ascii_arr] # 将ASCII码转换为字符串
print(sorted_arr)
# 结果:['abc', 'def', 'ghi', 'jkl', 'mno']