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

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

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

#include 
#include 
#include 
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;inext=new Num;
		cur->next->v=arr[i];
		cur=cur->next;
	}

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

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

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

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

	srand(time(0));
	for(int i=0;i

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

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



你可能感兴趣的:(C++_原创区)