常用排序之基数排序

       基数排序属于“分配式排序”,又称“桶子法”。它是通过键值的信息,将要排序的元素分配至某些“桶”中,以达到排序的作用。基数排序属于稳定性排序。

时间复杂度

       基数排序的时间复杂度为O(nlog(r)m),其中r为所采取的基数,而m为堆数。

基本原理
       将所有待比较数值(正整数)统一为同样的数位长度,数位较短的数前面补零。然后,从最低位开始,依次进行一次排序。这样从最低位排序一直到最高位排序完成以后, 数列就变成一个有序序列。

方法
       最高位优先法,简称MSD法:先按k1排序分组,同一组中记录,关键码k1相等,再对各组按k2排序分成子组,之后,对后面的关键码继续这样的排序分组,直到按最次位关键码kd对各子组排序后。再将各组连接起来,便得到一个有序序列。
       最低位优先法,简称LSD法:先从kd开始排序,再对kd-1进行排序,依次重复,直到对k1排序后便得到一个有序序列。

实例
       按LSD方法,假设有一个数组如下:
       73,22,93,43,55,14,28,65,39,81
第一步:首先根据个位数的数值,将它们依次分配到0-9个桶中:
         0号桶:
         1号桶:81
         2号桶:22
         3号桶:73,93,43
         4号桶:14
         5号桶:55,65
         6号桶:
         7号桶:
         8号桶:28
         9号桶:39
第二步:将桶子里的数值串起来,称为以下数列:
               81,22,73,93,43,14,55,65,28,39
        接着根据十位数来分配:
         0号桶:
         1号桶:14
         2号桶:22,28
         3号桶:39
         4号桶:43
         5号桶:55
         6号桶:65
         7号桶:73
         8号桶:81 
         9号桶:93
第三步:将桶子里的数值重新串起来成为以下数列:
               14, 22, 28, 39, 43, 55, 65, 73, 81, 93
       这时候整个数列已经排序完毕;如果排序的对象有三位数以上,则持续进行以上的动作直至最高位数为止。
       LSD的基数排序适用于位数小的数列,如果位数多的话,使用MSD的效率会比较好。MSD的方式与LSD相反,是由高位数为基底开始进行分配,但在分配之后并不马上合并回一个数组中,而是在每个“桶子”中建立“子桶”,将每个桶子中的数值按照下一数位的值分配到“子桶”中。在进行完最低位数的分配后再合并回单一的数组中。

下面是代码实现:

#include<stdio.h>
#include<iostream>
using namespace std;

int maxbit(int data[], int n) //辅助函数,求数据的最大位数
{
	int d = 1; //保存最大的位数
	int p = 10;
	for (int i = 0; i < n; ++i)
	{
		while (data[i] >= p)
		{
			p *= 10;
			++d;
		}
	}
	return d;
}

int* radixsort(int data[], int n) //基数排序
{
	int d = maxbit(data, n);
	int *tmp = new int[n];
	int *count = new int[10]; //计数器
	int i, j, k;
	int radix = 1;
	for (i = 1; i <= d; i++) //进行d次排序
	{
		for (j = 0; j < 10; j++)
			count[j] = 0; //每次分配前清空计数器
		for (j = 0; j < n; j++)
		{
			k = (data[j] / radix) % 10; //统计每个桶中的记录数
			count[k]++;
		}
		for (j = 1; j < 10; j++)
			count[j] = count[j - 1] + count[j]; //将tmp中的位置依次分配给每个桶
		for (j = n - 1; j >= 0; j--) //将所有桶中记录依次收集到tmp中
		{
			k = (data[j] / radix) % 10;
			tmp[count[k] - 1] = data[j];
			count[k]--;
		}
		for (j = 0; j < n; j++) //将临时数组的内容复制到data中
			data[j] = tmp[j];
		radix = radix * 10;
	}
	return data;
	delete[]tmp;
	delete[]count;
}

int main()
{
	const int n = 13;
	int data[] = { 1,255,8,6,25,47,14,35,58,75,96,158,657 };
	for (int i = 0; i < n; i++)
		cout << data[i] << " ";
	cout << endl;
	
	int *d = radixsort(data,n);
	
	for (int i = 0; i < n; i++)
		cout << d[i] << " ";
	cout << endl;
	system("pause");
}


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值