zoukankan      html  css  js  c++  java
  • 排序算法-冒泡排序/飞梭排序

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

    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]));
    
    
  • 相关阅读:
    1082 射击比赛 (20 分)
    1091 N-自守数 (15 分)
    1064 朋友数 (20 分)
    1031 查验身份证 (15 分)
    1028 人口普查 (20 分)
    1059 C语言竞赛 (20 分)
    1083 是否存在相等的差 (20 分)
    1077 互评成绩计算 (20 分)
    792. 高精度减法
    791. 高精度加法
  • 原文地址:https://www.cnblogs.com/stringarray/p/12702609.html
Copyright © 2011-2022 走看看