排序【5】基数排序和计数排序

 前面介绍的几种排序方式都是比较式的排序,今天,我们来介绍两种非比较排序。计数排序和基数排序。

一、计数排序

1.基本思想:

遍历待排数组,找到数组中最大的元素,然后开辟一个比这个最大元素大1的新数组,以新数组的下标表示待排元素,统计原数组中所有元素出现的个数放在新数组相应的位置,然后把新数组中除过0次出现的其余元素,按顺序拷贝回原数组即可。

2.思想流图

3.代码实现:

void CountSort(int *array, int size)//计数排序
{
	assert(array);
	int MAX = array[0];
	for (size_t i = 0; i < size; ++i)
	{
		if (array[i] > MAX)
			MAX = array[i];
	}
	int *tmp = new int[MAX + 1];
	memset(tmp, 0, sizeof(int)*(MAX + 1));
	for (size_t j = 0; j < size; ++j)
	{
		++tmp[array[j]];
	}
	int index = 0;
	for (size_t k = 0; k < size; ++k)
	{
		while (tmp[k]--)
		{
			array[index] = k;
			++index;
		}
	}
	delete[] tmp;
}

4.算法性能:

时间复杂度:它的时间复杂度是O(N+K),其中K主要是取决于排序数组的范围。

空间复杂度:它的空间复杂度是O(N),实际上,计数排序是一种以空间换时间的做法。

稳定性:不稳定。

适用场景:元素排列比较集中的情况。

 5.优化:

当元素比较集中的时候,我们再开辟比最大元素大1的数组的时候就比较浪费空间,因此我们找到数组中元素的最大最小值,开辟一个最大值减去最小值再加一的数组大小,就比较节省空间。

void CountSort1(int* a,size_t n)  
{  
    //找到待排序序列的最大值和最小值  
    int max = a[0];  
    int min = a[0];  
    for (size_t i = 0; i < n-1; ++i)  
    {  
        if (max < a[i+1])  
        {  
            max = a[i+1];  
        }  
        if (min > a[i+1])  
        {  
            min = a[i+1];  
        }  
    }  
  
    //开辟适当空间的数组  
    int range = max - min + 1;  
    int* tmp = new int[range];  
    memset(tmp,0,sizeof(int)*(range));  
    for (size_t i = 0; i < n; ++i)  
    {  
        tmp[a[i]-min]++;  
    }  
  
    //将数据考回原数组  
    int index = 0;  
    for (int i = 0; i < range; ++i)  
    {  
        while(tmp[i]--)  
        {  
            a[index] = i+min;  
            ++index;  
        }  
    }  
    delete []tmp;  
}  

二、基数排序

  1.基本思想:基数排序又成为“桶子法“,是根据元素各个位先进行排序,比如先根据个位进行排序,再根据十位排,一直排到最大元素的最高位截至。

2.思想流图:

  3.代码实现:
int GetMaxdigit(int*array, int size)
{
	assert(array);
	int MAX = array[0];
	for (size_t i = 0; i < size; ++i)
	{
		if (array[i] > MAX)
			MAX = array[i];
	}
	int count = 0;
	while (MAX)
	{
               MAX/=10;
		++count;
	}
	return count;
}
void LSDSort(int *array, int size)//基数排序
{
	assert(array);
	int base = 1;
	int digit = GetMaxdigit(array, size);//获取最大元素的位数
	int *tmp = new int[size];//开辟临时数组
	while (digit--)
	{
		//统计某位相同的数据出现的次数
		int count[10] = { 0 };
		for (size_t i = 0; i < size; ++i)
		{
			int index=array[i] / base % 10;
			count[index]++;
		}
		int start[10] = { 0 };
		//统计个位相同的数在数组中出现的位置
		for (size_t j = 1; j < size; ++j)
		{
			start[j] = count[j - 1] + start[j - 1];
		}
		memset(tmp, 0, sizeof(int)*size);
		for (int k = 0; k < size; ++k)
		{
			int index = array[k] / base % 10;
			tmp[start[index]++] = array[k];

		}
		memcpy(array, tmp, sizeof(int)*size);
		base *= 10;

	}

	delete []tmp;
}
4.算法性能:
时间复杂度:0(N*digit)主要取决于最大元素的位数digit。
空间复杂度:O(N)
稳定性:稳定。

  



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值