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]));
    
    
  • 相关阅读:
    编程入门之结构体
    编程入门之函数理解
    编程入门之编码风格
    Linux基础 30分钟GDB调试快速突破
    GDB实战
    linux下终端游戏
    DSP学习教程基于28335(一)
    Linux内核模块编程可以使用的内核组件
    Windows10下配置Linux下C语言开发环境
    Git常规配置与基本用法
  • 原文地址:https://www.cnblogs.com/stringarray/p/12702609.html
Copyright © 2011-2022 走看看