排序----- 计数排序,基数排序

计数排序,基数排序

计数排序

基本思想

计数排序又称为鸽巢原理,是对哈希直接定址法的变形应用。

操作步骤:

  1. 统计相同元素出现次数

  2. 根据统计的结果将序列回收到原来的序列中

思维导图

在这里插入图片描述
在这里插入图片描述

特性总结

  1. 计数排序在数据范围集中时,效率很高,但是适用范围及场景有限。

  2. 时间复杂度:O(MAX(N,range)),range表示范围(Max函数:取两者中大的那个数)

  3. 空间复杂度:O(range),range表示范围

  4. 稳定性:稳定

代码实现

//计数排序
// 没有两数之间比较大小的排序
//只能排序全是正数或全是负数的序列
//对同时含正数和负数的序列不适用
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;
}

基数排序

基本思想

将待排序的元素按照每个位上的数字来进行排序,从低位到高位依次进行排序,直到排序完成为止。

具体来说,它将所有元素按照个位数进行排序,然后按照十位数进行排序,以此类推,直到按照最高位排序完成为止。

在这里插入图片描述

思维导图

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

特性总结

  1. 时间复杂度:基数排序的时间复杂度为O(d(N+k))其中d是元素的位数,N是元素个数,k是基数。当d较小,k不是很大时,基数排序的时间复杂度可以达到线性级别,比如在对电话号码进行排序时。
  2. 空间复杂度:O(k+n),N是元素个数,k是基数
  3. 稳定性:稳定

代码实现

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表示范围。两个排序的逻辑都不难,但是想法很偏僻。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值