常用算法PHP版(三)- 快速排序

快速排序是对冒泡排序的一种改进。

快速排序大概是这样子滴:“第一部分的数组,基数的数组,第二部分的数组”组装成的一个数组。

每一次运行方法(调用或递归),小于基数的分为一部分,大于基数的分为另一部分。组装数组的时把基数放中间,就完成了排序。

下面这张图的红色柱子就是基数。它先把小于它的放左半部分,大于它的放右半部分,自己移到中间当中间值。
在这里插入图片描述
注意:本文是以低位下标键0作为基数,上图是以最高位键,这是不同的,所以不要把下面的代码和这个图做参考。

你会发现每一波代码的注释都不一样,那是因为整个排序流程我都注释了。

/**
 * 快速排序
 *
 * @param array $arr 数组
 * @return array
 */
function quickSort($arr)
{
    if (count($arr) > 1) { // 至少需要俩个,才有比对的必要
        $base = $arr[0]; // 基数

        $left = array(); // 设置一个空数组,等待接收小于基数的值
        $right = array(); // 设置一个空数组,等待接收大于基数的值

        for ($i = 1; $i < count($arr); $i++) { // 因为下标0已经被基数占用了,所以$i只能从1开始

            /**
             * 第一轮for循环,如果下标0的基数(1)小于下标1的值(4),条件符合,把下标1的值(4)赋给$right数组
             * 第二轮for循环,如果下标0的基数(1)小于下标2的值(3),条件符合,把下标2的值(3)赋给$right数组
             * 第三轮for循环,如果下标0的基数(1)小于下标3的值(5),条件符合,把下标3的值(5)赋给$right数组
             * 第四轮for循环,如果下标0的基数(1)小于下标4的值(2),条件符合,把下标4的值(2)赋给$right数组
             */
            if ($base < $arr[$i]) {
                $right[] = $arr[$i];
            } else {
                $left[] = $arr[$i]; // 把下标1的值(4)赋给$right数组
            }
        }

        $left = quickSort($left); // 因为数组为空,传进去后直接就返回了
        $right = quickSort($right); // $right = [4, 3, 5, 2]

        return array_merge($left, array($base), $right);
    } else {
        return $arr;
    }
}
$arr = [1, 4, 3, 5, 2];
var_dump(quickSort($arr));

上面的for运行结果为:$arr = [4, 3, 5, 2];

第一次递归传进方法中

/**
 * 第一次递归传进方法中
 *
 * $arr = [4, 3, 5, 2];
 */
function quickSort($arr)
{
    if (count($arr) > 1) {
        $base = $arr[0]; // 4

        $left = array();
        $right = array();

        for ($i = 1; $i < count($arr); $i++) {

            /**
             * 第一轮for循环,如果下标0的基数(4)小于下标1的值(3),条件不符合,进入else,把下标1的值(3)赋给$left数组
             * 第二轮for循环,如果下标0的基数(4)小于下标2的值(5),条件符合,把下标2的值(5)赋给$right数组
             * 第三轮for循环,如果下标0的基数(4)小于下标3的值(2),条件不符合,进入else,把下标3的值(2)赋给$left数组
             */
            if ($base < $arr[$i]) {
                $right[] = $arr[$i];
            } else {
                $left[] = $arr[$i];
            }
        }

        $left = quickSort($left); // $left = [3, 2];
        $right = quickSort($right); // 只有一个所以进去了直接返回了

        return array_merge($left, array($base), $right);
    } else {
        return $arr;
    }
}

第二次递归传进方法中


/**
 * 第二次递归传进方法中
 *
 * $arr = [3, 2];
 */
function quickSort($arr)
{
    if (count($arr) > 1) {
        $base = $arr[0]; // 3

        $left = array();
        $right = array();

        for ($i = 1; $i < count($arr); $i++) {

            /**
             * 第一轮for循环,如果下标0的基数(3)小于下标1的值(2),条件不符合,进入else,把下标1的值(2)赋给$left数组
             */
            if ($base < $arr[$i]) {
                $right[] = $arr[$i];
            } else {
                $left[] = $arr[$i];
            }
        }

        $left = quickSort($left); // 只有一个所以进去了直接返回了
        $right = quickSort($right); // 为空数组,所以进去了直接返回了

        return array_merge($left, array($base), $right); // 返回2与基数3组装的 [2, 3],往下看返回的第一次递归方法中
    } else {
        return $arr;
    }
}

回看第一次递归方法

第二次的递归返回给了第一次递归的方法[2, 3],返回给了$left = quickSort($left) 这一行。

而下面还有一行$right = quickSort($right)没有走完。它只有一个5,所以进去递归直接就返回了。

此时,第一层递归(看下面代码)的这个方法中,$left = [2, 3](第二次递归返回的),$base = [4](原本就存在于第一次递归方法中),$right = [5](看上面那段话),返回[2, 3, 4, 5]

以下代码是上面第一次递归的代码,方便你不用往上拉而已,没有改动。

/**
 * 第一次递归传进方法中
 *
 * $arr = [4, 3, 5, 2];
 */
function quickSort($arr)
{
    if (count($arr) > 1) {
        $base = $arr[0]; // 4

        $left = array();
        $right = array();

        for ($i = 1; $i < count($arr); $i++) {

            /**
             * 第一轮for循环,如果下标0的基数(4)小于下标1的值(3),条件不符合,进入else,把下标1的值(3)赋给$left数组
             * 第二轮for循环,如果下标0的基数(4)小于下标2的值(5),条件符合,把下标2的值(5)赋给$right数组
             * 第三轮for循环,如果下标0的基数(4)小于下标3的值(2),条件不符合,进入else,把下标3的值(2)赋给$left数组
             */
            if ($base < $arr[$i]) {
                $right[] = $arr[$i];
            } else {
                $left[] = $arr[$i];
            }
        }

        $left = quickSort($left); // $left = [3, 2];
        $right = quickSort($right); // 只有一个所以进去了直接返回了

        return array_merge($left, array($base), $right);
    } else {
        return $arr;
    }
}

第一次递归返回了[2, 3, 4, 5],其实就是返回给了原方法中的$right

此时,原方法(看下面的代码)$left = [] $base = [1] $right = [2, 3, 4, 5],组装完成 [1, 2, 3, 4, 5]

以下代码是最上面原方法的代码,方便你不用往上拉而已。

/**
 * 快速排序
 *
 * @param array $arr 数组
 * @return array
 */
function quickSort($arr)
{
    if (count($arr) > 1) { // 至少需要俩个,才有比对的必要
        $base = $arr[0]; // 基数

        $left = array(); // 设置一个空数组,等待接收小于基数的值
        $right = array(); // 设置一个空数组,等待接收大于基数的值

        for ($i = 1; $i < count($arr); $i++) { // 因为下标0已经被基数占用了,所以$i只能从1开始

            /**
             * 第一轮for循环,如果下标0的基数(1)小于下标1的值(4),条件符合,把下标1的值(4)赋给$right数组
             * 第二轮for循环,如果下标0的基数(1)小于下标2的值(3),条件符合,把下标2的值(3)赋给$right数组
             * 第三轮for循环,如果下标0的基数(1)小于下标3的值(5),条件符合,把下标3的值(5)赋给$right数组
             * 第四轮for循环,如果下标0的基数(1)小于下标4的值(2),条件符合,把下标4的值(2)赋给$right数组
             */
            if ($base < $arr[$i]) {
                $right[] = $arr[$i];
            } else {
                $left[] = $arr[$i]; // 把下标1的值(4)赋给$right数组
            }
        }

        $left = quickSort($left); // 因为数组为空,传进去后直接就返回了
        $right = quickSort($right); // $right = [4, 3, 5, 2]

        return array_merge($left, array($base), $right);
    } else {
        return $arr;
    }
}

你最好自己组装一个乱序的数组,然后重新心读一遍。

总结:
如果要你写,你就贯彻:小于基数的数值,就赋给left,大于就赋给right。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值