一、计数排序算法
计数排序原理
计数排序的核心思想是通过统计数组中每个数值出现的次数来确定每个数值的最终位置。它适用于整数排序,尤其是当整数的范围不是特别大时。
计数排序步骤
-
确定数值范围:首先需要知道数组中的最大值和最小值,这有助于确定计数数组的大小。如果数据范围已知,则可以直接使用该范围。
-
创建计数数组:创建一个大小等于数值范围的数组,通常称为
count[]
。这个数组的每一个位置对应着一个可能的数值,初始值设置为0。 -
统计每个数值出现的次数:遍历待排序数组,对于数组中的每一个元素,在
count[]
中相应位置的计数加1。这样count[]
就记录了每个数值出现的次数。 -
累计计数:遍历
count[]
,将前一个元素的值累加到当前元素上,得到的结果就是该数值在排序后数组中的正确位置。这个步骤是通过累加count[]
中的值来完成的。 -
构建输出数组:创建一个新的数组
output[]
用于存放排序后的结果。从待排序数组中再次遍历,根据count[]
中记录的位置,将数值放入output[]
中正确的索引位置。注意这里是从后往前遍历待排序数组,以保持稳定性(即相同的元素保持原有的顺序)。 -
复制排序结果:最后将
output[]
中的数据复制回原数组。
假设我们有一个待排序的数组 arr[] = {4, 2, 2, 8, 3, 3, 1}
,数值范围为 [1, 8]。
-
创建计数数组:创建一个大小为 8 的数组
count[]
,初始化为[0, 0, 0, 0, 0, 0, 0, 0]
。 -
统计每个数值出现的次数:遍历
arr[]
并更新count[]
。例如,当遇到第一个元素 4 时,count[4]
加 1;遇到第二个元素 2 时,count[2]
加 1,以此类推。最后count[]
变为[0, 1, 2, 2, 1, 0, 0, 1]
。 -
累计计数:遍历
count[]
并累加值。例如,count[1]
不变;count[2]
变为1 + 2 = 3
;count[3]
变为3 + 2 = 5
;以此类推。最后count[]
变为[0, 1, 3, 5, 6, 6, 6, 7]
。 -
构建输出数组:创建一个新的数组
output[]
,并从后往前遍历arr[]
。例如,最后一个元素 1 应该放在output[1]
的位置,即output[count[1] - 1] = 1
,然后count[1]
减 1。重复此过程直到所有元素被放置完毕。 -
复制排序结果:最后将
output[]
的内容复制回原数组arr[]
。
- 时间复杂度:O(n + k),其中 n 是数组长度,k 是数值范围。
- 空间复杂度:O(k),需要额外的空间来存储计数数组。
- 稳定性:计数排序是稳定的排序算法,相同的元素会保持原有的相对顺序。
- 适用性:适用于整数排序,特别是当数值范围不是特别大时。
二、代码
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
// 函数声明
int* create_and_generate_random_array(int size, int range);
void print_array(const int *array, int size);
void counting_sort(int *array, int size, int range);
int main() {
int size = 10; // 数组大小
int range = 100; // 数据范围
// 创建并填充随机数组
int *array = create_and_generate_random_array(size, range);
if (array == NULL) {
printf("Memory allocation failed\n");
return 1;
}
// 打印原始数组
printf("Original array:\n");
print_array(array, size);
// 进行计数排序
counting_sort(array, size, range);
// 打印排序后的数组
printf("Sorted array:\n");
print_array(array, size);
// 释放内存
free(array);
return 0;
}
// 创建并生成随机数组
int* create_and_generate_random_array(int size, int range) {
int *array = (int *)malloc(sizeof(int) * size);
if (array == NULL) {
return NULL;
}
srand(time(NULL)); // 设置随机数种子
for (int i = 0; i < size; i++) {
array[i] = rand() % range; // 生成0到range-1之间的随机数
}
return array;
}
// 打印数组
void print_array(const int *array, int size) {
for (int i = 0; i < size; i++) {
printf("%d ", array[i]);
}
printf("\n");
}
// 计数排序
void counting_sort(int *array, int size, int range) {
int *count = (int *)malloc((range + 1) * sizeof(int));
int *output = (int *)malloc(size * sizeof(int));
// 初始化计数数组
for (int i = 0; i <= range; ++i) {
count[i] = 0;
}
// 统计每个数值出现的次数
for (int i = 0; i < size; ++i) {
count[array[i]]++;
}
// 累积计数
for (int i = 1; i <= range; ++i) {
count[i] += count[i - 1];
}
// 构建输出数组
for (int i = size - 1; i >= 0; --i) {
output[count[array[i]] - 1] = array[i];
count[array[i]]--;
}
// 复制排序结果到原数组
for (int i = 0; i < size; ++i) {
array[i] = output[i];
}
// 释放临时数组
free(count);
free(output);
}