冒泡详解释

这是第一次写博客,我作为一个程序小白也不知道写点什么,所以就打算记录一下自己的一个学习过程以及对学习的理解吧!
下面是冒泡算法的详解:

package com.starryNight.test;

import java.util.Arrays;

/**
 * 注释太tm多了,关键是你们要“详解”,能看懂就行,我就不在乎什么语文格式了
 * @author starryNight
 * @version 1.0.0
 * */
public class Test {
    /**
     * 此方法为主要实现方法
     * 用于对数组中的数据进行冒泡排序
     * @param arr
     * */
    private static void bubbleSort_relese1_0(int arr[]){
        //众所周知,冒泡算法的主要结构是这样的。。。。
        int temp=0;
        for (int i=0;i<arr.length;i++) {
            for (int j=0;j<arr.length-1;j++) {
                if(arr[j]>arr[j+1]){
                    temp=arr[j];
                    arr[j]=arr[j+1];
                    arr[j+1]=temp;
                }
            }
        }
        //ok,为什么要这么写呢?
        //冒泡算法的原理:第一个数与第二个数进行比较,如果满足条件位置不变.
        //             再把第二个数与第三个数进行比较,不满足条件则替换位置.
        //             再把第三个数与第四个数进行比较,以此类推
        //那为什么要减j<arr.length-1呢?以长度为5的数组举个例子,当数组第4个数比第5个数大时要实现前后交换,那么如下:
        //      arr[4]>arr[4+1]这样?好吧,看似没有问题,那么问题:长度为5的数组下标最大是几?
        //      所以如果不减1的话,在比较的途中会发生数组越界,小伙伴们在实验时可以把-1去掉,然后看看是否会报如下异常:
        //      java.lang.ArrayIndexOutOfBoundsException
        //那么执行过程中发生了什么呢?我们以一个数组{5,4,3,2,1}为例子
        //我们将每一次外循环定义为outer loop,内循环定义为innern loop
        //第一次outer loop i=0;i<5                              第二次outer loop i=1;i<5
        //     第一次inner loop j=0;j<4 循环完毕的结果:{4,5,3,2,1}     第一次inner loop j=0;j<4 循环完毕的结果:{3,4,2,1,5}
        //     第二次inner loop j=1;j<4 循环完毕的结果:{4,3,5,2,1}     第二次inner loop j=1;j<4 循环完毕的结果:{3,2,4,1,5}
        //     第三次inner loop j=2;j<4 循环完毕的结果:{4,3,2,5,1}     第三次inner loop j=2;j<4 循环完毕的结果:{3,2,1,4,5}
        //     第四次inner loop j=3;j<4 循环完毕的结果:{4,3,2,1,5}     第四次inner loop j=3;j<4 循环完毕的结果:{3,2,1,4,5}
        //第一次outer loop结束最终结果:{4,3,2,1,5}                第二次outer loop结束最终结果:{3,2,1,4,5}
        //第三次outer loop i=2;i<5                              第四次outer loop i=3;i<5
        //     第一次inner loop j=0;j<4 循环完毕的结果:{2,3,1,4,5}     第一次inner loop j=0;j<4 循环完毕的结果:{1,2,3,4,5}
        //     第二次inner loop j=1;j<4 循环完毕的结果:{2,1,3,4,5}     第二次inner loop j=1;j<4 循环完毕的结果:{1,2,3,4,5}
        //     第三次inner loop j=2;j<4 循环完毕的结果:{2,1,3,4,5}     第三次inner loop j=2;j<4 循环完毕的结果:{1,2,3,4,5}
        //     第四次inner loop j=3;j<4 循环完毕的结果:{2,1,3,4,5}     第四次inner loop j=3;j<4 循环完毕的结果:{1,2,3,4,5}
        //第三次outer loop结束最终结果:{2,1,3,4,5}                第四次outer loop结束最终结果:{1,2,3,4,5}
        //第五次outer loop i=4;i<5
        //     第一次inner loop j=0;j<4 循环完毕的结果:{1,2,3,4,5}
        //     第二次inner loop j=1;j<4 循环完毕的结果:{1,2,3,4,5}
        //     第三次inner loop j=2;j<4 循环完毕的结果:{1,2,3,4,5}
        //     第四次inner loop j=3;j<4 循环完毕的结果:{1,2,3,4,5}
        //第五次outer loop结束最终结果:{1,2,3,4,5}
        //ok,执行完毕,以上是我们{5,4,3,2,1}这个数组经过冒泡过后的最终结果
        //嗯,有没有发现什么问题呢? 外循环第四次的时候就已经得到了我们想要的结果,既然如此为何要外循环5次呢?
        //然后我们看看冒泡的定义:前一个叔和后一个数两两比较,小的前移大的后移。
        //   我们这里是用的从小到大的顺序,每一次冒泡(结束一次外循环,我们称之为冒了一次泡,因为外循环一次结束过后最大的数会到最上面去,
        //以此类推。。。)是不是最大的数跑最上面去了?既然如此当第四次泡冒完了,最小的泡泡(也就是数字)已经在最底下了。所以还需要多冒一次吗?
        //那是否可以修改一下代码:i<arr.length-1,这样一来不就只冒四次泡了吗?完美
    }
    /**
     * 这个方法,我们用来执行第一次优化的冒泡代码
     * @param arr
     * */
    private static void bubbleSort_relese1_1(int arr[]){
        //上个方法我们说到这5个数字冒四次泡,
        int temp=0;
        for (int i=0;i<arr.length-1;i++) {
            for (int j=0;j<arr.length-1;j++) {
                if(arr[j]>arr[j+1]){
                    temp=arr[j];
                    arr[j]=arr[j+1];
                    arr[j+1]=temp;
                }
            }
        }
        //结束完毕,结果和上面的一支,但是少了一次执行过程,因为四次之后最小的泡泡已经垫底,不需要再冒了,一下是结果:
        //第一次outer loop i=0;i<5                              第二次outer loop i=1;i<5
        //     第一次inner loop j=0;j<4 循环完毕的结果:{4,5,3,2,1}     第一次inner loop j=0;j<4 循环完毕的结果:{3,4,2,1,5}
        //     第二次inner loop j=1;j<4 循环完毕的结果:{4,3,5,2,1}     第二次inner loop j=1;j<4 循环完毕的结果:{3,2,4,1,5}
        //     第三次inner loop j=2;j<4 循环完毕的结果:{4,3,2,5,1}     第三次inner loop j=2;j<4 循环完毕的结果:{3,2,1,4,5}
        //     第四次inner loop j=3;j<4 循环完毕的结果:{4,3,2,1,5}     第四次inner loop j=3;j<4 循环完毕的结果:{3,2,1,4,5}
        //第一次outer loop结束最终结果:{4,3,2,1,5}                第二次outer loop结束最终结果:{3,2,1,4,5}
        //第三次outer loop i=2;i<5                              第四次outer loop i=3;i<5
        //     第一次inner loop j=0;j<4 循环完毕的结果:{2,3,1,4,5}     第一次inner loop j=0;j<4 循环完毕的结果:{1,2,3,4,5}
        //     第二次inner loop j=1;j<4 循环完毕的结果:{2,1,3,4,5}     第二次inner loop j=1;j<4 循环完毕的结果:{1,2,3,4,5}
        //     第三次inner loop j=2;j<4 循环完毕的结果:{2,1,3,4,5}     第三次inner loop j=2;j<4 循环完毕的结果:{1,2,3,4,5}
        //     第四次inner loop j=3;j<4 循环完毕的结果:{2,1,3,4,5}     第四次inner loop j=3;j<4 循环完毕的结果:{1,2,3,4,5}
        //第三次outer loop结束最终结果:{2,1,3,4,5}                第四次outer loop结束最终结果:{1,2,3,4,5}
        //   观察上面得到的数据看似没有问题(如果你发现了问题也别说出来,就当你不知道,让我说!!!)。在第二次冒泡(也就是outer loop)中,5在
        //第一次冒泡中就已经冒到了最上面去,这是不是意味着我们已经知道了5是最大的,但是还是傻不拉几的拿5前面的数和5比较了一次。而第三次冒泡中
        //我们已经知道5是最大的,4是第二大的,然后我们却又傻不拉几的拿4和5比了一次,然后又拿4前面的数和4比了一次。第四次冒泡我怕就不说了。。
        //所以当我们知道了最大的数字,就不需要拿最大的数字和前面的比较,知道了第二大的就不需要拿最大的和第二大的比,也不需要拿第二大的和前一个
        //比。所以这意味着第一次冒泡我们无法确定谁最大,要两两比较4次,此时i的值为0。第二次冒泡,已近知道了最大的,所以只需两两比较3次,此时i
        //的值为1。第三次冒泡,已近知道了最大的数,第二大的数,只需两两比较2次,此时i的值为2。第四次冒泡,我们已经知道了最大的,第二大的,第三大
        //的,所以只需两两比较1次,此时i的值为3。那么如何靳准控制每次冒泡中两两比较的次数呢?修改代码:j<arr.length-1-i;
        //这样一来第一次冒泡j<4-0,四次两两比较。第二次冒泡j<4-1,三次两两比较。第三次冒泡j<4-2,两次两两比较。第四次冒泡j<4-3,一次两两比
        //较。完美
    }
    /**
     * 此方法用于执行又一次优化的冒泡代码
     * */
    public static void bubbleSort_relese1_2(int arr[]){
        //这是又一次优化的,原来是j<arr.length-1,现在是j<arr.length-1-i
        int temp=0;
        for (int i=0;i<arr.length-1;i++) {
            for (int j=0;j<arr.length-1-i;j++) {
                if(arr[j]>arr[j+1]){
                    temp=arr[j];
                    arr[j]=arr[j+1];
                    arr[j+1]=temp;
                }
            }
        }
        //废话不多说,看数据:
        //第一次outer loop i=0;i<5
        //     第一次inner loop j=0;j<4-0 循环完毕的结果:{4,5,3,2,1}
        //     第二次inner loop j=1;j<4-0 循环完毕的结果:{4,3,5,2,1}
        //     第三次inner loop j=2;j<4-0 循环完毕的结果:{4,3,2,5,1}
        //     第四次inner loop j=3;j<4-0 循环完毕的结果:{4,3,2,1,5}
        //第一次outer loop结束最终结果:{4,3,2,1,5}
        /*-----------------------------------------------*/
        //第二次outer loop i=1;i<5
        //     第一次inner loop j=0;j<4-1 循环完毕的结果:{3,4,2,1,5}
        //     第二次inner loop j=1;j<4-1 循环完毕的结果:{3,2,4,1,5}
        //     第三次inner loop j=2;j<4-1 循环完毕的结果:{3,2,1,4,5}
        //第二次outer loop结束最终结果:{3,2,1,4,5}
        /*-----------------------------------------------*/
        //第三次outer loop i=2;i<5
        //     第一次inner loop j=0;j<4-2 循环完毕的结果:{2,3,1,4,5}
        //     第二次inner loop j=1;j<4-2 循环完毕的结果:{2,1,3,4,5}
        //第三次outer loop结束最终结果:{2,1,3,4,5}
        /*-----------------------------------------------*/
        //第四次outer loop i=3;i<5
        //   第一次inner loop j=0;j<4-3 循环完毕的结果:{1,2,3,4,5}
        //第四次outer loop结束最终结果:{1,2,3,4,5}
        //ok这样一来不就去掉了重复的比较么,但是还有没有什么可以改进的呢?
        //请看版本bubbleSort_relese_2_0
    }
    private static void bubbleSort_relese_2_0(int arr[]){
        //这里要讲到一个东西,就是for循环。
        //for(表达式1(初始化变量,例如int i=0);表达式2(比较运算符,例如i<5);表达式3(自增变量,例如i++)){
        //  语句块...
        //}
        //它的执行过程是这样的:
        //   表达式1-->表达式2(若为真)-->语句块-->表达式3--表达式2(若为假)-->结束循环
        //嗯,我们发现当两两比较结束过后,这里面的语句块执行完毕,表达式3会执行,然后由表达式2来决定是否继续循环。
        //所以当我在语句块中做了我们想做的,即目的达到过后干嘛还浪费时间去执行表达式3,然后执行表达式2?直接break就好了。如下
        int temp=0;
        for (int i=0;i<arr.length-1;i++) {
            boolean flag=true;
            for (int j=0;j<arr.length-1-i;j++) {
                if(arr[j]>arr[j+1]){
                    temp=arr[j];
                    arr[j]=arr[j+1];
                    arr[j+1]=temp;
                    flag=false;
                }
            }
            if (flag) break;
        }
        //第一次outer loop i=0;i<5
        //     第一次inner loop j=0;j<4-0 循环完毕的结果:{4,5,4,3,2}
        //     第二次inner loop j=1;j<4-0 循环完毕的结果:{4,4,5,3,2}
        //     第三次inner loop j=2;j<4-0 循环完毕的结果:{4,4,3,5,2}
        //     第四次inner loop j=3;j<4-0 循环完毕的结果:{4,4,3,2,5}
        //第一次outer loop结束最终结果:{4,4,3,2,5}
        /*-----------------------------------------------*/
        //第二次outer loop i=1;i<5
        //     第一次inner loop j=0;j<4-1 循环完毕的结果:{3,4,2,1,5}
        //     第二次inner loop j=1;j<4-1 循环完毕的结果:{3,2,4,1,5}
        //     第三次inner loop j=2;j<4-1 循环完毕的结果:{3,2,1,4,5}
        //第二次outer loop结束最终结果:{3,2,1,4,5}
        /*-----------------------------------------------*/
        //第三次outer loop i=2;i<5
        //     第一次inner loop j=0;j<4-2 循环完毕的结果:{2,3,1,4,5}
        //     第二次inner loop j=1;j<4-2 循环完毕的结果:{2,1,3,4,5}
        //第三次outer loop结束最终结果:{2,1,3,4,5}
        /*-----------------------------------------------*/
        //第四次outer loop i=3;i<5
        //   第一次inner loop j=0;j<4-3 循环完毕的结果:{1,2,3,4,5}
        //第四次outer loop结束最终结果:{1,2,3,4,5}
    }
    public static void main(String[] args) {
        //检验真理的时候到了,我们来看看代码是否可以正确执行
//        int arr1[]={5,4,3,2,1};
//        bubbleSort_relese1_0(arr1);
//        System.out.println(Arrays.toString(arr1));
//
//        int arr2[]={10,9,8,7,6,5,4};
//        bubbleSort_relese1_1(arr2);
//        System.out.println(Arrays.toString(arr2));
//
//        int arr3[]={25,9,6,3,1,2,7};
//        bubbleSort_relese1_2(arr3);
//        System.out.println(Arrays.toString(arr3));

        int  arr4[]={10,9,8,7,6,5,4,3,2,1,0};
        bubbleSort_relese_2_0(arr4);
        System.out.println(Arrays.toString(arr4));
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值