基数排序

桶排序

基数排序之前,先说一下桶排序,桶排序很好理解,比如序列array = {3, 1, 2, 5, 6, 8},这个数组,进行桶排序就可以申请一个大小为10的vis数组,把vis[array[i]]++。在从1遍历到10,只要碰到vis[i] != 0 就直接输出vis[i]个 i,最后就是array排完序的样子了。这个是比较容易理解。

基数排序

上面桶排序的缺点太明显了,浪费空间不说,如果数字大一点的话,根本开不了那么大的数组。因此基数排序就对桶排序进行了一点点的改进。数字虽然可以特别大,但每一位的数字最多只有十种可能,我能不能根据数字每一位来进行排序呢?
赫尔曼·何乐礼就想到了解决办法,也就是今天的基数排序,基数排序是一个稳定的排序。先看一下过程,
对于序列 {3, 2, 44, 5, 6}来说,我们先按照最后一位来排序
变为了 {2, 3, 44, 5, 6}
然后是第二位来排序
变为了
{02, 03, 05, 06, 44}
神奇吧,就通过两个循环就做到了。
那么按照从低位到高位和从高位到低位排序结果一样不一样呢,为什么只能从低位到高位进行排序呢?
我们可以看 {3, 2, 44, 5, 6},如果直接按照高位排序,先从第二位排序,对于一个稳定的算法来说,它就变成了{03, 02, 05, 06, 44},接下来在按照第二位排序的话就变为了{02, 03, 44, 05, 06},因此说明了基数排序应该从低位到高位。
我们假设现在是根据高位来进行排序,那低位肯定是已经有序的了,如果高位相同的话,由于这个算法是稳定的,并且低位已经有序了,那么像45, 47这样的情况就还是45在前。所以前一位有序是为了下一位排序做铺垫的。如果第二位不同,那还看个啥第一位,直接排就行了,比如35, 47,3<5,所以35一定在47前面。
和桶排序的关系:
咱们前面说了基数排序是桶排序的改进,那为啥上面一点都没有提到桶排序呢?其实对于每一位进行排序的时候用的就是桶排序,每一位就十种数字,开一个大小为10的数组就够了。而且通过神奇的操作,还能把它在辅助数组中的位置定下来,我们代码中看。

在这里插入图片描述

代码

#include <iostream>
#include <cstring>

using namespace std;

int a[10000], temp[10000];
int n;

int find()  //查找最大的位数是多少,也可以在输入的时候直接进行判断,就少一个n 
{
	int d = 1, p = 10;
	
	for (int i=0; i<n; i++)
	{
		while (a[i] > p)
		{
			d++;
			p*=10;
		}
	}
	
	return d;
}

void slove()  //基数排序 
{
	int k = find(), p = 1;
	int buket[10];   //计算当前位有多少个i的数字 
	
	for (int i=0; i<k; i++)
	{
		memset(buket, 0, sizeof(buket));
		memset(temp, 0, sizeof(temp));
		
		for (int j=0; j<n; j++)
			buket[(a[j] / p) % 10]++;
		
		for (int j=1; j<10; j++)   //计算出在temp数组中的位置 
			buket[j] += buket[j-1];
		
		for (int j=n-1; j>=0; j--)  //从n-1保证了当前位相等的情况下,低位大的数字先进temp的后面。不懂可修改for循环测试(3 1 5 44 5 2)
		{
			temp[buket[(a[j]/p)%10]-1] = a[j];
			buket[(a[j]/p)%10]--;
		}
		
		for (int j=0; j<n; j++) //将辅助数组的内容放回原数组,好为了下一次计算做准备 
			a[j] = temp[j];
		
		p*=10;
	}
}

int main()
{
	cin >> n;
	
	for (int i=0; i<n; i++)
		cin >> a[i];
	
	slove();
	
	for (int i=0; i<n; i++)
		cout << a[i] << endl;
	
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值