<?php
/**
* 向下调整函数(递归)
* @param $arr
* @param $i 非叶子节点
* @param $j 堆的最后一个节点位置
*/
function sift(&$arr, $i, $j)
{
$left = 2 * $i + 1; // 左孩子节点
$right = 2 * $i + 2; // 右孩子节点
$max = $i;
if ($left <= $j && $arr[$left] > $arr[$max]) {
$max = $left;
}
if ($right <= $j && $arr[$right] > $arr[$max]) {
$max = $right;
}
if ($max != $i) {
// 交换元素,父节点换成更大的数
$tmp = $arr[$i];
$arr[$i] = $arr[$max];
$arr[$max] = $tmp;
echo join(',', $arr) . "\n";
sift($arr, $max, $j); // 构建下一个非叶子节点
}
}
/**
* 向下调整函数(非递归)
* @param $arr
* @param $low 非叶子节点
* @param $high 堆的最后一个节点位置
*/
function sift2(&$arr, $low, $high)
{
$tmp = $arr[$low]; // 父节点位置的元素值
$i = $low;
$j = 2 * $i + 1; // 左孩子节点
while ($j <= $high) {
if (($j + 1 <= $high) && $arr[$j + 1] > $arr[$j]) {
// 如果有右孩子节点,并且比左孩子节点大
$j = $j + 1;
}
if ($arr[$j] > $tmp) {
// 孩子节点比父节点大,将更大的元素移到父节点
$arr[$i] = $arr[$j];
$i = $j; // 孩子节点做为下一个父节点继续构建
$j = 2 * $i + 1;
} else {
$arr[$i] = $tmp; // 孩子节点不比父节点大,停止循环,当前父节点移入初始父节点的元素值
break;
}
}
$arr[$i] = $tmp; // 叶子节点移入初始父节点的元素值
echo join(',', $arr) . "\n";
}
/**
* 堆排序
*/
function heap_sort(&$arr)
{
$len = count($arr);
if ($len <= 1) {
return;
}
// 构建大顶堆,从最后一个非叶子节点往上构建
for ($i = intval(($len - 1 - 1) / 2); $i >= 0; $i--) {
// sift($arr, $i, $len - 1);
sift2($arr, $i, $len - 1);
}
// exit;
for ($i = $len - 1; $i > 0; $i--) {
// 根节点与最后一个节点元素交换
$tmp = $arr[0];
$arr[0] = $arr[$i];
$arr[$i] = $tmp;
// sift($arr, 0, $i - 1);
sift2($arr, 0, $i - 1);
}
}
$arr = [1, 2, 3, 4, 5, 6, 7, 8, 9];
echo join(',', $arr) . "\n";
heap_sort($arr);
echo join(',', $arr) . "\n";
PHP堆排序,向下调整函数包含递归和非递归方法
最新推荐文章于 2024-07-26 17:57:56 发布