为了账号安全,请及时绑定邮箱和手机立即绑定

常用的排序算法(五)--选择排序以及优化(PHP实现)

常用的排序算法系列


选择排序以及优化

选择排序也是一种常用的简单的排序算法,虽然算法的复杂度是和冒泡一样都是O(n^2),但性能还是稍微好一些的,在一些简单的场景中选择排序非常好用。

假设当前需要进行排序,选择排序的核心思路是,找到一个最大或者最小的标记位,将其与当前需要排序的位置交换他们的值,这样的交换就会比冒泡更加有效率。

举例说明:
假设当前需要排序的数组如下:
[ 34, 5, 555,14, 88, 5 ]

首先我们要用一个循环来遍历这个数组,用来做排序的位置交换。
默认呢,假设当前取到的第一个数字是最小的,我们记录下编号即可,后面找到真正的最小值编号我们再更新即可。

第一次我们取第一个数 34 作为当前的最小值,记录下他的 最小值编号 0。

接着,我们要再用一个循环,去找数组后面部分的需要交换的位置(也就是找到真正的最小值编号),当前排序的,是编号0位置,因此我们从编号1开始往后找,如果发现后面有小于等于编号位置的值,我们就更新这个最小值编号

往后找,发现 5 比 34 小,于是最小值编号就变成了1 。
继续往后找,发现编号5的5等于当前最小值5,于是最小值编号就变成了5 。

最后,我们来判断一下最小值编号和最开始有没有变化,如果有变化,说明找到了一个更小的数再后面,那就应该进行交换操作把它弄到前面来。如果没有变化,就是说后面没有更小的了,我们不需要交换了。往后开始排下一个位置即可。

此时最小值编号是5,已经不等于最开始我需要排序的位置0了,所以我们进行一个交换,得到的结果为:

[ 34, 5, 555,14, 88, 5 ] --> 排序一次后–> [ 5, 5, 555,14, 88, 34 ]

完成之后,我们排下一个位置,也就是位置编号1,重复上面的步骤即可。

位置1的5,找不到更小的,不理
[ 5,5, 555,14, 88, 34 ]

位置2的555,与位置5的34交换
[ 5, 5, 555,14, 88, 34 ] --> [ 5, 5, 34 ,14, 88, 555 ]

位置3的14,找不到更小的,不理
[ 5, 5, 34 ,14, 88, 555 ]

位置4的88,找不到更小的,不理
[ 5, 5, 34 ,14, 88, 555 ]

位置5的555,找不到更小的。不理
[ 5, 5, 34 ,14, 88,** 555** ]

这样我们就完成了排序的过程。写程序的时候要特别注意这个编号的概念,我们的目的是为了找编号,然后将对应标号的值去做交换,并不是直接去用这个最小值。

PHP实现排序过程如下:

优化

可以看出,我们通过找最小值的下标编号,来减少中间不必要的数组元素交换操作,而我们每次只是标记一个最小的值,通过一个方向来排序。

因为最大最小其实是一个对称的操作判断,有没有方式可以更快完成这个流程呢?

当然是有的,我们可以把原来单路的选择排序,改成双路的,每次标记一个最小和一个最大的值,通过两个方向来排序。

每次排序的进行两个标记,一个是找出范围里的最大值,另一个是找出范围里的最小值,相当于是同时在做一个两个方向的排序,每次排序能稳定的排出来两个值。

下一次循环的时候,缩减查找的排序范围,左边界的值加一,右边界的值减一,直到相遇。

这里其实就有一点点快排的味道出来了,快排是有分治思想在里面的,所以会更加快。

PHP排序过程如下:

代码

PHP选择排序

<?php
/**
 * Created by PhpStorm.
 * User: L
 * Date: 2018-9-27
 * Time: 11:29
 */

$ar = [5, 8, 6, 4, 12, 5, 3, 1, 89, 54];

echo "input: <br/>";
print_r(json_encode($ar));
echo "<br/>";

selection($ar);

echo "result: <br/>";
print_r(json_encode($ar));
echo "<br/>";

/** 选择排序
 * @param array $ar
 * @param null $len
 */
function selection(array & $ar, $len = null)
{
    if ($len === null) {
        $len = sizeof($ar);
    }

    for ($i = 0; $i < $len - 1; $i++) {
        $min = $i; //consider i as min_index

        for ($j = $i + 1; $j < $len; $j++) {//find min_index
            if($ar[$j]<=$ar[$min]){
                $min = $j;
            }
        }
        //check min_index and swap
        if($min!=$i){//changeSelectionSort.php
            $t = $ar[$i];
            $ar[$i]=$ar[$min];
            $ar[$min] = $t;
        }

        echo "after 1 times: <br/>";
        print_r(json_encode($ar));
        echo "<br/>";
    }
}

PHP选择排序-双路优化

<?php
/**
 * Created by PhpStorm.
 * User: L
 * Date: 2018-9-27
 * Time: 11:29
 */

$ar = [5, 8, 6, 4, 12, 5, 3, 1, 89, 54];

echo "input: <br/>";
print_r(json_encode($ar));
echo "<br/>";

selection($ar);

echo "result: <br/>";
print_r(json_encode($ar));
echo "<br/>";

/** 优化的选择排序
 * @param array $ar
 * @param null $len
 */
function selection(array & $ar, $len = null)
{
    if ($len === null) {
        $len = sizeof($ar);
    }


    for ($left = 0, $right = $len - 1; $left < $right; $left++, $right--) {
        $min = $left; //consider left as min_index and max_index
        $max = $right;

        for ($j = $left + 1; $j <= $right; $j++) {//find min_index max_index

            if ($ar[$j] <= $ar[$min]) {
                $min = $j;
            }

            if ($ar[$j] >= $ar[$max]) {
                $max = $j;
            }

        }
        //check min_index and swap
        if ($min != $left) {
            $t = $ar[$left];
            $ar[$left] = $ar[$min];
            $ar[$min] = $t;
        }

        if ($max != $right) {
            $t = $ar[$right];
            $ar[$right] = $ar[$max];
            $ar[$max] = $t;
        }


        echo "after 1 times: <br/>";
        print_r(json_encode($ar));
        echo "<br/>";
    }

}


点击查看更多内容
2人点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
JAVA开发工程师
手记
粉丝
8343
获赞与收藏
253

关注作者,订阅最新文章

阅读免费教程

感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消