【排序】计数排序

本文详细介绍了计数排序算法的基本思想,利用哈希映射的绝对和相对映射,以及其在数据重复且范围集中的场景下的高效性。讨论了空间复杂度和时间复杂度,并指出适用局限。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

计数排序算法思想

  • 动图演示:

在这里插入图片描述

  • 基本思想:

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

  • 操作步骤:
    • 统计相同元素出现次数。
    • 根据统计的结果将序列回收到原来的序列中。

假设现在要对如下数组进行排序:

在这里插入图片描述

计数的核心步骤就是数组中数字的值是多少,就把该值映射到新开辟数组的下标上。仔细观察这串数组,最大数字为10,所以这里我们要开辟11个空间,才能保证数字10放到新数组下标为10的位置,遍历原数组,一个val出现几次,它映射的位置++几次。

在这里插入图片描述

上述方法即哈希的绝对映射思想,原数组的某个元素是几,对应新开辟数组下标为几的位置就相应的加加,出现几次,加加几次。此方法看似可行,但存在一个大问题,空间复杂度过大,如若一组数据为【10000,9999,5000,9999,5000,8888】,难道说为了排这几个数字,你要开辟10001个大小空间的数组吗,得不偿失,更何况你这10001个空间的前5000个空间没有值映射,纯纯浪费了空间,这就是绝对映射的弊端,因此要用相对映射。

  • 绝对映射:原数组是几,映射到新数组下标位置++。
  • 相对映射:此时新数组下标的范围是从0到原数组最小的值,而映射到下标的位置为原数组val的值 - 原数组最小min的值。

在这里插入图片描述

综上,计数排序使用于数据有一些重复,数据范围比较集中 ,从而避免空间浪费过于严重。

代码如下:

//计数排序
void CountSort(int* a, int n)
{
	int min = a[0], max = a[0];
	//先求出原数组的最大和最小值
	for (int i = 1; i < n; i++)
	{
		if (a[i] < min)
			min = a[i];
		if (a[i] > max)
			max = a[i];
	}
	//求出新数组的范围
	int range = max - min + 1;
	//开辟新数组
	int* countA = (int*)malloc(sizeof(int) * range);
	assert(countA);
	//把新开辟数组初始化为0
	memset(countA, 0, sizeof(int) * range);
 
	//计数
	for (int i = 0; i < n; i++)
	{
		countA[a[i] - min]++; //统计相同元素出现次数(相对映射)
	}
 
	//排序
	int j = 0;
	for (int i = 0; i < range; i++)
	{
		while (countA[i]--)
		{
			a[j++] = i + min; //赋值时,记得加回原先的min
		}
	}
	free(countA);
}

计数排序特性总结

  1. 计数排序在数据范围集中时,效率很高,但是适用范围及场景有限。
  2. 时间复杂度:O(N + range)。
  3. 空间复杂度:O(range)。
  4. 稳定性:稳定。

八大排序图表汇总

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值