计数排序是用空间换取时间的算法,其假设n个输入元素中的每一个都在0到k区间内的一个整数,其中k为某个整数。当k=O(n)时,排序的运行时间为Theta(n)。
基本思想:对每一个输入元素x,确定小于x的元素个数。利用这一信息,就可以直接把x放到它在输出数组中的位置上了。
输入数组为A[1..n]
辅助数组:B[1..n]存放排序的输出,C[1..k]提供临时存储空间(存放A中数组元素值的出现次数)。
伪代码:
COUNTING-SORT(A,B,k)
let C[0..k] be a new array
for i = 0 to k //后面需要使用数组C来存储A中各元素的出现次数,所以需要清零操作
C[i] = 0
for j = 1 to A.length
C[A[j]] = C[A[j]] + 1 //统计A中各元素的出现次数存储在C中,C中下标为A中的元素值,与其对应的数组元素为出现次数,如C[1] = 0,即为“1”在A中的出现次数为0
for i = 1 to k
C[i] = C[i] + C[i-1] //计算A中小于等于i的一共有多少个,方便此后将i放在数组B中正确的位置上
for j = A.length downto 1
B[C[A[j]]] = A[j] //使用A中元素A[j]的出现次数作为B中的下标,把每个元素放在B中适当的位置
C[A[j]] = C[A[j]] -1 //在B中放入一个元素,与其对应C中出现的次数-1。这样,当遇到下一个等于A[j]的输入元素时,该元素可以被直接放到B中A[j]的前一位置上
1 2 3 4 5 6 7 8 0 1 2 3 4 5 1 2 3 4 5 6 7 8
A[2 5 3 0 2 3 0 3] C[2 2 4 7 7 8] B[ 3 ]
0 1 2 3 4 5 0 1 2 3 4 5
C[2 0 2 3 0 1] C[2 2 4 6 7 8]
(a) (b) (c)
1 2 3 4 5 6 7 8 1 2 3 4 5 6 7 8 1 2 3 4 5 6 7 8
B[ 0 3 ] B[ 0 3 3 ] B[0 0 2 2 3 3 3 5]
0 1 2 3 4 5 0 1 2 3 4 5
C[1 2 4 6 7 8] C[1 2 4 5 7 8]
(d) (e) (f)
步骤(a)为伪代码中第二个for循环,统计A中各元素的出现次数
步骤(b)为伪代码中第三个for循环,统计A中小于等于i元素的数量
步骤(c)(d)(e)为伪代码中第四个for循环,进行排序
步骤(f)为排序结果。
计数排序为稳定的排序算法,通常被用做基数排序算法的一个子过程,为了使基数排序能够正确运行,计数排序必须是稳定的。
计数排序Demo:
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#define LENGTH 8
void counting_sort(int *A,int *B,int k)
{
int *C=(int *)malloc(k*sizeof(int));
for(int i = 0;i < k;i++)
C[i] = 0;
for(int i = 0;i < LENGTH;i++)
C[A[i]]++;
for(int i = 1;i < k;i++)//i应从1开始,若从0开始,则C[i-1]越界
C[i] = C[i] + C[i-1];
for(int i = LENGTH-1;i >= 0;i--)
{
B[C[A[i]]-1] = A[i];//B数组的下标从0开始,C[A[i]]中的元素数量的总和从1开始计数,所以存放到B中时需要减1,才能放到正确的位置上 想象当A中只有一个元素,C[A[i]] = 1,要存放进B中,就是B[C[A[i]]-1]
C[A[i]]--;
}
free(C);
C = NULL;
}
int main()
{
int A[LENGTH],B[LENGTH];
for(int i = 0;i < LENGTH;i++)
std::cin >> A[i];
//scanf("%d",A[i]);
counting_sort(A,B,6);//k决定了数组中数的取值范围 0<=x<=k
for(int i = 0;i < LENGTH;i++)
printf("%d ",B[i]);
printf("\n");
system("pause");
return 0;
}
算法描述参照 算法总结系列之五: 基数排序(Radix Sort) -- Jeffrey Sun
radix_sort Demo:
#include <iostream>
#include <stdio.h>
#include <math.h>
using namespace std;
#define LENGTH 4
#define NUM_LEN 3 //最大数位长度
void radix_sort(int *A,int d)
{
int sort_num = 0;
int B[LENGTH];
for(int j = 1;j <= d;j++)//d是总位数,位数由低到高进行排序
{
//计数排序部分
int p = (int)pow(10,j-1);//用于A[i]/p%10 获取整个数组第j位的值,本轮是按照数组的第j位进行排序
int C[10];//每一位的取值共有0-9十个情况
for(int i = 0;i < 10;i++)
C[i] = 0;
for(int i = 0;i < LENGTH;i++)
C[A[i]/p%10]++;
for(int i = 1;i < 10;i++)//i应从1开始
C[i] = C[i] + C[i-1];
for(int i = LENGTH-1;i >= 0;i--)
{
B[C[ A[i]/p%10 ]-1] = A[i];//B数组的下标从0开始,C[A[i]]中的元素数量的总和从1开始计数,所以存放到B中时需要减1,才能放到正确的位置上 想象当A中只有一个元素,C[A[i]] = 1,要存放进B中,就是B[C[A[i]]-1]
C[A[i]/p%10]--;
}
//end
for(int i = 0;i < LENGTH;i++)//将本轮排序结果赋值回原数组
A[i] = B[i];
}
}
int main()
{
int A[LENGTH];
for(int i = 0;i < LENGTH;i++)
cin >> A[i];
radix_sort(A,NUM_LEN);
for(int i = 0;i < LENGTH;i++)
cout << A[i] <<" ";
cout<<endl;
system("pause");
return 0;
}