算法学习(三):归并排序与逆序对求解

用php实现一个归并排序算法,并基于归并排序思想求解逆序对数目。

1. 归并排序:自顶向下

//自顶向下归并排序:分而治之
function mergeSortUD(&$a,$s=0,$e=null){//注意此处传引用,否则发生写时赋值
    if(!isset($e)){
        $e = count($a) - 1;
    }
    if(count($a) < 1 || $s >= $e || $s < 0 || $e >= count($a)){
        return;
    }
    $mid = $s + floor(($e - $s) / 2);//注意此处取整数,否则$mid为浮点数
    mergeSortUD($a,$s,$mid);
    mergeSortUD($a,$mid+1,$e);
    merge($a,$s,$mid,$e);
}
function merge(&$a,$s,$mid,$e){
    $m = [];
    $ms = 0;
    $i = $s;
    $j = $mid+1;
    while($i <= $mid && $j <= $e){
        if($a[$i] < $a[$j]){
            $m[$ms++] = $a[$i++];
        }elseif($a[$i] == $a[$j]){
            $m[$ms++] = $a[$i++];
            $m[$ms++] = $a[$j++];
        }else{
            $m[$ms++] = $a[$j++];
        }
    }
    while($i <= $mid){
        $m[$ms++] = $a[$i++];
    }
    while($j <= $e){
        $m[$ms++] = $a[$j++];
    }
    //将排好序的子区间复制到原数组
    foreach($m as $k => $v){
        $a[$s++] = $v;
    }
}
$a = [9,8,7,6,5,4,3,2,1,0];
mergeSortUD($a);
var_dump($a);

2.归并排序:自底向上

//自底向上归并排序:从局部到整体
function mergeSortDU(&$a,$s=0,$e=null){
    if(!isset($e)){
        $e = count($a) - 1;
    }
    if(count($a) < 1 || $s >= $e || $s < 0 || $e >= count($a)){
        return;
    }
    
    $size = 1;
    $maxSize = count($a);
    while($size <= $maxSize){
        $i = $s;
        while($i <= $e){
            merge($a,$i,min($i+$size-1,$e),min($i+2*$size-1,$e));
            $i = $i+2*$size;
        }
        $size = $size * 2;
    }
}
$a = [9,8,7,6,5,4,3,2,1,0];
mergeSortDU($a);
var_dump($a);

3. 求解逆序对数

借用自顶向下归并排序的思想,每次merge逐个比较子区间元素大小时,若左子区间的元素大于右子区间元素值,则逆序对数累加。

function rmergeSort($a,$s,$e){
    if(count($a) < 1 || $s >= $e || $s < 0 || $e >= count($a)){
        return;
    }
    $mid = $s + floor(($e - $s) / 2);//注意此处取整数,否则$mid为浮点数
    rmergeSort($a,$s,$mid);
    rmergeSort($a,$mid+1,$e);
    rmerge($a,$s,$mid,$e);
}
function rmerge(&$a,$s,$mid,$e){
    global $reverseCount;
    $m = [];
    $ms = 0;
    $i = $s;
    $j = $mid+1;
    while($i <= $mid && $j <= $e){
        if($a[$i] < $a[$j]){
            $m[$ms++] = $a[$i++];
        }elseif($a[$i] == $a[$j]){
            $m[$ms++] = $a[$i++];
            $m[$ms++] = $a[$j++];
        }else{
            $reverseCount++;//找到逆序对
            $m[$ms++] = $a[$j++];
        }
    }
    while($i <= $mid){
        $m[$ms++] = $a[$i++];
    }
    while($j <= $e){
        $m[$ms++] = $a[$j++];
    }
    //将排好序的子区间复制到原数组
    foreach($m as $k => $v){
        $a[$s++] = $v;
    }
}
$reverseCount = 0; $a = [9,8,7,6,5,4,3,2,1,0]; rmergeSort($a,0,9); var_dump($a); echo '逆序对数目:'.$reverseCount;
原文地址:https://www.cnblogs.com/ling-diary/p/9401775.html