【排序算法】基数排序:LSD 与 MSD

【排序算法】基数排序:LSD 与 MSD1.算法原理基数排序是通过“分配”和“收集”过程来实现排序。1)分配,先从个位开始,根据位值(0-9)分别放到0~9号桶中(比如53,个位为3,则放入3号桶中)2)收集,再将放置在0~9号桶中的数据按顺序放到数组中重复(1)(2)过程,从个位到最高位(比如32位无符号整形最大数4294967296,最高位10位)。而这个思想该如何理解呢?请看以下例子。(1)

大家好,又见面了,我是你们的朋友全栈君。1.算法原理

基数排序是通过“分配”和“收集”过程来实现排序。

1)分配,先从个位开始,根据位值(0-9)分别放到0~9号桶中(比如53,个位为3,则放入3号桶中)

2)收集,再将放置在0~9号桶中的数据按顺序放到数组中

重复(1)(2)过程,从个位到最高位(比如32位无符号整形最大数4294967296,最高位10位)。而这个思想该如何理解呢?请看以下例子。

(1)假设有欲排数据序列如下所示:

73 28 93 43 55 14 22 65 26 81

首先根据个位数的数值,在遍历数据时将它们各自分配到编号0至9的桶(个位数值与桶号一一对应)中。

从低位到高位分配收集过程:

【排序算法】基数排序:LSD 与 MSD

观察可以看到,此时原无序数据序列已经排序完毕。如果排序的数据序列有三位数以上的数据,则重复进行以上的动作直至最高位数为止。
基于两种不同的排序顺序,我们将基数排序分为

    LSD(Least significant digital):排序方式由数值的最右边(低位)开始

    MSD(Most significant digital):由数值的最左边(高位)开始。

注意一点:

LSD的基数排序适用于位数少的数列,如果位数多的话,使用MSD的效率会比较好。

MSD的方式由高位数为基底开始进行分配,但在分配之后并不马上合并回一个数组中,而是在每个“桶子”中建立“子桶”,将每个桶子中的数值按照下一数位的值分配到“子桶”中。在进行完最低位数的分配后再合并回单一的数组中。

由高位到低位分配收集过程:

     73 28 93 43 55 14 22 65 26 81


【排序算法】基数排序:LSD 与 MSD

(2)我们把扑克牌的排序看成由花色和面值两个数据项组成的主关键字排序。要求如下:

     花色顺序:梅花<方块<红心<黑桃

     面值顺序:2<3<4<…<10<J<Q<K<A

那么,若要将一副扑克牌排成下列次序:

     梅花2,…,梅花A,方块2,…,方块A,红心2,…,红心A,黑桃2,…,黑桃A。

有两种排序方法:

<1>先按花色分成四堆,把各堆收集起来;然后对每堆按面值由小到大排列,再按花色从小到大按堆收叠起来。—-称为”最高位优先”(MSD)法。

<2>先按面值由小到大排列成13堆,然后从小到大收集起来;再按花色不同分成四堆,最后顺序收集起来。—-称为”最低位优先”(LSD)法。

2.算法分析

平均时间复杂度:O(dn)(d即表示整形的最高位数)

空间复杂度:O(10n) (10表示0~9,用于存储临时的序列) 

稳定性:稳定

3.程序实现

(1)LSD法实现

最低位优先法首先依据最低位关键码Kd对所有对象进行一趟排序,

再依据次低位关键码Kd-1对上一趟排序的结果再排序,

依次重复,直到依据关键码K1最后一趟排序完成,就可以得到一个有序的序列。

使用这种排序方法对每一个关键码进行排序时,不需要再分组,而是整个对象组。

因为分配和收集阶段,数字符合先入先出的关系。因此可以用10个队列来保存 0-9 上分配的数字,在收集阶段,按先入先出的顺序取出每个桶中的数字,依次放到原数组中。

/********************************************************
*函数名称:GetNumInPos
*参数说明:num 一个整形数据
*     pos 表示要获得的整形的第pos位数据
*说明:    找到num的从低到高的第pos位的数据
*********************************************************/
int GetNumInPos(int num, int pos)
{
	int temp = 1;
	for (int i = 0; i < pos - 1; i++)
		temp *= 10;

	return (num / temp) % 10;
}

#define MAXPOS 10    //最高位的位数
void RadixSort(vector<int> &A)
{
	int len = A.size();
	vector<vector<int>> radixArray(10);  //分为0~9的序列空间

	for (int pos = 1; pos <= MAXPOS; pos++)    //从个位开始到最高位数
	{
		for (int i = 0; i < len; i++)    //分配过程
		{
			int num = GetNumInPos(A[i], pos);
			radixArray[num].push_back(A[i]);
		}

		for (int i = 0, j = 0; i < 10; i++)    //收集
		{
			while (!radixArray[i].empty())
			{
				A[j++] = radixArray[i].front();  //取首部数据依次插入原数组
				radixArray[i].erase(radixArray[i].begin());    //移除首部元素
			}
		}
	}
}

(2)MSD法实现

最高位优先法通常是一个递归的过程:

<1>先根据最高位关键码K1排序,得到若干对象组,对象组中每个对象都有相同关键码K1。

<2>再分别对每组中对象根据关键码K2进行排序,按K2值的不同,再分成若干个更小的子组,每个子组中的对象具有相同的K1和K2值。

<3>依此重复,直到对关键码Kd完成排序为止。

<4> 最后,把所有子组中的对象依次连接起来,就得到一个有序的对象序列。

/********************************************************
*函数名称:GetNumInPos
*参数说明:num 一个整形数据
*     pos 表示要获得的整形的第pos位数据
*说明:    找到num的从低到高的第pos位的数据
*********************************************************/
int GetNumInPos(int num, int pos)
{
 int temp = 1;
 for (int i = 0; i < pos - 1; i++)
  temp *= 10;
 return (num / temp) % 10;
}
//MSD,调用时指定最高位数d
void RadixSort(vector<int> &A, int d)
{
 int len = A.size();
 vector<vector<int>> radixArray(10);  //分为0~9的序列空间,用队列保存每个桶分配的数据
 //位数大于0,且数组长度大于1
 if (d >= 1 && len > 1)
 {
  for (int i = 0; i < len; i++)    //分配过程
  {
   int num = GetNumInPos(A[i], d);
   radixArray[num].push_back(A[i]);
  }
  cout << endl;
  for (int i = 0, j = 0; i < 10; i++)    //收集
  {
   RadixSort(radixArray[i], d-1);  //递归,对每个子桶从次高位开始分配
   while (!radixArray[i].empty())
   {
    A[j++] = radixArray[i].front();  //取队列首部数据依次插入原数组
    radixArray[i].erase(radixArray[i].begin());
   }
  }
 }
}

参考:http://blog.csdn.net/cjf_iceking/article/details/7943609

http://www.cnblogs.com/Braveliu/archive/2013/01/21/2870201.html





版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/132967.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)
blank

相关推荐

  • Qmake VS Cmake

    Qmake VS Cmake用cmake构建Qt工程(对比qmake进行学习)cmakevsqmakeqmake是为Qt量身打造的,使用起来非常方便cmake使用上不如qmake简单直接,但复杂换来的是强大的功能内置的out-ofsource构建。(目前QtCreator为qmake也默认启用了该功能。参考:浅谈qmake之sha

  • HTML+CSS实现导航条及下拉菜单[通俗易懂]

    HTML+CSS实现导航条及下拉菜单[通俗易懂]html+css实现下拉菜单

  • SSM整合(基于XML配置方式)

    SSM整合(基于XML配置方式)我们整合SSM框架时,大部分都是基于注解+XML配置方式。只因为结合这两种方法能够实现同样的效果,而且会更加的轻松。所以在此推荐朋友们用注解+XML配置的方式,基于注解+XML配置方式会另写一篇。但是有朋友和我说,怎么用纯XML方式整合SSM呢?我做了一个入门的整理,如果不足,请多多指教。本文是基于XML配置方式整合SSM框架,由于本人不太推荐这种方式。首先可以看一下完整的目录结构…

  • Linux安装Redis(图文解说详细版)「建议收藏」

    Linux安装Redis(图文解说详细版)「建议收藏」最近开个新坑,就是在linux环境中操作开发环境,带大家玩转Linux,会整理出一篇Linux的专栏,欢迎大家订阅!!富贵同学linux环境为CentOS7.8版本。这次说一下Redis的安装第一步,下载安装包https://redis.io/download第二步,上传安装包到/opt下(老规矩了,安装包在opt下)第三步,解压安装包tar-zxvfredis-6.2.6.tar.gz第四步,编译进入到reidis-6.2.6中输入make进行编译第五步,安装进入s

  • 【Web攻防】红队外围信息收集【总结】

    【Web攻防】红队外围信息收集【总结】​外围打点前言由于红队不同于一般的渗透测试,强调更多的是如何搞进去拿到相应机器权限或者实现某特定目的,而不局限于你一定要在什么时间,用什么技术或者必须通过什么途径去搞,相比传统渗透测试,红队则更趋于真实的入侵活动,这种场景其实对防御者的实战对抗经验和技术深度都是比较大的挑战信息收集方式一般采取以下几种方式在搜索引擎(如:baidu、google)进行搜索: 主站相关联的链接,主站链接下可能会放置跳转,如邮件、OA等相关系统。 主站子域名进行搜索,通过二级或三级域名进行目标搜索相.

  • 递归求数组的和_java递归教程

    递归求数组的和_java递归教程使用递归实现数组求和示例分享思路如下:给定一个含有n个元素的整型数组a,求a中所有元素的和。问题的难点在于如何使用递归上。如果使用递归,则需要考虑如何进行递归执行的开始以及终止条件,首先如果数组元素个数为0,那么和为0。同时,如果数组元素个数为n,那么先求出前n-1个元素之和,再加上a[n-1]即可。此时可以完成递归功能。总之,递归就是在某个函数的执行过程中首先判断它的终止条件参数,终止条件参数满…

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号