用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;