归并(Merge)排序法是将两个(或两个以上)有序表合并成一个新的有序表。归并排序的一个缺点是它需要存储器有另一个大小等于数据项数目的数组。如果初始数组几乎占满整个存储器,那么归并排序将不能工作,但是如果有足够的空间,归并排序会是一个很好的选择。

假设待排序的序列:

4 3 7 9 2 8 6

先说思路,归并排序的中心思想是将两个已经排序好的序列,合并成一个排序的序列。

上面的序列可以分成:

4 3 7 9

2  8  6

这两个序列,然后对这两个序列分别排序:结果为:

设置为序列A,与序列B,

3 4 7 9

2  6  8

将上面的两个序列 合并成一个排序好的序列:

合并的具体思路是:

设置两个位置指示器,分别指向序列A与序列B开始的位置:红色为指示器指向位置:

3 4 7 9

2  6  8

比较两个指示器所指向的元素的值,将较小的插入到一个新的数组内,例如序列C,同时将对应的指示器向后移动一位:

结果为:

3 4 7 9

2  6  8

形成的序列C:已经被插入一个元素了,刚才较小的 元素2.

2

然后 再次 比较序列A与序列B中指示器所指向的元素:将小的放入到序列C中,移动相应指针,结果为:

3 47 9

2  6 8

2  3

以此类推,迭代执行,直到序列A或者序列B中某个指示器已经移到到数组末端。例如:

多次比较后,序列B已经将指示器移出到序列末端(最后一个元素之后)了。

3 4 792  6  8

2 3 4 6 7 8

然后将没有用完的序列,这里面是序列A中其余的元素全部插入到序列C的后边即可,就剩下一个9 了,将其插入到序列C后即可:

序列C结果:

2 3 4 5 6 7 8 9

这样就实现了将两个有序序列合并成一个有序序列的操作,

下面先看这个合并的php代码:

/**

* 将两个有序数组合并成一个有序数组

* @param $arrA,

* @param $arrB,

* @reutrn array合并好的数组

*/

function mergeArray($arrA, $arrB) {

$a_i = $b_i = 0;//设置两个起始位置标记

$a_len = count($arrA);

$b_len = count($arrB);

while($a_i

//当数组A和数组B都没有越界时

if($arrA[$a_i] < $arrB[$b_i]) {

$arrC[] = $arrA[$a_i++];

} else {

$arrC[] = $arrB[$b_i++];

}

}

//判断 数组A内的元素是否都用完了,没有的话将其全部插入到C数组内:

while($a_i < $a_len) {

$arrC[] = $arrA[$a_i++];

}

//判断 数组B内的元素是否都用完了,没有的话将其全部插入到C数组内:

while($b_i < $b_len) {

$arrC[] = $arrB[$b_i++];

}

return $arrC;

}

经过上面的分析和程序的实现,我们不难发现,合并已排序的序列的时间应该是线性的,就是说,最多会发生N-1次比较,其中N是所有元素之和。

通过上面的描述,我们实现了将两个排序好的数组进行和并的过程。

此时,大家可能会有疑问,这个和归并排序整个序列有什么关系?或者你是如何能够得到最开始的两个排序好的子序列的呢?

下面,我们就来描述以下什么是归并排序,然后再看,上面的合并与归并排序的关系是如何的:

大家不妨去想,当我们需要排序如下的数组时,我们是否可以先将数组的前半部分与数组的后半部分分别进行归并排序,然后将排序的结果合并起来呢?

例如:待排序的数组:

4 3 7 9 2 8 6

先分成2部分:

4 3 7 9

2 8 6

将前半部分 与 后半部分 分别看成一个序列,再次进行归并(就是拆分,排序,合并)操作

就会变成:

前:

4 3

7 9

后:

2 8

6

同样  再对每个自序列进行 归并排序,再次(拆分,排序,合并)。

当拆分的子序列内只存在一个元素(长度为1)时,那么这个序列就不必再拆分了,就是一个排序好的数组了。然后将这个序列,与其他的序列再合并到一起即可,最终就将所有的都合并好了,成为一个完整的排序好的数组。

程序实现:

通过上面的描述 大家应该想到,可以使用递归程序来实现这个程序设计吧:

想要实现这个程序,可能需要解决如下问题:

怎么将数组做拆分:

设定两个指示器,一个指向数组开始假定为$left,一个指向数组最后一个元素$right:

4 3 7 9 2 8 6

然 后判断 $left 是否小于$right,如果小于,说明这个序列内元素个数大于一个,就将其拆分成两个数组,拆分的方式是生成一个中间的指示器$center,值 为$left + $right /2 整除。结果为:3,然后将$left 到$center 分成一组,$center+1到$right分成一组:

4 3 7 92 8 6接下来,递归的 利用$left, $center, $center+1, $right分别做为 两个序列的 左右指示器,进行操作。知道数组内有一个元素$left==$right .然后按照上面的合并数组即可:

/**

* mergeSort 归并排序

* 是开始递归函数的一个驱动函数

* @param &$arr array 待排序的数组

*/

function mergeSort(&$arr) {

$len = count($arr);//求得数组长度

mSort($arr, 0, $len-1);

}

/**

* 实际实现归并排序的程序

* @param &$arr array 需要排序的数组

* @param $left int 子序列的左下标值

* @param $right int 子序列的右下标值

*/

function mSort(&$arr, $left, $right) {

if($left < $right) {

//说明子序列内存在多余1个的元素,那么需要拆分,分别排序,合并

//计算拆分的位置,长度/2 去整

$center = floor(($left+$right) / 2);

//递归调用对左边进行再次排序:

mSort($arr, $left, $center);

//递归调用对右边进行再次排序

mSort($arr, $center+1, $right);

//合并排序结果

mergeArray($arr, $left, $center, $right);

}

}

/**

* 将两个有序数组合并成一个有序数组

* @param &$arr, 待排序的所有元素

* @param $left, 排序子数组A的开始下标

* @param $center, 排序子数组A与排序子数组B的中间下标,也就是数组A的结束下标

* @param $right, 排序子数组B的结束下标(开始为$center+1)

*/

function mergeArray(&$arr, $left, $center, $right) {

//设置两个起始位置标记

$a_i = $left;

$b_i = $center+1;

while($a_i<=$center && $b_i<=$right) {

//当数组A和数组B都没有越界时

if($arr[$a_i] < $arr[$b_i]) {

$temp[] = $arr[$a_i++];

} else {

$temp[] = $arr[$b_i++];

}

}

//判断 数组A内的元素是否都用完了,没有的话将其全部插入到C数组内:

while($a_i <= $center) {

$temp[] = $arr[$a_i++];

}

//判断 数组B内的元素是否都用完了,没有的话将其全部插入到C数组内:

while($b_i <= $right) {

$temp[] = $arr[$b_i++];

}

//将$arrC内排序好的部分,写入到$arr内:

for($i=0, $len=count($temp); $i

$arr[$left+$i] = $temp[$i];

}

}

//do some test:

$arr = array(4, 7, 6, 3, 9, 5, 8);

mergeSort($arr);

print_r($arr);

注意上面的代码带排序的数组都使用的是 引用传递,为了节约空间。

而且,其中的合并数组的方式也为了节约空间做了相对的修改,把所有的操作都放到了$arr上完成,引用传递节约资源。

好了 上面的代码就完成了归并排序,归并排序的时间复杂度为O(N*LogN) 效率还是相当客观的。

再说,归并排序算法,中心思想是 将一个复杂问题分解成相似的小问题,再把小问题分解成更小的问题,直到分解到可以马上求解为止,然后将分解得到的结果再合并起来的一种方法。这个思想用个 成语形容叫化整为零。 放到计算机科学中有个专业属于叫分治策略(分治发)。分就是大问题变小问题,治就是小结果合并成大结果。

分治策略是很多搞笑算法的基础,我们在讨论快速排序时,也会用到分治策略的。

最后简单的说一下这个算法,虽然这个算法在时间复杂度上达到了O(NLogN)。但是还是会有一个小问题,就是在合并两个数组时,如果数组的总元素个数为 N,那么我们需要再开辟一个同样大小的空间来保存合并时的数据(就是mergeArray中的$temp数组),而且还需要将数据有$temp拷贝 会$arr,因此会浪费一些资源。因此在实际的排序中还是 相对的较少使用。

php 归并排序,详解PHP归并排序的实现相关推荐

  1. 归并排序详解(python实现)

    归并排序详解(python实现) 因为上个星期leetcode的一道题(Median of Two Sorted Arrays)所以想仔细了解一下归并排序的实现.

  2. 归并排序详解(Acwing 归并排序y总模板)

    归并排序详解 文章目录 归并排序过程 demo(完整y总模板) 结束语 每个人心里都有一团火,路过的人却只看见了烟.加油xdm!!! 归并排序过程 基础知识:我们知道归并排序也是一种基于分治法思想的排 ...

  3. 归并排序过程实现c语言,C语言归并排序详解

    C语言归并排序详解 发布日期:2015-12-31 11:16 来源: 标签: 编程语言 C教程 C语言归并排序 C语言归并排序算法 本章我们主要学习C语言实现排序算法之归并排序,对归并排序的原理及实 ...

  4. 归并排序详解(Java语言描述 萌新向)

    目录 一,归并排序简介 二,归并排序原理 三,归并排序图解 1,归并总体的图解 2,合并两个子组的流程 3,归并排序动画演示 四,归并排序代码实现与分析(Java) 1,方法的合集 2,Merge类各 ...

  5. 数据结构排序系列详解之七 归并排序

    在前面说的那几种排序都是将一组记录按关键字大小排成一个有序的序列,而归并排序的思想是:基于合并,将两个或两个以上有序表合并成一个新的有序表 归并排序算法:假设初始序列含有n个记录,首先将这n个记录看成 ...

  6. mergesort java_归并排序详解(MergeSort)递归和非递归实现

    归并排序的概念及定义 归并排序(Merge)是将两个(或两个以上)有序表合并成一个新的有序表,即把待排序序列分为若干个子序列,每个子序列是有序的.然后再把有序子序列合并为整体有序序列. 归并排序是建立 ...

  7. c语言归并排序代码详细注释,C语言实现排序算法之归并排序详解

    排序算法中的归并排序(Merge Sort)是利用"归并"技术来进行排序.归并是指将若干个已排序的子文件合并成一个有序的文件. 一.实现原理: 1.算法基本思路 设两个有序的子文件 ...

  8. python 归并排序(详解)

    一.归并排序 归并排序(MERGE-SORT)是建立在归并操作上的一种有效的排序算法,该算法采用经典的分治(divide-and-conquer)策略(分治法将问题分(divide)成一些小的问题然后 ...

  9. 举例详解PHP归并排序的实现

    来源:https://blog.phpha.com/backup/archives/1683.html 归并(Merge)排序法是将两个(或两个以上)有序表合并成一个新的有序表,即把待排序序列分为若干 ...

最新文章

  1. SPOJ375(树链剖分)
  2. 将存储过程的返回值赋给变量
  3. mybatis动态sql中where标签的使用
  4. 【Android 插件化】“ 插桩式 “ 插件化框架 ( 类加载器创建 | 资源加载 )
  5. 唐岩自述奋斗史:从娄底青年到陌陌上市
  6. 全排列(我开始怀疑自己的智商了....)
  7. 58.配置tomcat监听80 虚拟主机 日志
  8. python蓝牙编程_蓝牙编程经典程序!
  9. 数据转移-从MySQL到Hive
  10. 2022年全新美观的春节倒计时代码
  11. 工作那些事(三十一)怎样带好一个项目团队
  12. bash脚本使用记录
  13. CVE-2012-0158 MSCOMCTL控件漏洞分析
  14. 苹果鼠标右键怎么按_IOS13.4更新后的鼠标用途在哪?
  15. 站在巨人的肩膀上-听课感想
  16. SD SDHC SDXC
  17. [附源码]java毕业设计流浪宠物免费领养系统
  18. BLDC-坐标变换(Clark,Park,反Park)
  19. 网友推荐2010年央视春晚节目单 恶搞社会热点
  20. 2016谷歌重返中国,体验Google中国开发者网站

热门文章

  1. 为什么要学习 Markdown?究竟有什么用?
  2. 漫画:什么是公有云、私有云和混合云?
  3. IslandViewer4|基因组岛在线预测
  4. 序列处理工具|Seqkit
  5. R语言中这些你想知道含义又不知道怎么查的特殊符号
  6. Nature 子刊:三代测序的DNA提取和宏基因组学分析
  7. R语言ggplot2可视化:使用geom_line函数将dataframe中数据可视化为时间序列(或折线图)(Time Series Plot From a Data Frame)、添加标题、副标题
  8. Python基于MASK信息抽取ROI子图并构建基于迁移学习(densenet)的图像分类器实战(原始影像和mask文件都是二维的情况)
  9. pandas使用组合条件筛选、过滤数据行
  10. 为Jupyter notebook配置R kernel过程及踩坑记录