zoukankan      html  css  js  c++  java
  • 冒泡排序 (Bubble Sort)

    冒泡排序 (Bubble Sort)

    冒泡排序的基本概念

    冒泡排序(Bubble Sort)也是一种简单直观的排序算法。它重复地走访过要排序的数列,一次比较两个元素,如果他们的顺序错误就把他们交换过来。走访数列的工作是重复地进行直到没有再需要交换,也就是说该数列已经排序完成。这个算法的名字由来是因为越小的元素会经由交换慢慢"浮"到数列的顶端。

    作为最简单的排序算法之一,冒泡排序给我的感觉就像 Abandon 在单词书里出现的感觉一样,每次都在第一页第一位,所以最熟悉。冒泡排序还有一种优化算法,就是立一个 flag,当在一趟序列遍历中元素没有发生交换,则证明该序列已经有序。但这种改进对于提升性能来说并没有什么太大作用

    冒泡排序的算法步骤

    比较相邻的元素。如果第一个比第二个大,就交换他们两个。

    对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对。这步做完后,最后的元素会是最大的数。

    针对所有的元素重复以上的步骤,除了最后一个。

    持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较。

    给定一个N个元素的数组,冒泡法排序将:

    1. 如果元素大小关系不正确,交换这两个数(在本例中为a> b),
    2. 比较一对相邻元素(a,b),
    3. 重复步骤1和2,直到我们到达数组的末尾(最后一对是第(N-2)和(N-1)项,因为我们的数组从零开始)
    4. 到目前为止,最大的元素将在最后的位置。 然后我们将N减少1,并重复步骤1,直到N = 1。

    冒泡排序的分析

    冒泡排序的算法时间分析

    比较和交换需要一个以常量为界的时间,我们称之为c。
    (标准)Bubble Sort中有两个嵌套循环。
    外循环正好运行N次迭代。 但内部循环运行变得越来越短:

    1. 当 i = 0,(N-1)次迭代(比较和可能交换)时。
    2. 当 i = 1,(N-2)次迭代时,...
    3. 当 i =(N-2)时,1次迭代,
    4. 当 i=(N-1),0迭代.

    因此,总迭代次数=(N-1)+(N-2)+ ... + 1 + 0 = N *(N-1)/ 2。
    总时间= c * N *(N-1)/ 2 = O(N ^ 2)。
    冒泡排序实际上是低效的,它的 O(N^2) 时间复杂度。 想象一下,我们有 N = 106 个数字。 即使我们的计算机速度超快,并且可以在1秒内计算108次操作,但冒泡排序仍需要大约100秒才能完成。
    但是,它可以提前终止。
    冒泡排序什么时候最快:
    当输入的数据已经是正序时(都已经是正序了,我还要你冒泡排序有何用啊)。
    冒泡排序什么时候最慢:
    当输入的数据是反序时(写一个 for 循环反序输出数据不就行了,干嘛要用你冒泡排序呢,我是闲的吗)。

    冒泡排序的实例分析

    以数组 arr = [5, 1, 4, 2, 8] 为例说明,加粗的数字表示每次循环要比较的两个数字:

    第一次外循环

    ( 5 1 4 2 8 ) → ( 1 5 4 2 8 ), 5 > 1 交换位置
    ( 1 5 4 2 8 ) → ( 1 4 5 2 8 ), 5 > 4 交换位置
    ( 1 4 5 2 8 ) → ( 1 4 2 5 8 ), 5 > 2 交换位置
    ( 1 4 2 5 8 ) → ( 1 4 2 5 8 ), 5 < 8 位置不变

    第二次外循环(除开最后一个元素8,对剩余的序列)

    ( 1 4 2 5 8 ) → ( 1 4 2 5 8 ), 1 < 4 位置不变
    ( 1 4 2 5 8 ) → ( 1 2 4 5 8 ), 4 > 2 交换位置
    ( 1 2 4 5 8 ) → ( 1 2 4 5 8 ), 4 < 5 位置不变

    第三次外循环(除开已经排序好的最后两个元素,可以注意到上面的数组其实已经排序完成,但是程序本身并不知道,所以还要进行后续的循环,直到剩余的序列为 1)

    ( 1 2 4 5 8 ) → ( 1 2 4 5 8 )
    ( 1 2 4 5 8 ) → ( 1 2 4 5 8 )

    第四次外循环(最后一次)
    ( 1 2 4 5 8 ) → ( 1 2 4 5 8 )

    冒泡排序的动图演示

    冒泡排序的代码实现

    public static void main(String[] args) {
        // 定义数组
        int[] a = new int[10];
        // 数据初始化 (0~99) 随机数
        for (int i = 0; i < 10; i++) {
            a[i] = new Random().nextInt(99);
        }
    
        // 排序前输出
        System.out.println("排序前: " + Arrays.toString(a));
        // 排序
        for (int i = 0; i < a.length - 1; i++) {
            // 这里判定条件 - i 是为了提升性能, 即已经排序的无序再进行比较
            for (int j = 0; j < a.length - 1 - i; j++) {
                // 这里大于号为升序, 小于号为降序
                if (a[j] > a[j + 1]) {
                    int t = a[j];
                    a[j] = a[j + 1];
                    a[j + 1] = t;
                }
            }
        }
        // 排序后输出
        System.out.println("排序后: " + Arrays.toString(a));
    }
    

    结果:

    排序前: [42, 41, 35, 84, 7, 81, 98, 88, 48, 11]
    排序后: [7, 11, 35, 41, 42, 48, 81, 84, 88, 98]
    
  • 相关阅读:
    服务器架构前面加了防火墙,Nginx如何获取客户端真实ip???
    Prometheus学习笔记(5)Grafana可视化展示
    Prometheus学习笔记(4)什么是pushgateway???
    Prometheus学习笔记(3)什么是node_exporter???
    Prometheus学习笔记(2)Prometheus部署
    Prometheus学习笔记(1)Prometheus架构简介
    Centos 7 中的ulimit -n 65535 对进程的文件句柄限制不生效??
    Jenkins实用发布与回滚PHP项目生产实践
    Ansible入门笔记(3)之Playbook
    Ansible入门笔记(2)之常用模块
  • 原文地址:https://www.cnblogs.com/zpKang/p/13323846.html
Copyright © 2011-2022 走看看