用 PHP 实现经典排序算法

前言

最近在学习数据结构及算法,打算用PHP实现一些经典的排序算法,来巩固一下所学的内容,如果有不对的地方,欢迎大佬指教。
因为时间的关系,这里只展示代码,关于算法原理或者思路,后续可能会写专门的博客出来,感谢大家支持。

冒泡排序

/**
 * 给指定数组按照从小到大排序
 *
 * @param  array  $arr [待排序的数组]
 * @return [type]      [返回为数组]
 */
public function sort($arr=array(1,2,3,6,4,3)){
    //对整个数组进行遍历
    for($i=0;$i<count($arr)-1;$i++){
        //每一轮的冒泡处理
        for($j=0;$j<count($arr)-1-$i;$j++){
            //如果当前循环元素比他的后一位大
            if($arr[$j]>$arr[$j+1]){
                //暂存当前循环的值
                $tmp=$arr[$j];
                //交换两个元素的位置
                $arr[$j]=$arr[$j+1];
                $arr[$j+1]=$tmp;
            }
        }
    }
    //打印结果
    var_dump($arr);
}

当然这只是冒泡的初步使用,不难可以看出,有很大的优化空间。比如说在第二轮循环完毕就已经是一个有序的数组了,但是我们的程序还是会循环6次,在这种情况下,我们需要对我们的冒泡进行优化:

/**
 * 给指定数组按照从小到大排序
 *
 * @param  array  $arr [待排序的数组]
 * @return [type]      [返回为数组]
 */
public function sort($arr=array(1,2,3,6,4,3)){
    //对整个数组进行遍历
    for($i=0;$i<count($arr)-1;$i++){
        //有序标记,默认为true,用1表示
        $isSorten=1;
        //每一轮的冒泡处理
        for($j=0;$j<count($arr)-1-$i;$j++){
            //如果当前循环元素比他的后一位大
            if($arr[$j]>$arr[$j+1]){
                //暂存当前循环的值
                $tmp=$arr[$j];
                //交换两个元素的位置
                $arr[$j]=$arr[$j+1];
                $arr[$j+1]=$tmp;
                //因为有元素交换,所以将true改为false,用0表示
                $isSorten=0;
            }
        }
        //如果$isSorted为真,结束循环
        if ($isSorten) {
            break;
        }
    }
    //打印结果
    var_dump($arr);
}

这是第二版优化,当然,有第二版就有第三版。第三版我们主要侧重优化一下性能,当然示例的数组可能不太明显看出来,如果换成array(3,1,4,5,6,7)可能会容易看出来,那就是其实1后面的循序已经是我们想要的了,但是我们的程序还是会挨个比较,让我们来解决他:

/**
 * 给指定数组按照从小到大排序
 *
 * @param  array  $arr [待排序的数组]
 * @return [type]      [返回为数组]
 */
public function sort($arr=array(1,2,3,6,4,3)){
    //记录最后一次交换顺序的位置
    $listChangeIndex=0;
    //表示边界,即每次比较到这里就可以了
    $sortBorber =count($arr)-1;
    //对整个数组进行遍历
    for($i=0;$i<count($arr)-1;$i++){
        //有序标记,默认为true,用1表示
        $isSorten=1;
        //每一轮的冒泡处理
        for($j=0;$j<$sortBorber;$j++){
            //如果当前循环元素比他的后一位大
            if($arr[$j]>$arr[$j+1]){
                //暂存当前循环的值
                $tmp=$arr[$j];
                //交换两个元素的位置
                $arr[$j]=$arr[$j+1];
                $arr[$j+1]=$tmp;
                //因为有元素交换,所以将true改为false,用0表示
                $isSorten=0;
                //更新为最后一次交换元素的位置
                $listChangeIndex=$j;
            }
        }
        $sortBorber=$listChangeIndex;
        //如果$isSorted为真,结束循环
        if ($isSorten) {
            break;
        }
    }
    //打印结果
    var_dump($arr);
}

鸡尾酒排序

如你所见,冒泡算法是从左到右进行比较的。如果说冒泡算法是单向,那么鸡尾酒算法就是双向,就像现在的火车,有两个车头,一头开到终点后,另外一头接着开。

/**
 * 给指定数组按照从小到大排序
 *
 * @param  array  $arr [待排序的数组]
 * @return [type]      [返回为数组]
 */
public function sort($arr=array(1,2,3,6,4,3,6,3,8)){
    $tem=0;
    //对整个数组进行遍历
    for($i=0;$i<count($arr)/2;$i++){
        //有序标记,默认为true,用1表示
        $isSorten=1;
        //基数轮
        for($j=1;$j<count($arr)-1-$i;$j++){
            //如果当前循环元素比他的后一位大
            if($arr[$j]>$arr[$j+1]){
                //暂存当前循环的值
                $tmp=$arr[$j];
                //交换两个元素的位置
                $arr[$j]=$arr[$j+1];
                $arr[$j+1]=$tmp;
                //因为有元素交换,所以将true改为false,用0表示
                $isSorten=0;
            }
        }
        //如果$isSorted为真,结束循环
        if ($isSorten) {
            break;
        }
        //偶数轮开始前重新定义为true,用1表示
        $isSorten=1;
        //偶数轮,从右向左比较
        for($j=count($arr)-1-$i;$j>1;$j--){
            //如果当前循环元素比他的后一位小
            if($arr[$j]<$arr[$j-1]){
                //暂存当前循环的值
                $tmp=$arr[$j];
                //交换两个元素的位置
                $arr[$j]=$arr[$j-1];
                $arr[$j-1]=$tmp;
                //因为有元素交换,所以将true改为false,用0表示
                $isSorten=0;
            }
        }

         //如果$isSorted为真,结束循环
        if ($isSorten) {
            break;
        }
    }
    //打印结果
    var_dump($arr);
}

两者的特点呢也比较容易区分,鸡尾酒排序减少了排序的回合,相比于冒泡排序,代码量几乎是增加了一倍。
比较冒泡排序,鸡尾酒排序更适合大部分元素已经有序的情况。

其他算法待补充……

本作品采用《CC 协议》,转载必须注明作者和本文链接
空舟湖上~      ——Jouzeyu
lochpure
《L04 微信小程序从零到发布》
从小程序个人账户申请开始,带你一步步进行开发一个微信小程序,直到提交微信控制台上线发布。
《L03 构架 API 服务器》
你将学到如 RESTFul 设计风格、PostMan 的使用、OAuth 流程,JWT 概念及使用 和 API 开发相关的进阶知识。
讨论数量: 2

冒泡排序:


/**
 * bubble sort.
 *
 * @param array $values
 * @return array
 */
function sort(array $values) : array
{
    $len = count($values);
    for ($i = 0; $i < $len; $i++) {
        for ($j = 0; $j < $len - $i - 1; $j++) {
            if ($values[$j] > $values[$j+1]) {
                [$values[$j], $values[$j+1]] = [$values[$j+1], $values[$j]];
            }
        }
    }
    return $values;
}

/**
 * bubble sort V2.
 *
 * @param array $values
 * @return array
 */
function sortV2(array $values) : array
{
    $len = count($values);
    for ($i = 0, $exchange = true; $exchange && $i < $len; $i++) {
        for ($j = 0, $exchange = false; $j < $len - $i - 1; $j++) {
            if ($values[$j] > $values[$j+1]) {
                [$values[$j], $values[$j+1]] = [$values[$j+1], $values[$j]];
                $exchange = true;
            }
        }
    }
    return $values;
}
4年前 评论
乐观的摸一摸头

考虑下参数传引用,否则空间复杂度跟不上

4年前 评论

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!