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 相关文章推荐
[原创]PHP中通过ADODB库实现调用Access数据库之修正版本
Dec 31 PHP
phpfans留言版用到的数据操作类和分页类
Jan 04 PHP
php为什么选mysql作为数据库? Mysql 创建用户方法
Jul 02 PHP
比较全的PHP 会话(session 时间设定)使用入门代码
Jun 05 PHP
Zend的MVC机制使用分析(一)
May 02 PHP
使用php判断网页是否gzip压缩
Jun 25 PHP
分享一个超好用的php header下载函数
Jan 31 PHP
PHP中file_get_contents高?用法实例
Sep 24 PHP
yii分页组件用法实例分析
Dec 28 PHP
PHP 网站修改默认访问文件的nginx配置
May 27 PHP
PHP迭代与递归实现无限级分类
Aug 28 PHP
php多进程并发编程防止出现僵尸进程的方法分析
Feb 28 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
php 正则匹配函数体
2009/08/25 PHP
发款php蜘蛛统计插件只要有mysql就可用
2010/10/12 PHP
PHP基础知识回顾
2012/08/16 PHP
php中读写文件与读写数据库的效率比较分享
2013/10/19 PHP
php之Smarty模板使用方法示例详解
2014/07/08 PHP
Javascript的IE和Firefox兼容性汇编
2006/07/01 Javascript
用js实现的自定义的对话框的实现代码
2010/03/21 Javascript
input 输入框获得/失去焦点时隐藏/显示文字(jquery版)
2013/04/02 Javascript
Egret引擎开发指南之创建项目
2014/09/03 Javascript
javascript结合Flexbox简单实现滑动拼图游戏
2016/02/18 Javascript
Bootstrap表单布局样式代码
2016/05/31 Javascript
Jquery揭秘系列:ajax原生js实现详解(推荐)
2016/06/08 Javascript
AngularJS实现单独作用域内的数据操作
2016/09/05 Javascript
微信小程序  网络请求API详解
2016/10/25 Javascript
node安装--linux下的快速安装教程
2017/03/21 Javascript
Angularjs根据json文件动态生成路由状态的实现方法
2017/04/17 Javascript
React.Js添加与删除onScroll事件的方法详解
2017/11/03 Javascript
ionic使用angularjs表单验证(模板验证)
2018/12/12 Javascript
nodejs基础之常用工具模块util用法分析
2018/12/26 NodeJs
Vue切换Tab动态渲染组件的操作
2020/09/21 Javascript
详解vue实现坐标拾取器功能示例
2020/11/18 Vue.js
[03:09]2014DOTA2国际邀请赛 Mushi前队友送上祝福
2014/07/12 DOTA
使用基于Python的Tornado框架的HTTP客户端的教程
2015/04/24 Python
Python中使用partial改变方法默认参数实例
2015/04/28 Python
用Python编写一个每天都在系统下新建一个文件夹的脚本
2015/05/04 Python
python实现的MySQL增删改查操作实例小结
2018/12/19 Python
对python中基于tcp协议的通信(数据传输)实例讲解
2019/07/22 Python
Python迷宫生成和迷宫破解算法实例
2019/12/24 Python
如何基于python3和Vue实现AES数据加密
2020/03/27 Python
python爬虫爬取图片的简单代码
2021/01/18 Python
亚洲领先的旅游体验市场:Voyagin
2019/11/23 全球购物
Java面试题:说出如下代码的执行结果
2015/10/30 面试题
个人求职简历的自我评价
2013/10/19 职场文书
检讨书1000字
2014/10/11 职场文书
入党介绍人意见范文
2015/06/01 职场文书
教你如何使用Python开发一个钉钉群应答机器人
2021/06/21 Python