PHP排序算法之基数排序(Radix Sort)实例详解


Posted in PHP onApril 21, 2018

本文实例讲述了PHP排序算法之基数排序(Radix Sort)。分享给大家供大家参考,具体如下:

基数排序在《大话数据结构》中并未讲到,但是为了凑齐八大排序算法,我自己通过网络学习了这个排序算法,并给大家分享出来。

基本思想:

基数排序(radix sort)属于“分配式排序”(distribution sort),又称“桶子法”(bucket sort)或bin sort,顾名思义,它是透过键值的部份资讯,将要排序的元素分配至某些“桶”中,藉以达到排序的作用,基数排序法是属于稳定性的排序,其时间复杂度为O (nlog(r)m),其中r为所采取的基数,而m为堆数,在某些时候,基数排序法的效率高于其它的稳定性排序法。

其实这个思想我也没法总结出来,下面通过例子来说明吧:

基本解法:

PS:在这里我们介绍的基数排序我们采用 LSD(最低位优先),当然还有 MSD(最高位优先),大家自己去百度一下他们之间的异同吧。

假如现在我们有以下这么一些数:

2 343 342 1 128 43 4249 814 687 654 3

我们使用基数排序将他们从小到大排序。

第一步、首先根据个位数的数值,在走访数值(从前到后走访,后面步骤相同)时将它们分配至编号0到9的桶子中:

0 :
1 : 1
2 : 2 342
3 : 343 43 3
4 : 814 654
5 :
6 :
7 : 687
8 : 128
9 : 4249

第二步、接下来将这些桶子中的数值重新串接起来,成为以下的数列:

1 2 342 343 43 3 814 654 687 128 4249

第三步、根据十位数的数值,在走访数值(从前到后走访,后面步骤相同)时将它们分配至编号0到9的桶子中:

0 : 1 2 3
1 : 814
2 : 128
3 :
4 : 342 343 43 4249
5 : 654
6 :
7 :
8 : 687
9 :

第四步、接下来将这些桶子中的数值重新串接起来,成为以下的数列:

1 2 3 814 128 342 343 43 4249 654 687

第五步、根据百位数的数值,在走访数值(从前到后走访,后面步骤相同)时将它们分配至编号0到9的桶子中:

0 : 1 2 3 43
1 : 128
2 : 4249
3 : 342 343
4 :
5 :
6 : 654 687
7 :
8 : 814
9 :

第六步、接下来将这些桶子中的数值重新串接起来,成为以下的数列:

1 2 3 43 128 4249 342 343 654 687 814

。。。。。。后面的步骤大家应该都会走了吧。其实到了第六步的时候就剩 4249 没有排好序了。

从上面的步骤来看,很多的步骤都是相同的,因此肯定是个循环了,我们只需要控制个位、十位、百位、、、、就好了。

还是看代码吧。

算法实现:

//交换函数
function swap(array &$arr,$a,$b){
  $temp = $arr[$a];
  $arr[$a] = $arr[$b];
  $arr[$b] = $temp;
}
//获取数组中的最大数
//就像上面的例子一样,我们最终是否停止算法不过就是看数组中的最大值:4249,它的位数就是循环的次数
function getMax(array $arr){
  $max = 0;
  $length = count($arr);
  for($i = 0;$i < $length;$i ++){
    if($max < $arr[$i]){
      $max = $arr[$i];
    }
  }
  return $max;
}
//获取最大数的位数,最大值的位数就是我们分配桶的次数
function getLoopTimes($maxNum){
  $count = 1;
  $temp = floor($maxNum / 10);
  while($temp != 0){
    $count ++;
    $temp = floor($temp / 10);
  }
  return $count;
}
/**
 * @param array $arr 待排序数组
 * @param $loop 第几次循环标识
 * 该函数只是完成某一位(个位或十位)上的桶排序
 */
function R_Sort(array &$arr,$loop){
  //桶数组,在强类型语言中,这个数组应该声明为[10][count($arr)]
  //第一维是 0-9 十个数
  //第二维这样定义是因为有可能待排序的数组中的所有数的某一位上的只是一样的,这样就全挤在一个桶里面了
  $tempArr = array();
  $count = count($arr);
  //初始化$tempArr数组
  for($i = 0;$i < 10;$i ++){
    $tempArr[$i] = array();
  }
  //求桶的index的除数
  //如798个位桶index=(798/1)%10=8
  //十位桶index=(798/10)%10=9
  //百位桶index=(798/100)%10=7
  //$tempNum为上式中的1、10、100
  $tempNum = (int)pow(10, $loop - 1);
  for($i = 0;$i < $count;$i ++){
    //求出某位上的数字
    $row_index = ($arr[$i] / $tempNum) % 10;
    for($j = 0;$j < $count;$j ++){
      if(@$tempArr[$row_index][$j] == NULL){
        $tempArr[$row_index][$j] = $arr[$i];   //入桶
        break;
      }
    }
  }
  //还原回原数组中
  $k = 0;
  for($i = 0;$i < 10;$i ++){
    for($j = 0;$j < $count;$j ++){
      if(@$tempArr[$i][$j] != NULL){
        $arr[$k ++] = $tempArr[$i][$j];  //出桶
        $tempArr[$i][$j] = NULL;  //避免下次循环的时候污染数据
      }
    }
  }
}
//最终调用的主函数
function RadixSort(array &$arr){
  $max = getMax($arr);
  $loop = getLoopTimes($max);
  //对每一位进行桶分配(1 表示个位,$loop 表示最高位)
  for($i = 1;$i <= $loop;$i ++){
    R_Sort($arr,$i);
  }
}

调用算法:

$arr = array(2, 343, 342, 1, 128, 43, 4249, 814, 687, 654, 3);
RadixSort($arr);
var_dump($arr);

运行结果:

array(11) {
 [0]=>
 int(1)
 [1]=>
 int(2)
 [2]=>
 int(3)
 [3]=>
 int(43)
 [4]=>
 int(128)
 [5]=>
 int(342)
 [6]=>
 int(343)
 [7]=>
 int(654)
 [8]=>
 int(687)
 [9]=>
 int(814)
 [10]=>
 int(4249)
}

其实这些代码我是在挺早之前写的,今天在写博客的时候发现,其实桶就是一个队列,所以上面的 R_Sort()函数复杂了,我们使用 array_push() array_shift() 来重写该方法(当然,要模拟队列的话,用 SPL 提供的 splqueue 是最为恰当的,在这里为了简便我就不用了):

function R_Sort(array &$arr,$loop){
  $tempArr = array();
  $count = count($arr);
  for($i = 0;$i < 10;$i ++){
    $tempArr[$i] = array();
  }
  //求桶的index的除数
  //如798个位桶index=(798/1)%10=8
  //十位桶index=(798/10)%10=9
  //百位桶index=(798/100)%10=7
  //$tempNum为上式中的1、10、100
  $tempNum = (int)pow(10, $loop - 1);
  for($i = 0;$i < $count;$i ++){
    //求出某位上的数字
    $row_index = ($arr[$i] / $tempNum) % 10;
    //入桶
    array_push($tempArr[$row_index],$arr[$i]);
  }
  //还原回原数组中
  $k = 0;
  for($i = 0;$i < 10;$i ++){
    //出桶
    while(count($tempArr[$i]) > 0){
      $arr[$k ++] = array_shift($tempArr[$i]);
    }
  }
}

基数排序法是属于稳定性的排序,其时间复杂度为O (nlog(r)m),其中r为所采取的基数,而m为堆数。

好了,到这里基数排序就已经给大家介绍完了。这个算法的总结主要是通过看网上的资料,所以就不再给出原作者了。

PHP 相关文章推荐
15种PHP Encoder的比较
Apr 17 PHP
php中sql注入漏洞示例 sql注入漏洞修复
Jan 24 PHP
thinkphp实现like模糊查询实例
Oct 29 PHP
php实现httpRequest的方法
Mar 13 PHP
必须收藏的23个php实用代码片段
Feb 02 PHP
ThinkPHP设置禁止百度等搜索引擎转码(简单实用)
Feb 15 PHP
WordPress分页伪静态加html后缀
Jun 08 PHP
Nginx环境下PHP flush失效的解决方法
Oct 19 PHP
thinkPHP统计排行与分页显示功能示例
Dec 02 PHP
PHP流Streams、包装器wrapper概念与用法实例详解
Nov 17 PHP
php中加密解密DES类的简单使用方法示例
Mar 26 PHP
Cookie跨域问题解决方案代码示例
Nov 24 PHP
PHP排序算法之堆排序(Heap Sort)实例详解
Apr 21 #PHP
PHP实现Huffman编码/解码的示例代码
Apr 20 #PHP
PHP排序算法之希尔排序(Shell Sort)实例分析
Apr 20 #PHP
PHP排序算法之直接插入排序(Straight Insertion Sort)实例分析
Apr 20 #PHP
PHP排序算法之简单选择排序(Simple Selection Sort)实例分析
Apr 20 #PHP
PHP排序算法之冒泡排序(Bubble Sort)实现方法详解
Apr 20 #PHP
PHP实现二叉树深度优先遍历(前序、中序、后序)和广度优先遍历(层次)实例详解
Apr 20 #PHP
You might like
初学者入门:细述PHP4的核心Zend
2006/09/05 PHP
PHP魔术方法以及关于独立实例与相连实例的全面讲解
2016/10/18 PHP
php中字符串和整数比较的操作方法
2019/06/06 PHP
JS对URL字符串进行编码/解码分析
2008/10/25 Javascript
javascript中length属性的探索
2011/07/31 Javascript
javascript window.confirm确认 取消对话框实现代码小结
2012/10/21 Javascript
javascript学习(二)javascript常见问题总结
2013/01/02 Javascript
Javascript中封装window.open解决不兼容问题
2014/09/28 Javascript
jQuery和AngularJS的区别浅析
2015/01/29 Javascript
javascript控制图片播放的实现代码
2020/07/29 Javascript
基于jquery实现在线选座订座之影院篇
2015/08/24 Javascript
jquery实现无刷新验证码的简单实例
2016/05/19 Javascript
JavaScript与ActionScript3两者的同性与差异性
2016/09/22 Javascript
利用JS实现文字的聚合动画效果
2017/01/22 Javascript
D3.js进阶系列之CSV表格文件的读取详解
2017/06/06 Javascript
一篇文章让你彻底弄懂JS的事件冒泡和事件捕获
2017/08/14 Javascript
AngularJS使用ng-repeat遍历二维数组元素的方法详解
2017/11/11 Javascript
在create-react-app中使用sass的方法示例
2018/10/01 Javascript
Javascript 实现 Excel 导入生成图表功能
2018/10/22 Javascript
[52:05]EG vs OG 2019国际邀请赛小组赛 BO2 第二场 8.16
2019/08/18 DOTA
Django自定义用户认证示例详解
2018/03/14 Python
使用pandas的DataFrame的plot方法绘制图像的实例
2018/05/24 Python
python中reader的next用法
2018/07/24 Python
用vue.js组件模拟v-model指令实例方法
2019/07/05 Python
详解pandas数据合并与重塑(pd.concat篇)
2019/07/09 Python
pandas 空数据处理方法详解
2019/11/02 Python
python_mask_array的用法
2020/02/18 Python
python图片指定区域替换img.paste函数的使用
2020/04/09 Python
python实现程序重启和系统重启方式
2020/04/16 Python
Python根据字典的值查询出对应的键的方法
2020/09/30 Python
英国领先的办公用品供应商:Viking
2016/08/01 全球购物
公司领导推荐信
2013/11/12 职场文书
完美的中文自荐信
2014/05/24 职场文书
入党积极分子学习党的纲领思想汇报
2014/09/13 职场文书
创先争优个人总结
2015/03/04 职场文书
学长教您写论文:经验总结
2019/07/09 职场文书