php实现归并排序

来源:互联网 发布:yum配置文件 编辑:程序博客网 时间:2024/06/08 00:43

归并排序是建立在归并操作上的一种有效的排序算法。该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。

首先考虑下如何将将二个有序数列合并。这个非常简单,只要从比较二个数列的第一个数,谁小就先取谁,取了后就在对应数列中删除这个数。然后再进行比较,如果有数列为空,那直接将另一个数列的数据依次取出即可。

<?phpfunction mergearray($a,$b){    $a_point = 0;//可以理解为指向a的第一个位置    $b_point = 0;    $a_length = count($a);//a的长度    $b_length = count($b);    $tmp = array();//一个临时数组来合并这两个数组    $t_point = 0;    while($a_point < $a_length && $b_point < $b_length){        if($a[$a_point] < $b[$b_point]){            $tmp[$t_point++] = $a[$a_point++];        }else{            $tmp[$t_point++] = $b[$b_point++];        }    }    //哪一个有序列还有剩余,直接追加到tmp数组后面    while($a_point < $a_length){        $tmp[$t_point++] = $a[$a_point++];    }    while($b_point < $b_length){        $tmp[$t_point++] = $b[$b_point++];    }    return $tmp;}$a = array(12,36,43,44,59,62);$b = array(7,35,52,85,94);$merge = mergearray($a,$b);var_dump($merge)?>

再换一个问题,如果有序列b追加到有序列a的后面,变成只有一个序列$a = array(12,36,43,44,59,62,7,35,52,85,94); 那怎么进行归并排序?
我们仍可以用下标来将它分成两个有序列,第一个有序列从下标$a[0]$a[5],第二个有序列从$a[6]$a[10]
所以我们需要找到分成这两个有序列的中点的下边标,即下标5或者是下标6.
先不急,先假设这个中点下标是已知的:

<?phpfunction mergearray($a,$first,$mid,$last){    $a_point = $first;//指向有序列的第一个下标    $a_end = $mid;//该有序列的终点下标    $b_point = $mid+1;    $b_end = $last;    $tmp = array();//一个临时数组来合并这两个数组    $t_point = 0;    while($a_point <= $a_end && $b_point <= $b_end){//注意判断条件的等于号        if($a[$a_point] < $a[$b_point]){            $tmp[$t_point++] = $a[$a_point++];        }else{            $tmp[$t_point++] = $a[$b_point++];        }    }    while($a_point <= $a_end){        $tmp[$t_point++] = $a[$a_point++];    }    while($b_point <= $b_end){        $tmp[$t_point++] = $a[$b_point++];    }    return $tmp;}$a = array(12,36,43,44,59,62,7,35,52,85,94);$merge = mergearray($a,0,5,count($a)-1);var_dump($merge)?>?>

到目前为止,所做的操作只是归并中的并操作(合并),那什么归操作
归操作就是递归地把一个序列分成两组,再将每一组再分成两组,依次类推,当分出来的小组只有一个数据时,可以认为这个小组组内已经达到了有序,然后再合并相邻的二个小组就可以了。这样通过先递归的分解数列,再合并数列就完成了归并排序
php实现:

<?phpfunction mergearray(&$arr,&$tmp,$first,$mid,$last){    $first_start = $first;    $first_end = $mid;    $last_start = $mid+1;    $last_end = $last;    $t = $first;    while($first_start<=$first_end&&$last_start<=$last_end){        if($arr[$first_start] < $arr[$last_start]){            $tmp[$t++] = $arr[$first_start++];        }else{            $tmp[$t++] = $arr[$last_start++];        }    }    while($first_start<=$first_end){        $tmp[$t++] = $arr[$first_start++];    }    while($last_start <= $last_end){        $tmp[$t++] = $arr[$last_start++];    }    for($i = $first; $i <= $last; $i++){        $arr[$i] = $tmp[$i];    }}function mergesort(&$arr,&$tmp,$first,$last){    if($first < $last){        $mid = (int)(($first+$last)/2);        mergesort($arr,$tmp,$first,$mid);        mergesort($arr,$tmp,$mid+1,$last);        mergearray($arr,$tmp,$first,$mid,$last);    }}$arr = array(44,12,59,36,62,43,94,7,35,52,85);$tmp = array();mergesort($arr,$tmp,0,count($arr)-1);unset($tmp);//释放tmpvar_dump($arr);

归并排序的效率是比较高的,设数列长为N,将数列分开成小数列一共要logN步,每步都是一个合并有序数列的过程,时间复杂度可以记为O(N),故一共为O(N*logN)。因为归并排序每次都是在相邻的数据中进行操作,所以归并排序在O(N*logN)的几种排序方法(快速排序,归并排序,希尔排序,堆排序)也是效率比较高的。


参考资料:
白话经典算法系列之五 归并排序的实现

0 0
原创粉丝点击