PHP排序算法之归并排序(Merging Sort)实例详解


Posted in PHP onApril 21, 2018

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

基本思想:

归并排序:就是利用归并(合并)的思想实现的排序方法。它的原理是假设初始序列含有 n 个元素,则可以看成是 n 个有序的子序列,每个子序列的长度为 1,然后两两归并,得到 ⌈ n / 2⌉ (⌈ x ⌉ 表示不小于 x 的最小整数)个长度为 2 或 1 的有序序列;再两两归并,······,如此重复,直至得到一个长度为 n 的有序序列为止,这种排序方法就成为 2 路归并排序。

一、归并的过程:

a[i] 取 a 数组的前部分(已经排好序),a[j] 取 a 数组的后部分(已经排好序)

r 数组存储排好序的 a 数组

比较 a[i]和 a[j] 的大小,若 a[i] ≤ a[j],则将第一个有序表中的元素 a[i] 复制到 r[k] 中,并令 i 和 k 分别加上 1;否则将第二个有序表中的元素 a[j] 复制到 r[k] 中,并令 j 和 k 分别加上 1,如此循环下去,直到其中一个有序表取完,然后再将另一个有序表中剩余的元素复制到 r 中从下标 k 到下标 t 的单元。归并排序的算法我们通常用递归实现,先把待排序区间 [s,t] 以中点二分,接着把左边子区间排序,再把右边子区间排序,最后把左区间和右区间用一次归并操作合并成有序的区间 [s,t]。

二、归并操作:

归并操作(merge),也叫归并算法,指的是将两个顺序序列合并成一个顺序序列的方法。

如 设有数列{6,202,100,301,38,8,1}

初始状态:6 , 202 , 100 , 301 , 38 , 8,1

第一次归并后:{6,202},{100,301},{8,38},{1},比较次数:3;

第二次归并后:{6,100,202,301},{1,8,38},比较次数:4;

第三次归并后:{1,6,8,38,100,202,301},比较次数:4;

总的比较次数为:3+4+4=11,;

逆序数为14;

三、算法描述:

归并操作的工作原理如下:

第一步:申请空间,使其大小为两个已经排序序列之和,该空间用来存放合并后的序列

第二步:设定两个指针,最初位置分别为两个已经排序序列的起始位置

第三步:比较两个指针所指向的元素,选择相对小的元素放入到合并空间,并移动指针到下一位置

重复步骤3直到某一指针超出序列尾

将另一序列剩下的所有元素直接复制到合并序列尾

PHP排序算法之归并排序(Merging Sort)实例详解

算法实现:

我们先来看看主函数部分:

//交换函数
function swap(array &$arr,$a,$b){
  $temp = $arr[$a];
  $arr[$a] = $arr[$b];
  $arr[$b] = $temp;
}
//归并算法总函数
function MergeSort(array &$arr){
  $start = 0;
  $end = count($arr) - 1;
  MSort($arr,$start,$end);
}

在总函数中,我们只调用了一个 MSort() 函数,因为我们要使用递归调用,所以将 MSort() 封装起来。

下面我们来看看 MSort() 函数:

function MSort(array &$arr,$start,$end){
  //当子序列长度为1时,$start == $end,不用再分组
  if($start < $end){
    $mid = floor(($start + $end) / 2); //将 $arr 平分为 $arr[$start - $mid] 和 $arr[$mid+1 - $end]
    MSort($arr,$start,$mid);  //将 $arr[$start - $mid] 归并为有序的$arr[$start - $mid]
    MSort($arr,$mid + 1,$end);  //将 $arr[$mid+1 - $end] 归并为有序的 $arr[$mid+1 - $end]
    Merge($arr,$start,$mid,$end);    //将$arr[$start - $mid]部分和$arr[$mid+1 - $end]部分合并起来成为有序的$arr[$start - $end]
  }
}

上面的 MSort() 函数实现将数组分半再分半(直到子序列长度为1),然后将子序列合并起来。

现在是我们的归并操作函数 Merge() :

//归并操作
function Merge(array &$arr,$start,$mid,$end){
  $i = $start;
  $j=$mid + 1;
  $k = $start;
  $temparr = array();
  while($i!=$mid+1 && $j!=$end+1)
  {
    if($arr[$i] >= $arr[$j]){
      $temparr[$k++] = $arr[$j++];
    }
    else{
      $temparr[$k++] = $arr[$i++];
    }
  }
  //将第一个子序列的剩余部分添加到已经排好序的 $temparr 数组中
  while($i != $mid+1){
    $temparr[$k++] = $arr[$i++];
  }
  //将第二个子序列的剩余部分添加到已经排好序的 $temparr 数组中
  while($j != $end+1){
    $temparr[$k++] = $arr[$j++];
  }
  for($i=$start; $i<=$end; $i++){
    $arr[$i] = $temparr[$i];
  }
}

到了这里,我们的归并算法就完了。我们调用试试:

$arr = array(9,1,5,8,3,7,4,6,2);
MergeSort($arr);
var_dump($arr);

运行结果:

array(9) {
 [0]=>
 int(1)
 [1]=>
 int(2)
 [2]=>
 int(3)
 [3]=>
 int(4)
 [4]=>
 int(5)
 [5]=>
 int(6)
 [6]=>
 int(7)
 [7]=>
 int(8)
 [8]=>
 int(9)
}

复杂度分析:

由于归并算法无论原来的序列是否有序都会进行分组和比较,因此它的最好、最坏、平均的时间复杂度都是 O(nlogn)

归并算法是一种稳定的排序算法。

本文参考自《大话数据结构》,在此仅作记录,方便以后查阅,大神勿喷!

PHP 相关文章推荐
PHP动态图像的创建
Oct 09 PHP
php获取bing每日壁纸示例分享
Feb 25 PHP
使用PHP和HTML5 FormData实现无刷新文件上传教程
Sep 06 PHP
php设置页面超时时间解决方法
Sep 22 PHP
php set_include_path函数设置 include_path 配置选项
Oct 30 PHP
深入理解Yii2.0乐观锁与悲观锁的原理与使用
Jul 26 PHP
PHP实现将几张照片拼接到一起的合成图片功能【便于整体打印输出】
Nov 14 PHP
php无限级评论嵌套实现代码
Apr 18 PHP
thinkphp5使用无限极分类
Feb 18 PHP
解决tp5在nginx下修改配置访问的问题
Oct 16 PHP
php获取是星期几的的一些常用姿势
Dec 15 PHP
基于PHP实现用户在线状态检测
Nov 10 PHP
PHP排序算法之快速排序(Quick Sort)及其优化算法详解
Apr 21 #PHP
Laravel模型间关系设置分表的方法示例
Apr 21 #PHP
PHP排序算法之基数排序(Radix Sort)实例详解
Apr 21 #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
You might like
PHP伪静态写法附代码
2008/06/20 PHP
给ECShop添加最新评论
2015/01/07 PHP
浅析THINKPHP的addAll支持的最大数据量
2015/02/03 PHP
十幅图告诉你什么是PHP引用
2015/02/22 PHP
php跨服务器访问方法小结
2015/05/12 PHP
PHP实现事件机制实例分析
2015/06/26 PHP
使用PHPWord生成word文档的方法详解
2019/06/06 PHP
phpstorm激活码2020附使用详细教程
2020/09/25 PHP
&amp;lt;script defer&amp;gt; defer 是什么意思
2009/05/10 Javascript
生成二维码方法汇总
2014/12/26 Javascript
基于jQuery倾斜打开侧边栏菜单特效代码
2015/09/15 Javascript
AngularJS基础 ng-cut 指令介绍及简单示例
2016/08/01 Javascript
javascript经典特效分享 手风琴、轮播图、图片滑动
2016/09/14 Javascript
flexslider.js实现移动端轮播
2017/02/05 Javascript
解决vue-cli脚手架打包后vendor文件过大的问题
2018/09/27 Javascript
Vue实现移动端页面切换效果【推荐】
2018/11/13 Javascript
Vue.js 中 axios 跨域访问错误问题及解决方法
2018/11/21 Javascript
Vue.js计算机属性computed和methods方法详解
2019/10/12 Javascript
vue 解决addRoutes多次添加路由重复的操作
2020/08/04 Javascript
Python tornado队列示例-一个并发web爬虫代码分享
2018/01/09 Python
Python基于多线程操作数据库相关问题分析
2018/07/11 Python
Python高级编程之消息队列(Queue)与进程池(Pool)实例详解
2019/11/01 Python
使用Python制作缩放自如的圣诞老人(圣诞树)
2019/12/25 Python
Python日期格式和字符串格式相互转换的方法
2020/02/18 Python
Python面向对象魔法方法和单例模块代码实例
2020/03/25 Python
Python实现七个基本算法的实例代码
2020/10/08 Python
分享29个基于Bootstrap的HTML5响应式网页设计模板
2015/11/19 HTML / CSS
html5教你做炫酷的碎片式图片切换 (canvas)
2017/07/28 HTML / CSS
德国知名健康零食网上商店:Seeberger
2017/07/27 全球购物
俄罗斯金苹果网上化妆品和香水商店:Goldapple
2019/12/01 全球购物
自考生毕业自我鉴定
2013/10/10 职场文书
淘宝客服专员岗位职责
2014/04/11 职场文书
党员群众路线剖析材料
2014/10/08 职场文书
出纳工作检讨书范文
2014/12/27 职场文书
婚礼领导致辞大全
2015/07/28 职场文书
Java 死锁解决方案
2022/05/11 Java/Android