Day26--冒泡排序

Day26--冒泡排序

冒泡排序无疑是最为出名的排序算法之一:总共有八大排序

冒泡的代码还是相当简单的,两层循环:外层冒泡轮数,里层依次比较:江湖中人人尽皆知。

我们看到嵌套循环:应该立马就可以得出这个算法的时间复杂度为 O (n²)。思考:如何优化?

1. 冒泡排序的思路理解:

一、冒泡排序的起名由来:

冒泡排序的主要思想是通过多次遍历要排序的数列,每次比较相邻的两个元素,如果它们的顺序错误就把它们交换过来。

这样经过多次遍历,最大(或最小)的元素就会像气泡一样 “浮” 到数列的顶端。

二、具体过程

  1. 第一轮遍历:
    • 从数列的第一个元素开始,依次比较相邻的两个元素。
    • 如果前一个元素比后一个元素大,就交换它们的位置。
    • 这样在第一轮遍历结束后,最大的元素就会被 “冒泡” 到数列的最后一个位置。
  2. 第二轮遍历:
    • 由于最大的元素已经在最后位置,所以第二轮遍历只需要对前面的 n - 1 个元素进行操作。
    • 重复第一轮的比较和交换过程,将第二大的元素 “冒泡” 到数列的倒数第二个位置。
  3. 依此类推:
    • 每一轮遍历都将未排序部分中的最大元素 “冒泡” 到相应位置。
    • 经过 n - 1 轮遍历后,整个数列就完成了排序。

三、示例说明

假设有一个整数数列 [8, 5, 2, 4, 3]。

  1. 第一轮遍历:

    • 比较 8 和 5,因为 8 > 5,所以交换位置,数列变为 [5, 8, 2, 4, 3]。

    • 比较 8 和 2,交换位置,变为 [5, 2, 8, 4, 3]。

    • 比较 8 和 4,交换位置,变为 [5, 2, 4, 8, 3]。

    • 比较 8 和 3,交换位置,变为 [5, 2, 4, 3, 8]。此时第一轮遍历结束,最大的元素 8 被 “冒泡” 到了最后位置。

  2. 第二轮遍历:

    • 比较 5 和 2,交换位置,变为 [2, 5, 4, 3, 8]。

    • 比较 5 和 4,交换位置,变为 [2, 4, 5, 3, 8]。

    • 比较 5 和 3,交换位置,变为 [2, 4, 3, 5, 8]。第二轮结束,第二大的元素 5 被 “冒泡” 到了倒数第二个位置。

      和第一轮相比,少了一次比较

  3. 第三轮遍历:

    • 比较 2 和 4,不交换位置,数列仍为 [2, 4, 3, 5, 8]。

    • 比较 4 和 3,交换位置,变为 [2, 3, 4, 5, 8]。第三轮结束,第三大的元素 4 被 “冒泡” 到了相应位置。

      和第二轮相比,少了一次比较

  4. 第四轮遍历:

    • 比较 2 和 3,不交换位置,数列保持 [2, 3, 4, 5, 8] 不变。第四轮结束,整个数列完成排序。

      和第三轮相比,少了一次比较

四、具体分析

从第二轮遍历开始,每一轮遍历,都比上一轮少一次比较。

每一轮遍历,都会产生出一个最大或者最小的数,排在最前面或者最后面,因此比较次数少一次

遍历的轮数:array.length-1

五、时间复杂度

元素个数:n; 当前遍历轮数: i

时间复杂度:

  • 最坏情况下,即数列是逆序的,需要进行 n - 1 轮遍历,每一轮遍历都要比较和交换 n - i 次(i 表示当前轮数),所以总的比较和交换次数为 n (n - 1)/2,时间复杂度为 O (n²)。
  • 最好情况下,即数列已经是有序的,只需要进行一轮遍历就可以完成排序,时间复杂度为 O (n)。不过这种情况出现的概率较低。
  1. 时间复杂度的理解:以冒泡排序为例:

    在计算机科学中,时间复杂度为 O (n²) 表示算法的运行时间与输入数据规模 n 的平方成正比。

    具体来说,当输入数据规模为 n 时,算法的执行时间可以用一个包含 n² 的表达式来近似表示。例如,如果一个算法对于规模为 n 的输入数据需要执行 n² 次基本操作,那么这个算法的时间复杂度就是 O (n²)。

    以冒泡排序为例,它有两层循环,外层循环执行 n - 1 次(n 为待排序数据的数量),内层循环在每一轮外层循环中执行的次数逐渐减少,但总体上也与 n 相关。对于一个包含 n 个元素的列表进行冒泡排序,大约需要比较和交换的次数为 n (n - 1)/2,当 n 很大时,这个数量级接近 n²,所以冒泡排序的时间复杂度为 O (n²)。

n (n - 1)/2的计算:

n-1+n-2+n-3+...+n-n=n*n-(1+2+...+n)=n *2 n/2-n (n + 1)/2=n/2 * (n-1)

2.冒泡排序的示例

从小到大排序

​ 示例:数组a{1,3,2},进行从小到大排序

​ 使用方法:1.用Arrays自带的方法

​ 2.冒泡排序

package com.liu.www.array;

import java.util.Arrays;

public class ArrayDemo07 {
    public static void main(String[] args) {
        int[] a={1,3,2};
        sort(a);
        System.out.println(Arrays.toString(a));


    }
    //冒泡排序
    //1. 比较两个相邻的元素大小。不行就交换位置,来满足:大的排后边,小的排前面
    //2. 每一轮遍历,都会产生出一个最大或者最小的数
    //3.下一轮可以少一次比较
    //4.以此类推,直到结束


    //下面的方法是从小往大排序
    public static int[] sort(int[] array){
        int temp=0;
        //外层循环:判断循环的次数
        for (int i = 0; i < array.length-1; i++) {
            //内层循环:比较两个数的位置。如果第一个数比第二个数大,则交换位置
            for (int j = 1; j <array.length-1-i; j++) {
                if(array[j]>array[j+1]){
                    temp=array[j+1];
                    array[j+1]=array[j];
                    array[j]=temp;
                }
            }
        }return array;

    }
    /*
    1 4 2 3   arrays.length=4                     i=0;i<3    j=0;j<3
    1    4                         1423                      j=0;j<3
    4    2--->   2     4           1243                      j=1;j<3
    4    3--->   3     4           1234                      j=2;j<3

     */
}

优化:

当已经排好序的时候,就可以节省遍历次数了

//下面的方法是从小往大排序
    public static int[] sort(int[] array){
        int temp=0;
        boolean flag=true;//通过flag标识符,减少没有意义的比较
        //外层循环:判断循环的次数
        for (int i = 0; i < array.length-1; i++) {
            //内层循环:比较两个数的位置。如果第一个数比第二个数大,则交换位置
            for (int j = 0; j <array.length-1-i; j++) {
                if(array[j]>array[j+1]){
                    temp=array[j+1];
                    array[j+1]=array[j];
                    array[j]=temp;
                    flag=false;
                }
                if(flag==true){
                    break;
                }
            }
        }return array;

    }

通过flag标识符,减少没有意义的比较。

当内循环第一次循环结束之后,也就是第一轮遍历结束之后,如果第二轮一直都没有进入if执行语句,也就是array[j]<=array[j+1]一直成立,那么说明,排序完成,就可以跳出循环了。

错误示例1:

import java.util.Arrays;

public class Exercise2 {
    public static void main(String[] args) {
          int[] a={1,3,2};
        System.out.println( Arrays.sort(a));

    }

    }

好的,下面来分析一下这段代码的错误以及如何改正:

错误分析

在你给出的代码中,Arrays.sort()方法是用于对数组进行排序的,但它的返回值是void,也就是它没有返回值。所以当你在System.out.println()中直接调用Arrays.sort(a)时,就会出错,因为System.out.println()需要传入一个可以转换为字符串的值来进行输出,而void类型显然不符合要求。

改正后的代码

要实现输出数组排序之后的结果,正确的做法是先对数组进行排序,然后再使用Arrays.toString()方法将排序后的数组转换为字符串进行输出。以下是改正后的代码:

import java.util.Arrays;

public class Exercise2 {
    public static void main(String[] args) {
        int[] a = {1, 3, 2};

        // 对数组a进行排序
        Arrays.sort(a);

        // 将排序后的数组转换为字符串并输出
        System.out.println(Arrays.toString(a));
    }
}

在上述改正后的代码中:

  • 首先通过Arrays.sort(a)对整数数组a进行排序操作,此时数组a的元素顺序会被改变为升序排列(在Arrays.sort()默认情况下是升序排序)。
  • 然后使用Arrays.toString()方法将排序后的数组a转换为一个字符串表示形式,这个字符串会以[开始,以]结尾,数组元素之间用逗号和空格分隔,比如如果数组排序后是[1, 2, 3],那么Arrays.toString(a)返回的字符串就是[1, 2, 3]
  • 最后通过System.out.println()将这个表示排序后数组的字符串输出到控制台,这样就实现了输出数组排序之后的结果的需求。

错误示例2:

import java.util.Arrays;

public class Exercise2 {
    public static void main(String[] args) {
          int[] a={1,3,2};
        Arrays.sort(a);
        System.out.println(a.toString());

    }

    }

分析:

以下是对这段代码错误原因的分析:

数组对象直接调用toString方法的问题

在Java中,数组是一种特殊的对象类型。当你直接对数组对象(如这里的a)调用toString方法时,它并不会按照你期望的那样返回数组元素的内容。实际上,数组对象的toString方法默认返回的是数组的一个哈希码表示形式(类似[I@10f87f48这种格式),而不是数组中各个元素的值以某种可读的形式呈现出来。

正确的做法

要想正确输出已经排序好的数组的元素内容,应该使用Arrays.toString方法。就像下面这样修改代码:

import java.util.Arrays;

public class Exercise2 {
    public static void main(String[] args) {
        int[] a = {1, 3, 2};

        Arrays.sort(a);

        // 使用Arrays.toString方法来获取数组元素内容的字符串表示并输出
        System.out.println(Arrays.toString(a));
    }
}

在修改后的代码中,Arrays.toString(a)会遍历已经排序好的数组a的每个元素,将它们转换为字符串形式,并按照[开头、元素之间用逗号和空格分隔、]结尾的格式生成一个新的字符串,然后通过System.out.println输出这个字符串,这样就能正确展示出排序后数组的元素情况了。

posted @   1hahahahahahahaha  阅读(25)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 零经验选手,Compose 一天开发一款小游戏!
· 因为Apifox不支持离线,我果断选择了Apipost!
· 通过 API 将Deepseek响应流式内容输出到前端
点击右上角即可分享
微信分享提示