基数排序的C++实现(解析)

介绍了基数排序的基本原理及特点,并提供了一种基于C++的实现方式,详细解析了代码中的关键步骤。

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

基数排序(Radix sort)是一种非比较型整数排序算法,其原理是将整数按位数切割成不同的数字,然后按每个位数分别比较。由于整数也可以表达字符串(比如名字或日期)和特定格式的浮点数,所以基数排序也不是只能使用于整数。基数排序的发明可以追溯到1887年赫尔曼·何乐礼在打孔卡片制表机(Tabulation Machine)上的贡献。时间复杂度是 O(k·n),其中n是排序元素个数,k是数字位数。——来自 维基百科
空间复杂度为O(B),其中B为基数Base,如10或16等,不是一个稳定排序。
维基百科上有C++实现的代码,够简练,看了一段时间才看明白,在每次基于各个数位上的数字散列和合并的时候,用的方式够巧妙,是我没想出来的!特在此处贴出来,然后解释之~

我仿着维基百科给的C++代码,实现如下:

#include <iostream>
#include <cstring>
#include <ctime>
using namespace std;

struct Num{
	int v;
	Num *next;
	Num(){
		next=0;
	}
};
void sort(int *arr,int len){
	const int RADIX=10;//以10为基进行排序
	int tmp;
	Num *topBox[RADIX];//桶中最新添加进去的元素
	Num *bottomBox[RADIX];//桶底元素

	for(int i=0;i<RADIX;++i){
		topBox[i]=bottomBox[i]=new Num;
	}

	//找最大值
	tmp=arr[0];
	for(int i=0;i<len;++i){
		if(tmp<arr[i])
			tmp=arr[i];
	}

	//计算最大值有多少个数位
	int digCnt=1;
	tmp/=RADIX;
	while(tmp){
		++digCnt;
		tmp/=RADIX;
	}

	//将数组转换成链表
	Num *head=new Num;
	Num *cur;
	cur=head;
	for(int i=0;i<len;++i){
		cur->next=new Num;
		cur->next->v=arr[i];
		cur=cur->next;
	}

	//开始基数排序
	int factor=1;
	for(int i=0;i<digCnt;++i){
		//散列
		for(cur=head->next;cur;cur=cur->next){
			tmp=(cur->v/factor)%RADIX;
			topBox[tmp]->next=cur;
			topBox[tmp]=topBox[tmp]->next;
		}
		//合并
		cur=head;
		for(int j=0;j<RADIX;++j){
			if(topBox[j]!=bottomBox[j]){
				cur->next=bottomBox[j]->next;
				cur=topBox[j];
				topBox[j]=bottomBox[j];
			}
		}
		//必须将最后一个数字的next赋值为NULL,否则导致链表形成环,导致再次"散列"时会死循环
		cur->next=0;

		//扩大因子,用于取下一个数字
		factor*=RADIX;
	}

	//使用链表给数组赋值
	cur=head->next;
	for(int i=0;i<len;++i,cur=cur->next){
		arr[i]=cur->v;
	}
}

void test(){
	int len=20;
	int *heap=new int[len];

	srand(time(0));
	for(int i=0;i<len;++i){
		heap[i]=rand()%10000;
	}
	cout<<"初始数组:"<<endl;
	printArray(heap,len);
	//mySort(heap,0,len-1);
	sort(heap,len);
	printArray(heap,len);
	delete heap;
}

bottomBox数组不会变化,因为它存储的是每个“桶”的初始元素,而topBox数组一直在变化,因为它始终指向“桶”中最近被添加的数字,这是由"基数排序中的每个"桶"必须在链表尾部添加新的数字"决定的,链表的尾部,就是topBox(可以把这个"桶"想象成一个开口向下的倒着的桶~)。起始状态,bottomBox与topBox里的每个元素都是一样的,因为每个"桶"里都没有数字,随着散列的进行,有些"桶"里就被先后放入多个数字,此时topBox随之变化,使自己总是指向"桶"最顶部的数字,也就是最新被添加的那个数字。

散列完成之后,需要将本次的散列结果按“在数组中散列到的桶号”串联起来,用于下次散列,串联的时候,每个“桶”中,开始的元素由bottomBox存储,终止元素由topBox存储,而且,如果该“桶”是空的,那么bottomBox对应的值与topBox对应的值相等,反过来说:凡是bottomBox中与topBox对应值不相等的那个“桶”里肯定有数字串,这个串的起始数字由bottomBox存储,终止数字由topBox存储。很巧妙吧!



评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值