(四)Java算法:冒泡排序

这篇具有很好参考价值的文章主要介绍了(四)Java算法:冒泡排序。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

一、简介

  冒泡排序(Bubble Sort),是一种计算机科学领域的较简单的排序算法。它的工作原理是:它重复地走访过要排序的元素列,依次比较两个相邻的元素,如果不是指定顺序(比如从小达到)就把他们交换过来。走访元素的工作是重复地进行,直到没有相邻元素需要交换,也就是说该元素列已经排序完成。

二、maven依赖

pom.xml

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter</artifactId>
        <version>2.6.0</version>
    </dependency>

    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <version>1.16.14</version>
    </dependency>
</dependencies>

三、多个版本实现

3.1、基础版本

  冒泡排序有很多实现,我们先看看它的最基本的实现。

    /**
     * 冒泡排序
     *
     * @param arr
     */
    public static void bubbleSortBase(int[] arr) {
        // 数组的长度
        int length = arr.length;
        // 遍历数组
        for (int i = 0; i < length; i++) {
            log.info("第【{}】轮排序将准备比较【{}】次", i + 1, length - 1 - i);
            for (int j = 0; j < length - 1 - i; j++) {
                // 从小到大排序,如果前一个元素【arr[j] 】比后一个元素【arr[j + 1]】大,则交换位置
                if (arr[j] > arr[j + 1]) {
                    log.info("【{}】与【{}】进行交换", arr[j], arr[j + 1]);
                    int temp = arr[j];
                    arr[j] = arr[j + 1];
                    arr[j + 1] = temp;
                }
            }
            log.info("第【{}】轮排序后的结果:{}", i + 1, arr);
        }
    }

    public static void main(String[] args) {
        int[] arr = new int[]{23, 8, 10, 21, 19, 9};
        log.info("要排序的初始化数据:{}", arr);
        //从小到大排序
        bubbleSortBase(arr);
    }

  运行结果(只有满足交换条件的比较才会进行交换)

--------------------3.1、基础版本-------------------------
要排序的初始化数据:[23, 8, 10, 21, 19, 9]
第【1】轮排序将准备比较【5】次      ---->就是6个数相邻两个数依次进行比较(满足条件的就交换)
【23】与【8】进行交换后数组变成--> [8, 23, 10, 21, 19, 9]
【23】与【10】进行交换后数组变成--> [8, 10, 23, 21, 19, 9]
【23】与【21】进行交换后数组变成--> [8, 10, 21, 23, 19, 9]
【23】与【19】进行交换后数组变成--> [8, 10, 21, 19, 23, 9]
【23】与【9】进行交换后数组变成--> [8, 10, 21, 19, 9, 23]
第【1】轮排序后的结果:[8, 10, 21, 19, 9, 23]
第【2】轮排序将准备比较【4】次      --->第一个最大的数已经排序完毕了,剩下5个数,也就是比较4次了
【21】与【19】进行交换后数组变成--> [8, 10, 19, 21, 9, 23]
【21】与【9】进行交换后数组变成--> [8, 10, 19, 9, 21, 23]
第【2】轮排序后的结果:[8, 10, 19, 9, 21, 23]
第【3】轮排序将准备比较【3】次      --->两个最大的数已经排序完毕了,剩下4个数,也就是比较3次了
【19】与【9】进行交换后数组变成--> [8, 10, 9, 19, 21, 23]
第【3】轮排序后的结果:[8, 10, 9, 19, 21, 23]
第【4】轮排序将准备比较【2】次      --->三个最大的数已经排序完毕了,剩下3个数,也就是比较2次了
【10】与【9】进行交换后数组变成--> [8, 9, 10, 19, 21, 23]
第【4】轮排序后的结果:[8, 9, 10, 19, 21, 23]
第【5】轮排序将准备比较【1】次     --->四个最大的数已经排序完毕了,剩下2个数,也就是比较1次了
第【5】轮排序后的结果:[8, 9, 10, 19, 21, 23]
第【6】轮排序将准备比较【0】次     --->五个最大的数已经排序完毕了,剩下1个数,不用比较了,也就是排完了
第【6】轮排序后的结果:[8, 9, 10, 19, 21, 23]

  我希望大家把这个最基础的版本先搞懂,画图太麻烦了,但是我觉得如果你把文字都看懂了,这里的数据流向的印象就会非常的深刻的,再看后面的两个版本。就容易理解。当然,后面的版本也不是强制要求,如果你想继续优化可以参考后面的两种方法。

3.2、优化版本

  这个版本是怎么来的呢,我们先看一组要排序的数据,调用我们刚才的基础版本。假设我们需要排序的数组数据是:23, 8, 9, 10, 21, 39, 29, 30

    public static void main(String[] args) {
        log.info("--------------------3.2、基础版本-------------------------");
        int[] arr1 = new int[]{23, 8, 9, 10, 21, 39, 29, 30};
        log.info("要排序的初始化数据:{}", arr1);
        //从小到大排序
        bubbleSortBase(arr1);
    }

  基础版本运行结果如下:

--------------------3.2、基础版本-------------------------
要排序的初始化数据:[23, 8, 9, 10, 21, 39, 29, 30]
第【1】轮排序将准备比较【7】次
【23】与【8】进行交换后数组变成--> [8, 23, 9, 10, 21, 39, 29, 30]
【23】与【9】进行交换后数组变成--> [8, 9, 23, 10, 21, 39, 29, 30]
【23】与【10】进行交换后数组变成--> [8, 9, 10, 23, 21, 39, 29, 30]
【23】与【21】进行交换后数组变成--> [8, 9, 10, 21, 23, 39, 29, 30]
【39】与【29】进行交换后数组变成--> [8, 9, 10, 21, 23, 29, 39, 30]
【39】与【30】进行交换后数组变成--> [8, 9, 10, 21, 23, 29, 30, 39]
第【1】轮排序后的结果:[8, 9, 10, 21, 23, 29, 30, 39]
第【2】轮排序将准备比较【6】次
第【2】轮排序后的结果:[8, 9, 10, 21, 23, 29, 30, 39]
第【3】轮排序将准备比较【5】次
第【3】轮排序后的结果:[8, 9, 10, 21, 23, 29, 30, 39]
第【4】轮排序将准备比较【4】次
第【4】轮排序后的结果:[8, 9, 10, 21, 23, 29, 30, 39]
第【5】轮排序将准备比较【3】次
第【5】轮排序后的结果:[8, 9, 10, 21, 23, 29, 30, 39]
第【6】轮排序将准备比较【2】次
第【6】轮排序后的结果:[8, 9, 10, 21, 23, 29, 30, 39]
第【7】轮排序将准备比较【1】次
第【7】轮排序后的结果:[8, 9, 10, 21, 23, 29, 30, 39]
第【8】轮排序将准备比较【0】次
第【8】轮排序后的结果:[8, 9, 10, 21, 23, 29, 30, 39]

  如果你熟悉基础版本了看这个就很清晰了。我们这个数组经过我们第一次排序后,数据就已经是有序的了,但是我们的程序还是进行比较,比如第【2】轮排序将准备比较【6】次,第【3】轮排序将准备比较【5】次等等。那有什么办法,如果我们的数据已经有序就不用再比较了呢?这就是我们优化版本要解决的,具体实现如下:

    /**
     * 冒泡排序(优化版本--最后几轮排序时剩下的数组数据有序)
     *
     * @param arr
     */
    public static void bubbleSortOptimize(int[] arr) {
        // 数组的长度
        int length = arr.length;
        // 遍历数组
        for (int i = 0; i < length - 1; i++) {
            // 有序标记,每一轮排序的初始值都是true
            boolean isOrderly = true;
            log.info("第【{}】轮排序将准备比较【{}】次", i + 1, length - 1 - i);
            for (int j = 0; j < length - i - 1; j++) {
                // 从小到大排序,如果前一个元素【arr[j] 】比后一个元素【arr[j + 1]】大,则交换位置
                if (arr[j] > arr[j + 1]) {
                    int t = arr[j];
                    arr[j] = arr[j + 1];
                    arr[j + 1] = t;
                    // 有元素交换,所以不是有序,标记变为false
                    isOrderly = false;
                    log.info("【{}】与【{}】进行交换后数组变成--> {}", arr[j + 1], arr[j], arr);
                }
            }
            log.info("第【{}】轮排序后的结果:{}", i + 1, arr);
            // 如果没有交换,说明数组已经有序了,直接跳出大循环
            if (isOrderly) {
                log.info("第【{}】轮排序后跳出循环", i + 1);
                break;
            }
        }
    }

  从我们优化代码来看,我们就是每一轮排序加了一个标志位isOrderly,标识数组元素是否有序,默认为true标识有序,当我们有元素交换的时候就把标识改成false。当一轮排序完成后,如果值为false说明本轮排序完成前是无序的(也就是说此次排序有交换元素,本轮排序完成后有可能数组已经有序,所以我这里说是排序完成前);如果值为true,意味着交换元素,说明本轮排序后数据已经有序了。

  优化版本运行结果如下:

--------------------3.2、优化版本-------------------------
要排序的初始化数据:[23, 8, 9, 10, 21, 39, 29, 30]
第【1】轮排序将准备比较【7】次
【23】与【8】进行交换后数组变成--> [8, 23, 9, 10, 21, 39, 29, 30]
【23】与【9】进行交换后数组变成--> [8, 9, 23, 10, 21, 39, 29, 30]
【23】与【10】进行交换后数组变成--> [8, 9, 10, 23, 21, 39, 29, 30]
【23】与【21】进行交换后数组变成--> [8, 9, 10, 21, 23, 39, 29, 30]
【39】与【29】进行交换后数组变成--> [8, 9, 10, 21, 23, 29, 39, 30]
【39】与【30】进行交换后数组变成--> [8, 9, 10, 21, 23, 29, 30, 39]
第【1】轮排序后的结果:[8, 9, 10, 21, 23, 29, 30, 39]
第【2】轮排序将准备比较【6】次
第【2】轮排序后的结果:[8, 9, 10, 21, 23, 29, 30, 39]
第【2】轮排序后跳出循环

  从运行结果来看,我们只需要两轮就完成了排序,并且少了很多不必要的比较次数。

3.3、综合版本

  这个版本又是怎么来的呢,我们先看一组要排序的数据,调用我们刚才的优化版本。假设我们需要排序的数组数据是:21, 10, 8, 9, 23, 29, 30, 39

    public static void main(String[] args) {
        log.info("---------------------3.3、优化版本------------------------");
        int[] arr4 = new int[]{21, 10, 8, 9, 23, 29, 30, 39};
        log.info("要排序的初始化数据:{}", arr4);
        //从小到大排序
        bubbleSortOptimize(arr4);
    }

  优化版本运行本次排序结果如下:

---------------------3.3、优化版本------------------------
要排序的初始化数据:[21, 10, 8, 9, 23, 29, 30, 39]
第【1】轮排序将准备比较【7】次
【21】与【10】进行交换后数组变成--> [10, 21, 8, 9, 23, 29, 30, 39]
【21】与【8】进行交换后数组变成--> [10, 8, 21, 9, 23, 29, 30, 39]
【21】与【9】进行交换后数组变成--> [10, 8, 9, 21, 23, 29, 30, 39]
第【1】轮排序后的结果:[10, 8, 9, 21, 23, 29, 30, 39]
第【2】轮排序将准备比较【6】次
【10】与【8】进行交换后数组变成--> [8, 10, 9, 21, 23, 29, 30, 39]
【10】与【9】进行交换后数组变成--> [8, 9, 10, 21, 23, 29, 30, 39]
第【2】轮排序后的结果:[8, 9, 10, 21, 23, 29, 30, 39]
第【3】轮排序将准备比较【5】次
第【3】轮排序后的结果:[8, 9, 10, 21, 23, 29, 30, 39]
第【3】轮排序后跳出循环

  从运行结果来看,首先我们的数组,后面几位是基本有序的,但是不管是第一轮还是,第二轮,还是第三轮,都要进行一次次的比较,显然是不必要的。我们优化版本是通过增加标志位记录交换位置,后续判断是否已有序,这里我们的综合版本也可以借鉴这个思路,同时把最后交换的位置也记下来,如果一轮排序下来,交换的位置之后的数据说明是不满足交换的条件的,也就是有序的,具体实现如下:

	/**
     * 冒泡排序(综合版本--数组中后面的数据有序)
     *
     * @param arr
     */
    public static void bubbleSortFinal(int[] arr) {
        // 数组的长度
        int len = arr.length;
        // 记录最后一次交换的位置
        int lastExchangeIndex = 0;
        // 无序数列的边界,每轮比较只需要比到这里就可以了
        int borderIndex = len - 1;
        // 遍历数组
        for (int i = 0; i < len - 1; i++) {
            // 有序标记,每一轮排序的初始值都是true
            boolean isOrderly = true;
            log.info("第【{}】轮排序将准备比较【{}】次", i + 1, borderIndex);
            for (int j = 0; j < borderIndex; j++) {
                // 从小到大排序,如果前一个元素【arr[j] 】比后一个元素【arr[j + 1]】大,则交换位置
                if (arr[j] > arr[j + 1]) {
                    int t = arr[j];
                    arr[j] = arr[j + 1];
                    arr[j + 1] = t;
                    // 有元素交换,所以不是有序,标记变为false
                    isOrderly = false;
                    // 记录一下最后一次元素交换的位置(说明arr[j]后面的元素已经有序,不用再比较了)
                    lastExchangeIndex = j;
                    log.info("【{}】与【{}】进行交换后数组变成--> {}", arr[j + 1], arr[j], arr);
                }
            }
            borderIndex = lastExchangeIndex;
            log.info("第【{}】轮排序后的结果:{}", i + 1, arr);
            // 如果没有交换,说明数组已经有序了,直接跳出大循环
            if (isOrderly) {
                log.info("第【{}】轮排序后跳出循环", i + 1);
                break;
            }
        }
    }

  综合版本运行本次排序结果如下:

---------------------3.3、综合版本------------------------
要排序的初始化数据:[21, 10, 8, 9, 23, 29, 30, 39]
第【1】轮排序将准备比较【7】次
【21】与【10】进行交换后数组变成--> [10, 21, 8, 9, 23, 29, 30, 39]
【21】与【8】进行交换后数组变成--> [10, 8, 21, 9, 23, 29, 30, 39]
【21】与【9】进行交换后数组变成--> [10, 8, 9, 21, 23, 29, 30, 39]
第【1】轮排序后最后的边界索引:2
第【1】轮排序后的结果:[10, 8, 9, 21, 23, 29, 30, 39]
第【2】轮排序将准备比较【2】次
【10】与【8】进行交换后数组变成--> [8, 10, 9, 21, 23, 29, 30, 39]
【10】与【9】进行交换后数组变成--> [8, 9, 10, 21, 23, 29, 30, 39]
第【2】轮排序后最后的边界索引:1
第【2】轮排序后的结果:[8, 9, 10, 21, 23, 29, 30, 39]
第【3】轮排序将准备比较【1】次
第【3】轮排序后最后的边界索引:1
第【3】轮排序后的结果:[8, 9, 10, 21, 23, 29, 30, 39]
第【3】轮排序后跳出循环

  从这个结果来看,我们的第一轮排序完记住了最后交换的边界索引,下次循环就是以此边界索引进行比较,从而减少了不必要的比较次数。如果数据很多并且经过几轮排序后,后面的数据已经是有序了,那么这个提升就会很大了。文章来源地址https://www.toymoban.com/news/detail-445018.html

优化版本 综合版本
第一轮比较 7 第一轮比较 7
第二轮比较 6 第二轮比较 2
第三轮比较 5 第三轮比较 1

总结

  • 基础版本:通用版本,整个排列数据完全无序,处于散列状态
  • 优化版本:通过增加布尔变量 isOrderly 作为标记,如果没有元素交换了,说明剩下的元素已经有序了,不用进行下一轮的排序,排序完成,优化不必要的比较轮次
  • 综合版本:针对一轮排序的比较次数,具体是通过交换元素时记录下它的边界 borderIndex ,边界之前是无序的,边界之后是有序的,有序的那部分就可以不用再比较了,优化掉不必要的比较次数

到了这里,关于(四)Java算法:冒泡排序的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • (四)Java算法:冒泡排序

       冒泡排序 (Bubble Sort),是一种计算机科学领域的较简单的排序算法。它的工作原理是:它重复地走访过要排序的元素列,依次比较两个相邻的元素,如果不是指定顺序(比如从小达到)就把他们交换过来。走访元素的工作是重复地进行,直到没有相邻元素需要交换,也

    2024年02月04日
    浏览(76)
  • Java-三个算法冒泡-选择排序,二分查找

    Java算法: 冒泡排序; 解析:将前后两个数对比,将大的数(或小的)调换至后面,每轮将对比过程中的最大(或最小)数,调到最后面。每轮对比数减一;初始对比数为数组长度-1. 选择排序: 解析:选择第一个数依次与其他元素对比,数值小的或(大的)交换位置至前方(

    2024年02月11日
    浏览(29)
  • (java版)排序算法----【冒泡,选择,插入,希尔,快速排序,归并排序,基数排序,堆排序】超详细~~

    目录 冒泡排序(BubbleSort): 代码详解:  冒泡排序的优化:  选择排序(SelectSort): 代码详解:  插入排序(InsertSort): 代码详解:  希尔排序(ShellSort):  法一(交换法)代码详解:  法二(移位法--插入排序的优化)代码详解: 快速排序(QuickSort):  代码详解:  归并排

    2024年02月20日
    浏览(35)
  • 七大排序算法——冒泡排序,通俗易懂的思路讲解与图解(完整Java代码)

    排序:所谓排序,就是使一串记录,按照其中的某个或某些的大小,递增或递减的排列起来的操作。 上述待排序的数中,有两个5。 将 前面 的5标记一个a, 将 后面 的5标记一个b。 通过算法进行排序后,这一组数就有序了, 但是要看两个相同的5的位置是否有改变。

    2024年02月16日
    浏览(28)
  • 【数据结构与算法】排序算法:冒泡排序,冒泡排序优化,选择排序、选择排序优化

    目录 一、冒泡排序 1、冒泡排序思想 2、冒泡排序算法的性能分析 代码实现: 二、选择排序 1、选择排序思想 2、选择排序算法的性能分析  代码实现: 1、冒泡排序思想 冒泡排序的基本思想是通过相邻元素之间的比较和交换来逐步将最大(或最小)的元素移到右边(或左边

    2024年01月19日
    浏览(38)
  • Java常见算法_常见的查找算法和排序算法——简介及代码演示

            在本文中我将介绍Java中的常见算法,查找算法包括基本查找、二分查找、插值查找和分块查找。排序算法包括冒泡排序、选择排序、插入排序和快速排序 1.基本查找: 代码: 这是简单的基本查找,通过遍历数组来查看元素是否存在 运行结果: 基本查找小练习: 代

    2024年04月10日
    浏览(30)
  • C++常见排序算法——冒泡排序算法

    首先说一下冒泡排序的基本算法思想: 它重复地走访过要排序的元素列,依次比较两个相邻的元素,如果顺序(如从大到小、首字母从Z到A)错误就把他们交换过来。 这个算法的名字由来是因为越小的元素会经由交换慢慢“浮”到数列的顶端(升序或降序排列),就如同碳酸

    2023年04月08日
    浏览(27)
  • 排序算法:冒泡排序

    冒泡排序是入门级的算法,但也有一些有趣的玩法。通常来说,冒泡排序有三种写法: 一边比较一边向后两两交换,将最大值 / 最小值冒泡到最后一位; 经过优化的写法:使用一个变量记录当前轮次的比较是否发生过交换,如果没有发生交换表示已经有序,不再继续排序;

    2024年02月11日
    浏览(31)
  • 排序:冒泡排序算法分析

    基于“交换”的排序︰ 根据序列中两个元素的比较结果来对换这两个记录在序列中的位置。 交换排序包括 冒泡排序 和 快速排序 。 1.算法原理 从后往前(或从前往后)两两比较相邻元素的值, 若为逆序(即 A [ i − 1 ] A [ i ] A[i-1]A[i] A [ i − 1 ] A [ i ] ) ,则交换它们,直到

    2024年02月07日
    浏览(31)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包