PHP堆排序,向下调整函数包含递归和非递归方法

<?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";

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值