排序算法8——基数排序

【基数排序】
基数排序的算法思想:基数排序不同于前面的各种排序算法,前面的排序算法都是基于元素之间的比较好实现的,而基数排序则是利用分类进行排序的方法。

【算法思想】

基数排序是一种多关键字排序算法。基数排序通过对所有元素根据关键字进行分类,然后按照关键字的顺序将这些元素收集起来,通过这样的方法完成对元素序列的排序。因此基数排序算法分成两个分部:分配和收集。

具体算法描述:假设第i个元素a_i的关键字为key_i,key_i是由d位个十进制组成,即key_i=ki^d ki^d-1 ... ki^1,其中ki^1为最低位,ki^d为最高位。关键字的每一位数字都可以作为一个子关键字。首先将每一个元素依次按照每个关键字进行排序并收集,直到按照所有的关键字都排序、收集完毕,这样就完成了排序过程。

【示例】
例如,一组元素序列为325,138,29,214,927,631,732,205。这组元素的位数最多是3,在排序之前首先将所有元素都转换为3位数字组成的数,不够3位的在前面添加0,即325,138,029,214,927,631,732,205。对这组元素进行基数排序需要进行3趟分配和收集。其次需要对该元素序列的关键字的最低位即个位上的数字进行分配和收集,再对十位数字进行分配和收集,最后是对最高位的数字进行分配和收集。一般情况下,采用链表实现基数排序。

对最低位进行分配和收集的过程如下图所示。

排序算法8——基数排序_第1张图片
其中,数组f[i]保存第i个链表的头指针,数组r[i]保存第i个链表的尾指针。

对十位数字的分配和收集的过程如下图所示。

排序算法8——基数排序_第2张图片
对百位数字的分配和收集的过程如下图所示。

排序算法8——基数排序_第3张图片
由上很容易看出,经过第1趟排序即对个位数字作为关键字进行分配后,关键字被分为10类,个位数组相同的数字被划分为一类,然后对分配后的元素进行收集之后,得到以个位数字非递减排列的元素。同理,经过第2趟分配和收集后,得到以十位数字非递减排列的元素序列。经过第3趟分配和收集后,得到最终排序结果。

code:

#include
#include
#include
#include
#include
#define MaxSize 200	/*待排序元素的最大个数*/
#define N 8         	/*待排序元素的实际个数*/
#define MaxNumKey 6	/*关键字项数的最大值*/
#define Radix 10		/*关键字基数,10表示十进制数字可以分为十组*/
/*静态链表的结点,存放待排序元素*/
typedef struct
{
	int key[MaxNumKey]; 	/*关键字*/
	int next;
}SListCell;
/*静态链表,存放元素序列*/
typedef struct
{
	SListCell data[MaxSize];		/*存储元素,data[0]为头结点*/
	int keynum;				/*每个元素的当前关键字个数*/
	int length;					/*静态链表的当前长度*/
}SList;
typedef int addr[Radix]; /*指针数组类型,用来指向每个链表的第1个结点和最后一个结点*/
void DispList(SList L); 			/*输出链表中的元素*/
void DispStaticList(SList L); 		/*以静态链表的形式输出元素*/
void InitList(SList *L, int d[], int n);
int trans(char c); 				/*将字符转换为数字*/
void Distribute(SListCell data[], int i, addr f, addr r); 	/*分配*/
void Collect(SListCell data[], addr f, addr r); 		/*收集*/
void RadixSort(SList *L); 					/*基数排序*/
void Distribute(SListCell data[], int i, addr f, addr r)
/*为data数组中的第i个关键字key[i]建立Radix个子表,使同一子表中元素的key[i]相同*/
/*f[0..Radix-1]和r[0..Radix-1]分别指向各个子表中第一个和最后一个元素*/
{
	int j, p;
	for (j = 0; j= 0; j--)
			printf("%c", L.data[i].key[j]);
		printf("    %d\n", L.data[i].next);
	}
}
void DispStaticList(SList L)
/*按链表形式输出静态链表*/
{
	int i = L.data[0].next, j;
	while (i)
	{
		for (j = L.keynum - 1; j >= 0; j--)
			printf("%c", L.data[i].key[j]);
		printf(" ");
		i = L.data[i].next;
	}
	printf("\n");
}
int trans(char c)
/*将字符c转化为对应的整数*/
{
	return c - '0';
}

结果:

排序算法8——基数排序_第4张图片

【主要用途】

基数排序算法实现复杂,它是一种多关键字排序算法,属于分类排序。因为基数排序算法不需要过多比较,所以在数据较多的情况下,采用基数排序算法的效率要优于前面谈到的排序算法。

【稳定性与复杂度】

基数排序是一种稳定的排序算法。
基数排序算法的时间复杂度为O(d(n+r)),其中,n表示待排序的元素个数,d表示关键字个数,r表示基数。其中一趟分配时间复杂度为O(n),一趟收集时间复杂度为O(r)。

基数排序需要2*r个指向链式队列的辅助空间。

 

你可能感兴趣的:(数据结构与算法)