在本教程中,您将学习计数排序的工作原理。此外,您还将找到C语言的示例。
计数排序是一种排序算法,它通过计算数组中每个唯一元素的出现次数来对数组的元素进行排序。计数存储在辅助数组中,并通过将计数映射为辅助数组的索引来完成排序。
计数排序如何工作?
- 从给定数组中找出最大元素(设为max)。
- 初始化一个数组,该数组长度为 max+1,所有元素为0。此数组用于存储给定数组中元素的计数。
- 将每个元素的计数存储在计数数组中各自的索引处。
例如:如果元素3的计数为2,则2存储在计数数组的第3个位置。如果给定数组中不存在元素“5”,则将0存储在计数数组第5位。
- 存储计数数组元素的累积和。它有助于将元素放入排序数组的正确索引中。
- 在计数数组中查找原始数组的每个元素的索引,得到累计计数。将元素放置在如下图所示计算的索引处。
- 将每个元素放置在正确的位置后,将其计数减少一。
整个推导过程我简单画了一下,如下图所示(实在懒得用visio了^_^)。
计数排序算法伪代码
countingSort(array, size)
max <- find largest element in array
initialize count array with all zeros
for j <- 0 to size
find the total count of each unique element and
store the count at jth index in count array
for i <- 1 to max
find the cumulative sum and store it in count array itself
for j <- size down to 1
restore the elements to array
decrease count of each element restored by 1
C示例
// Counting sort in C programming
#include <stdio.h>
void countingSort(int array[], int size) {
int output[10];
// Find the largest element of the array
int max = array[0];
for (int i = 1; i < size; i++) {
if (array[i] > max)
max = array[i];
}
// The size of count must be at least (max+1) but
// we cannot declare it as int count(max+1) in C as
// it does not support dynamic memory allocation.
// So, its size is provided statically.
int count[10];
// Initialize count array with all zeros.
for (int i = 0; i <= max; ++i) {
count[i] = 0;
}
// Store the count of each element
for (int i = 0; i < size; i++) {
count[array[i]]++;
}
// Store the cummulative count of each array
for (int i = 1; i <= max; i++) {
count[i] += count[i - 1];
}
// Find the index of each element of the original array in count array, and
// place the elements in output array
for (int i = size - 1; i >= 0; i--) {
output[count[array[i]] - 1] = array[i];
count[array[i]]--;
}
// Copy the sorted elements into original array
for (int i = 0; i < size; i++) {
array[i] = output[i];
}
}
// Function to print an array
void printArray(int array[], int size) {
for (int i = 0; i < size; ++i) {
printf("%d ", array[i]);
}
printf("\n");
}
// Driver code
int main() {
int array[] = {
4, 2, 2, 8, 3, 3, 1};
int n = sizeof(array) / sizeof(array[0]);
countingSort(array, n);
printArray(array, n);
}
复杂度
时间复杂度
有四个主要循环(可以在函数外部找到最大值)。
循环 | 计数时间 |
---|---|
第一次 | O(max) |
第二次 | O(size) |
第三次 | O(max) |
第四次 | O(size) |
总体体复杂度=O(max)+O(size)+O(max)+O(size) = O(max+size)
- 最坏情况的复杂度: O(n+k)
- 最佳情况的复杂度: O(n+k)
- 平均情况的复杂度: O(n+k)
在上述所有情况下,复杂度是相同的,因为无论元素如何放置在数组中,算法都要计算n+k次。
任何元素之间都没有比较,因此它比基于比较的排序技术更好。但是,如果整数非常大,这是不好的,因为应该创建该大小的数组。
空间复杂度
计数排序的空间复杂度为O(max)。元素的范围越大,空间的复杂度就越大。
计数排序的应用
- 有多个较小的整数
- 必须使用线性复杂度的场景
参考文档
[1]Parewa Labs Pvt. Ltd.Counting Sort Algorithm[EB/OL].https://www.programiz.com/dsa/counting-sort,2020-01-01.