图解:冒泡排序及其优化

2022年11月22日12:27:54

一、什么是冒泡排序?

冒泡排序(Bubble sort),是一种较简单的排序算法。这个算法的名字由来是因为越小的元素会经由交换慢慢“浮”到数列的顶端(升序或降序排列),就如同碳酸饮料中二氧化碳的气泡最终会上浮到顶端一样,故名“冒泡排序”。(PS:来源百度百科)

 二、算法原理(升序)

  •  1、比较相邻的两个元素。若第一个比第二个大,交换位置,反之位置不变。
  •  2、交换位置后,再与后面的一个两两比较。
  •  3、针对所有元素重复以上动作,最后一个除外。

 举例来说:36,26,27,2,4,19,50,48来说,会有多趟排序(size - 1),每一趟要排多次(size - k),这里列举出第一趟:

多趟排序的后的结果总结是这样的:

PS:这里留下一个思考,图里留了一个注意字样,在这里数组已经排序好了,但是还是会依次比较,你能想到什么方法优化吗?

它的动态执行过程如下动图所示:

PS:此动图来源于网络。

   最坏时间复杂度         最好时间复杂度            空间复杂度           是否稳定
          O(n^2)               O(n)                  O(1)               稳定

三、代码实现

public class BubbleSort {
    public static void main(String[] args) {
        // 直接定义一个数组
        int[] nums = {36,26,27,2,4,19,50,48};
        System.out.println("排序前的数组:" + Arrays.toString(nums));
        sort(nums);
        System.out.println("排序前的数组:" + Arrays.toString(nums));
    }

    /*
    * 对数组进行冒泡排序
    *
    * @param nums 需要排序的数组
    * */
    private static void sort(int[] nums) {
        // 数组长度 len
        int len = nums.length;
        // 临时变量 temp
        int temp = 0;
        // 外层循环控制排序趟数,len个进行len - 1趟
        for (int i = 0; i < len - 1; i++) {
            System.out.println("第"+ (i + 1) +"趟:");
            // 内层循环控制比较的次数,第i趟比较i-1次
            for (int j = 0; j < len - 1 - i; j++) {
                // 比较相邻的两个元素,若前面的数字大于后面的,交换位置
                if (nums[j] > nums[j+1]) {
                    temp = nums[j+1];
                    nums[j+1] = nums[j];
                    nums[j] = temp;
                }
             System.out.println("    "+"第"+ (j + 1) +"次:" + Arrays.toString(nums));
            }
        }
    }
}

        在这里插一嘴,想起来自己刚接触冒泡排序的时候,感觉那个时候的自己就是一个菜逼,哈哈哈哈哈,不理解两个for的意义,写了好几遍之后还是不理解,似懂非懂。对了,当时还对交换数据位置哪里每次写都要纠结好久,想着怎么交换呀,拿笔在纸上比划半年,才写出来,后来找到了一个小技巧:起手临时变量,中间半交叉,收尾临时变量。仅供参考,大佬勿喷(小声BB)

输出的结果:

        从运行的结果可以看出,从红色标记开始,后面的排序的已经是有序的,但是代码还是要往后面执行,因此说明代码是可以进行优化,这里你可以思考一下怎么去优化这个问题。

4、优化:

        增加一个标志位,当每次发生交换的时候,就进行标记,如果没有发生交换,不标记,也就是说此时数组已经有序,直接跳出循环,于此同时再记录一下最后一次交换元素的位置,即可完成对这个排序的优化。

代码如下所示:

public class BubbleSort {
    public static void main(String[] args) {
        // 直接定义一个数组
        int[] nums = {36,26,27,2,4,19,50,48};
        System.out.println("排序前的数组:" + Arrays.toString(nums));
        sort(nums);
        System.out.println("排序前的数组:" + Arrays.toString(nums));
    }

    /*
     * 对数组进行冒泡排序
     *
     * @param nums 需要排序的数组
     * */
    private static void sort(int[] nums) {
        // 数组长度 len
        int len = nums.length - 1;
        // 记录最后一个交换的位置
        int pos = 0;
        // 临时变量 temp
        int temp = 0;
        // 外层循环控制排序趟数,len个进行len - 1趟
        for (int i = 0; i < nums.length - 1; i++) {
            System.out.println("第" + (i + 1) + "趟:");
            // 标记位
            boolean flag = true;
            // 内层循环控制比较的次数,第i趟比较i-1次
            for (int j = 0; j < len; j++) {
                // 比较相邻的两个元素,若前面的数字大于后面的,交换位置
                if (nums[j] > nums[j + 1]) {
                    temp = nums[j + 1];
                    nums[j + 1] = nums[j];
                    nums[j] = temp;
                    // 如果能走到这里说明有有元素交换,还不是有序的,标记为false
                    flag = false;
                    // 最后一次交换元素的位置
                    pos = j;
                }
                System.out.println("    第" + (j + 1) + "次:" + Arrays.toString(nums));
            }
            // 如果没有元素交换,直接跳出循环
            if (flag) {
                break;
            }
            // 把最后一次交换元素的位置赋值给len,即下一次比较到记录位置
            len = pos;
        }
    }
}

输出的结果:

        对于优化这块,我觉得并不具备普遍性,如果是在最坏的时间复杂度的情况下,优化与不优化输出的结果都是一样的,所以我们只需要了解冒泡的思想即可。另外加标志位这个思想在实际的开发中也很常用,需要我们多多思考。


水平有限,写的不好的地方,希望大家指出。如果你感觉这篇文章对你有帮助,点赞支持一下

  • 作者:Retuester
  • 原文链接:https://blog.csdn.net/Retuester/article/details/119154164
    更新时间:2022年11月22日12:27:54 ,共 2449 字。