• 排序算法-冒泡排序/飞梭排序


    常见基于选择的排序算法有冒泡排序、插入排序、选择排序、归并排序和快速排序,我们在选择排序算法的时候,通常会根据以下几个维度来考虑:

    1. 时间复杂度
    2. 空间复杂度(对内存空间的消耗)
    3. 算法的稳定性(如果待排序的序列中存在值相等的元素,经过排序之后,相等元素之间原有的先后顺序不变)

    我们首先从冒泡排序开始。

    实现原理

    冒泡排序只会操作相邻的两个数据。每次冒泡操作都会对相邻的两个元素进行比较,看是否满足大小关系要求,如果不满足就让它俩互换。一次冒泡会让至少一个元素移动到它应该在的位置,重复 n 次,就完成了 n 个数据的排序工作。

    光看定义有点抽象,我们用图来演示,假设待排序数字是 4、5、6、3、2、1,第一次排序的流程是这样的:

    看这个图的时候要结合定义一起看,否则也比较懵逼,当然如果你去 VisuAlgo 上看动态图的话就更形象了:https://visualgo.net/zh/sorting,经过 n 次冒泡,最终完成排序(所谓冒泡,以升序来看,就是每次把待排序序列中的最大值插到已排序序列的最前面,这个过程就像冒泡一样):

    示例代码

    重要的是理解冒泡排序的原理,懂了原理就是把这个排序过程翻译成代码而已,以下是 PHP 代码实现的冒泡排序:

    <?php
    
    /**
     * 冒泡排序实现函数(PHP)
     * @param $nums
     * @return mixed
     */
    function bubble_sort($nums) {
        if (count($nums) <= 1) {
            return $nums;
        }
    
        for ($i = 0; $i < count($nums); $i++) {
            $flag = false;
            for ($j = 0; $j < count($nums) - $i - 1; $j++) {
                if ($nums[$j] > $nums[$j+1]) {
                    $temp  = $nums[$j];
                    $nums[$j] = $nums[$j+1];
                    $nums[$j+1] = $temp;
                    $flag = true;
                }
            }
            if (!$flag) {
                break;
            }
        }
    
        return $nums;
    }
    
    $nums = [4, 5, 6, 3, 2, 1];
    $nums = bubble_sort($nums);
    print_r($nums);
    
    

    可以看到我们对冒泡排序有个小小的优化,就是当某一次遍历的时候发现没有需要交换的元素,则认为整个序列已经排序完成。

    性能分析

    最后我们来看下冒泡排序的性能和稳定性:

    1. 时间复杂度: O(n^2)
    2. 空间复杂度:只涉及相邻元素的交换,是原地排序算法
    3. 算法稳定性:元素相等不会交换,是稳定的排序算法

    时间复杂度是 O(n^2),看起来性能并不是很好,所以我们在实践中基本不会选用冒泡算法。

    飞梭排序(冒泡排序的变形)

    思路分析:飞梭排序是冒泡排序的轻微变形。不同的地方在于,飞梭排序是从低到高然后从高到低来回排序,而冒泡排序则仅从低到高去比较序列里的每个元素。

    先对数组从左到右进行冒泡排序(升序),则最大的元素去到最右端;
    再对数组从右到左进行冒泡排序(降序),则最小的元素去到最左端;
    以此类推,依次改变冒泡的方向,并不断缩小未排序元素的范围,直到最后一个元素结束。

    PHP实现代码示例:

    function ShuttleSort(array $data)
    {
        /**
         * 替换方法
         *
         * @param array $data
         * @param       $i
         * @param       $j
         * @return array
         */
        $swap = function (array &$data, $i, $j) {
            $temp     = $data[$i];
            $data[$i] = $data[$j];
            $data[$j] = $temp;
            return $data;
        };
    
        $count = count($data);
        $left  = 0;
        $right = $count - 1;
    
        while ($left < $right) {
            // 从左到右
            $lastRight = 0;
            for ($i = $left; $i < $right; $i++) {
                if ($data[$i] > $data[$i + 1]) {
                    $swap($data, $i, 1 + $i);
                    $lastRight = $i;
                }
            }
            $right = $lastRight;
            // 从右到左
            $lastLeft = 0;
            for ($j = $right; $left < $j; $j--) {
                if ($data[$j - 1] > $data[$j]) {
                    $swap($data, $j - 1, $j);
                    $lastLeft = $j;
                }
            }
            $left = $lastLeft;
        }
        return $data;
    }
    
    var_dump(ShuttleSort([6, 13, 21, 99, 18, 2, 25, 33, 19, 84]));
    
    
  • 相关阅读:
    打开安装 好的Microsoft Dynamics CRM 4.0 报错误为 Caller does not have enough privilege to set CallerOriginToken to the specified value 的解决办法
    基于 Windows Server 2008 的计算机对 Microsoft Dynamics CRM 4.0 的支持
    Microsoft Dynamics CRM 4.0 如何添加自定义按钮
    Microsoft Dynamics CRM 4.0 Plugin 取值,赋值,查询
    C# 中的 enum(枚举) 类型使用例子
    vue事件的绑定
    表单验证2
    node中模块
    node模块的引入
    node中的读文件
  • 原文地址:https://www.cnblogs.com/stringarray/p/12702609.html
Copyright © 2020-2023  润新知