冒泡排序(Bubble Sort)

一、算法概述

1.1 算法分类

十种常见排序算法可以分为两大类:

  • 比较类排序:通过比较来决定元素间的相对次序,由于其时间复杂度不能突破O(nlogn),因此也称为非线性时间比较类排序。

  • 非比较类排序:不通过比较来决定元素间的相对次序,它可以突破基于比较排序的时间下界,以线性时间运行,因此也称为线性时间非比较类排序。

1.2 算法复杂度

1.3 相关概念

  • 稳定:如果a原本在b前面,而a=b,排序之后a仍然在b的前面。
  • 不稳定:如果a原本在b的前面,而a=b,排序之后 a 可能会出现在 b 的后面。
  • 时间复杂度:对排序数据的总的操作次数。反映当n变化时,操作次数呈现什么规律。
  • 空间复杂度:是指算法在计算机内执行时所需存储空间的度量,它也是数据规模n的函数。

二、冒泡排序(Bubble Sort)

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

2.1 算法描述

  • 1、比较相邻的元素。如果第一个比第二个大,就交换它们两个;
  • 2、对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对,这样在最后的元素应该会是最大的数;
  • 3、针对所有的元素重复以上的步骤,除了最后一个;
  • 4、重复步骤1~3,直到排序完成。

2.2 动图演示

2.3 排序过程

下面以数列{20,40,30,10,60,50}为例,演示它的冒泡排序过程(如下图)。


我们先分析第1趟排序

  • 当i=5,j=0时,a[0]<a[1]。此时,不做任何处理!
  • 当i=5,j=1时,a[1]>a[2]。此时,交换a[1]和a[2]的值;交换之后,a[1]=30,a[2]=40。
  • 当i=5,j=2时,a[2]>a[3]。此时,交换a[2]和a[3]的值;交换之后,a[2]=10,a[3]=40。
  • 当i=5,j=3时,a[3]<a[4]。此时,不做任何处理!
  • 当i=5,j=4时,a[4]>a[5]。此时,交换a[4]和a[5]的值;交换之后,a[4]=50,a[3]=60。

于是,第1趟排序完之后,数列{20,40,30,10,60,50}变成了{20,30,10,40,50,60}。此时,数列末尾的值最大。

根据这种方法:

  • 第2趟排序完之后,数列中a[5...6]是有序的。
  • 第3趟排序完之后,数列中a[4...6]是有序的。
  • 第4趟排序完之后,数列中a[3...6]是有序的。
  • 第5趟排序完之后,数列中a[1...6]是有序的。

第5趟排序之后,整个数列也就是有序的了。

2.4 代码实现

2.4.1 冒泡排序——常规版

/**
 * @Author: huangyibo
 * @Date: 2022/2/19 22:37
 * @Description: 冒泡排序 常规版
 * 文字描述(以升序为例)
 * 1、依次比较数组中相邻两个元素大小,若 arr[j] > arr[j + 1], 则交换两个元素,
 *      两两都比较一遍则称为一轮冒泡,结果是让最大的元素排到最后
 * 2、重复以上步骤, 直到整个数组有序
 */

public class BubbleSort {

    public static <E extends Comparable<E>> void bubbleSort(E[] arr){
        for (int i = 0; i < arr.length - 1; i++) {
            for (int j = 0; j < arr.length - 1 - i; j++) {
                if(arr[j].compareTo(arr[j + 1]) > 0){
                    swap(arr, j,j + 1);
                }
            }
        }
    }

    /**
     * 交换数组元素
     * @param arr
     * @param i
     * @param j
     * @param <E>
     */
    private static <E> void swap(E[] arr, int i, int j) {
        E temp = arr[i];
        arr[i] = arr[j];
        arr[j] = temp;
    }
}

2.4.2 冒泡排序——优化版1

  • 用boolean变量isSwapped记录是否发生位置交换,没有发生元素交换,则证明数组有序,直接跳出循环。
/**
 * @Author: huangyibo
 * @Date: 2022/2/19 22:37
 * @Description: 冒泡排序 优化版1
 * 用boolean变量isSwapped记录是否发生位置交换,
 * 没有发生元素交换,则证明数组有序,直接跳出循环
 *
 * 有利于有序数组排序,完全有序数组直接变为O(n)
 */

public class BubbleSort {

    public static <E extends Comparable<E>> void bubbleSort(E[] arr){
        for (int i = 0; i < arr.length - 1; i++) {
            //是否发生了交换
            boolean isSwapped = false;
            for (int j = 0; j < arr.length - 1 - i; j++) {
                if(arr[j].compareTo(arr[j + 1]) > 0){
                    swap(arr, j,j + 1);
                    isSwapped = true;
                }
            }

            //没有发生元素交换,则证明数组有序
            if(!isSwapped){
                break;
            }
        }
    }

    /**
     * 交换数组元素
     * @param arr
     * @param i
     * @param j
     * @param <E>
     */
    private static <E> void swap(E[] arr, int i, int j) {
        E temp = arr[i];
        arr[i] = arr[j];
        arr[j] = temp;
    }
}

2.4.3 冒泡排序——优化版2

  • 每轮冒泡时,最后一次交换索引可以作为下一轮冒泡的比较次数,如果这个值小于等于0,表示整个数组有序,直接退出外层循环即可。
/**
 * @Author: huangyibo
 * @Date: 2022/2/19 22:37
 * @Description: 冒泡排序 优化版2
 * 每轮冒泡时,最后一次交换索引可以作为下一轮冒泡的比较次数,
 * 如果这个值小于等于0,表示整个数组有序,直接退出外层循环即可
 *
 * 有利于有序数组排序,完全有序数组直接变为O(n)
 */

public class BubbleSort {

    public static <E extends Comparable<E>> void bubbleSort(E[] arr){
        for (int i = 0; i < arr.length - 1; ) {
            //最后一次发生元素交换的索引位置
            int lastSwappedIndex = 0;
            for (int j = 0; j < arr.length - 1 - i; j++) {
                if(arr[j].compareTo(arr[j + 1]) > 0){
                    swap(arr, j,j + 1);
                    lastSwappedIndex = j + 1;
                }
            }

            //外层循环遍历赋值,
            // 如果是有序数组的话,i = arr.length - 1 则直接终止了外层循环
            i = arr.length - 1 - lastSwappedIndex;
        }
    }

    /**
     * 交换数组元素
     * @param arr
     * @param i
     * @param j
     * @param <E>
     */
    private static <E> void swap(E[] arr, int i, int j) {
        E temp = arr[i];
        arr[i] = arr[j];
        arr[j] = temp;
    }
}

2.4.4 冒泡排序——优化版3(外层for无限循环写法)

  • 每轮冒泡时,最后一次交换索引可以作为下一轮冒泡的比较次数,如果这个值小于等于0,表示整个数组有序,直接退出外层循环即可。
/**
 * @Author: huangyibo
 * @Date: 2022/2/19 22:37
 * @Description: 冒泡排序 优化版3(外层for无限循环写法)
 * 每轮冒泡时,最后一次交换索引可以作为下一轮冒泡的比较次数,
 * 如果这个值小于等于0,表示整个数组有序,直接退出外层循环即可
 *
 * 有利于有序数组排序,完全有序数组直接变为O(n)
 */

public class BubbleSort {

    public static <E extends Comparable<E>> void bubbleSort(E[] arr){
        //循环比较次数
        int cycles = arr.length - 1;

        for ( ; ; ) {
            //最后一次发生元素交换的索引位置
            int lastSwappedIndex = 0;
            for (int j = 0; j < cycles; j++) {
                if(arr[j].compareTo(arr[j + 1]) > 0){
                    swap(arr, j,j + 1);
                    lastSwappedIndex = j;
                }
            }
            //最后一次元素交换位置的索引为下一轮循环的最大次数
            cycles = lastSwappedIndex;

            //循环比较次数小于等于0,则证明数组有序
            if(cycles <= 0){
                break;
            }
        }
    }

    /**
     * 交换数组元素
     * @param arr
     * @param i
     * @param j
     * @param <E>
     */
    private static <E> void swap(E[] arr, int i, int j) {
        E temp = arr[i];
        arr[i] = arr[j];
        arr[j] = temp;
    }
}

2.4.5 冒泡排序——优化版4(外层while循环写法)

  • 每轮冒泡时,最后一次交换索引可以作为下一轮冒泡的比较次数,如果这个值小于等于0,表示整个数组有序,直接退出外层循环即可。
/**
 * @Author: huangyibo
 * @Date: 2022/2/19 22:37
 * @Description: 冒泡排序 优化版4(外层while循环写法)
 * 每轮冒泡时,最后一次交换索引可以作为下一轮冒泡的比较次数,
 * 如果这个值小于等于0,表示整个数组有序,直接退出外层循环即可
 *
 * 有利于有序数组排序,完全有序数组直接变为O(n)
 */

public class BubbleSort {

    public static <E extends Comparable<E>> void bubbleSort(E[] arr){
        //循环比较次数
        int cycles = arr.length - 1;

        while (cycles > 0){
            //最后一次发生元素交换的索引位置
            int lastSwappedIndex = 0;
            for (int j = 0; j < cycles; j++) {
                if(arr[j].compareTo(arr[j + 1]) > 0){
                    swap(arr, j,j + 1);
                    lastSwappedIndex = j;
                }
            }

            //最后一次元素交换位置的索引为下一轮循环的最大次数
            cycles = lastSwappedIndex;
        }
    }

    /**
     * 交换数组元素
     * @param arr
     * @param i
     * @param j
     * @param <E>
     */
    private static <E> void swap(E[] arr, int i, int j) {
        E temp = arr[i];
        arr[i] = arr[j];
        arr[j] = temp;
    }
}

参考:
https://www.cnblogs.com/onepixel/articles/7674659.html

https://www.cnblogs.com/skywang12345/p/3596232.html

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 218,607评论 6 507
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,239评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,960评论 0 355
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,750评论 1 294
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,764评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,604评论 1 305
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,347评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,253评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,702评论 1 315
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,893评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,015评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,734评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,352评论 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,934评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,052评论 1 270
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,216评论 3 371
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,969评论 2 355

推荐阅读更多精彩内容