引言
排序算法c++实现系列第8弹——计数排序。
计数排序是理解起来相对简单的一个排序算法,
计数排序
计数排序(Counting Sort)是一种非比较型的排序算法,它的基本思想是统计待排序数组中每个元素的出现次数,然后根据统计信息将元素放置到正确的位置上,从而实现排序。计数排序适用于排序范围不大的非负整数数组,并且可以在线性时间内完成排序。
算法步骤
-
确定数据范围:寻找数据中的最大值和最小值。
-
统计频次:遍历待排序数组,统计每个元素出现的次数,并将统计结果存储在一个辅助数组(计数数组)中。
-
累加频次:对计数数组进行顺序累加,方便后续排序操作中得到原数组中每个数的下标位置。
-
排序:遍历待排序数组,根据元素的值和计数数组的统计信息,将元素放置到正确的位置上。
-
输出:将排序后的数组输出,排序完成。
算法的核心步骤如上,仅看步骤可能还是难以理解,可以联系着代码一起看。这边也推荐一个我个人觉得会让算法不那么抽象的学习方法:当在学习某一算法时,可以先去b站搜该算法的简单动图演示,大概了解步骤后,再来看以上的步骤总结和代码实现,事半功倍。
这里借助一个实实在在的例子,向大家演示计数排序算法:假设有 a[] = {1,2,3,5,6,7,3};
-
寻找最大值max=7;最小值min=1。
-
创建一个新数组b作为计数数组,将a遍历统计每个数据出现的频次。
for (int i = 0; i < len; i++) {
a[arr[i] - min]++; //arr[i] - min即将输入的数据值转化为的键
}
// 如 a[arr[0]-min] = a[1-1] => a[0] = 1;
// a[arr[1]-min] = a[2-1] => a[1] = 1;
特点
-
计数排序是一种稳定的排序算法,相同元素的相对位置在排序后保持不变。
-
计数排序的时间复杂度为O(n+k),其中 n 为待排序数组的长度,k为待排序数组中的最大值与最小值之差加一。
-
计数排序适用于待排序数组元素范围不大的情况,如果待排序数组范围较大,计数数组的空间消耗会增加。
代码
#include<bits/stdc++.h>
using namespace std;
int main() {
int max = INT_MIN, min = INT_MAX;
int arr[] = {61, 17, 29, 22, 34, 60, 72, 21, 50, 1, 62};
int len = (int) sizeof(arr) / sizeof(*arr);
// 寻找数组的max和min,以便建立计数数组
for (int i = 0; i < len; i++) {
max = max < arr[i] ? arr[i] : max;
min = min > arr[i] ? arr[i] : min;
}
// printf("max:%d,min:%d\n", max, min);
int d = max - min + 1; // 计数数组长度
int a[d] = {0}; // 计数数组
for (int i = 0; i < len; i++) {
a[arr[i] - min]++;
}
for (int i = 1; i < d; i++) {
a[i] += a[i - 1]; // 对次数累加,方便后续得到每个数的index
}
int b[len] = {0}; // b[]存放排序后的数组
for (int i = len - 1; i >= 0; i--) {// 从后往前排序-->稳定排序算法
int index = a[arr[i] - min] - 1; // 遍历a[]中每一个数,确定其index
b[index] = arr[i];
a[arr[i] - min]--;
}
for (int i = 0; i < len; i++) {
arr[i] = b[i];
printf("%d ", arr[i]);
}
return 0;
}
运行结果展示
其他排序算法
经典排序算法之堆排序详解|c++代码实现|什么是堆排序|如何代码实现堆排序-CSDN博客
经典排序算法之快速排序|c++代码实现|什么是快速排序|如何代码实现快速排序-CSDN博客
经典排序算法之归并排序|递归和迭代法代码均提供|c++代码实现|什么是归并排序|如何代码实现-CSDN博客
经典排序算法之希尔排序|c++代码实现||什么是希尔排序|如何代码实现-CSDN博客
经典排序算法之插入排序|c++实现|什么是插入排序|如何代码实现-CSDN博客
排序算法之选择排序|c++实现-CSDN博客
经典排序算法之冒泡排序|c++代码实现-CSDN博客