计数排序,基数排序
计数排序
基本思想
计数排序又称为鸽巢原理,是对哈希直接定址法的变形应用。
操作步骤:
统计相同元素出现次数
根据统计的结果将序列回收到原来的序列中
思维导图
特性总结
-
计数排序在数据范围集中时,效率很高,但是适用范围及场景有限。
-
时间复杂度:O(MAX(N,range)),range表示范围(Max函数:取两者中大的那个数)
-
空间复杂度:O(range),range表示范围
-
稳定性:稳定
代码实现
//计数排序
// 没有两数之间比较大小的排序
//只能排序全是正数或全是负数的序列
//对同时含正数和负数的序列不适用
void countsort(int* a, int n)
{
//找出待排序数组中最大值和最小值
//用于确定计数排序数组的大小
int max = a[0], min = a[0];
for (int i = 0; i < n; i++)
{
if (a[i]>max)
{
max = a[i];
}
if (a[i]<min)
{
min = a[i];
}
}
//range就是计数排序数组的范围
int range = max - min + 1;
int* tmp = (int*)malloc(sizeof(int) * range);
assert(tmp);
//将tmp数组初始化为0
memset(tmp,0,sizeof(int)*range);
//计数
for (int i = 0; i < n; i++)
{
tmp[a[i] - min]++;
}
//排序
int j = 0;
for (int i = 0; i < range; i++)
{
while (tmp[i]--)
{
a[j++] = i+min;
}
}
free(tmp);
tmp = NULL;
}
基数排序
基本思想
将待排序的元素按照每个位上的数字来进行排序,从低位到高位依次进行排序,直到排序完成为止。
具体来说,它将所有元素按照个位数进行排序,然后按照十位数进行排序,以此类推,直到按照最高位排序完成为止。
思维导图
特性总结
- 时间复杂度:基数排序的时间复杂度为O(d(N+k)),其中d是元素的位数,N是元素个数,k是基数。当d较小,k不是很大时,基数排序的时间复杂度可以达到线性级别,比如在对电话号码进行排序时。
- 空间复杂度:O(k+n),N是元素个数,k是基数
- 稳定性:稳定
代码实现
int getkey(int value, int k)
{
//k表示轮数
//第一轮取个位,循环只会进行一次
//第二轮取十位,循环会进行两次
//第三轮取百位,循环会进行三次
int key = 0;
while (k>=0)
{
key = value % 10;
value /= 10;
k--;
}
return key;
}
//基数排序
void radixsort(int*a,int left,int right)
{
//由基数排序的思维导图可知
//基数排序在回收数据的时候,符合先进先出,可用队列来存放
//基数为0--9 共10个
//创建一个存放10个队列的数组,并初始化
PQ Q[10];
for (int i = 0; i < 10; i++)
{
Queueinit(&Q[i]);
}
//i<3 由排序数据可知,最高位是百位,要排3轮
//i=0 时 排第一轮,个位排序
//i=1 时 排第二轮,十位排序
//i=2 时 排第三轮,百位排序
for (int i = 0; i < 3; i++)
{
//分发数据
//设排的是第一轮
//getkey函数就是获取每个数的个位
//然后根据每个数个位的不同,分别放到基数为0--9的队列中去
for (int j = left; j <= right; j++)
{
int key = getkey(a[j], i);
Queuepush(&Q[key], a[j]);
}
//回收数据
//设回收的是第一轮数据
//根据基数0--9 依次回收(出队列)
//先进先出
int k = 0;
for (int x = 0; x < 10; x++)
{
//当回收的那个队列为空时,表示以及回收完了
while (Queueempty(&Q[x]))
{
a[k++] = Queuefront(&Q[x]);
Queuepop(&Q[x]);
}
}
}
}
总结
计数排序是非比较排序,需要移动数据。基数排序不需要比较和移动数据,而是通过分发和回收数据来使数据有序。两种排序都是用空间换时间,两者都有空间上的损耗,基数排序空间复杂度:O(k+n),N是元素个数,k是基数。计数排序空间复杂度:O(range),range表示范围。基数排序的时间复杂度:O(d(N+k)),其中d是元素的位数,N是元素个数,k是基数。计数排序的时间复杂度:O(Max(N,range)),range表示范围。两个排序的逻辑都不难,但是想法很偏僻。