冒泡排序详解


概述:

一种将数组中无序元素按照大小规则依次排列的方法。
最小或最大的元素会像水中的气泡一样"漂浮"到数组的一端,故得名"冒泡排序"。


原理:

对数组中的元素两两相比,根据比较的结果,将大小不同的元素通过第三变量互换、分开放置。当上述过程重复足够多次时,便实现对所有元素的有序排列。
我们也可以用一句话概括冒泡排序原理:相邻元素比较大小,交换位置,重复上述过程。


实现冒泡排序代码的流程结构:

按照我们之间学过的流程结构,我们可以确定冒泡排序需要用到的结构有:

顺序结构:用于实现交换位置的功能。
选择结构:用于实现判断相邻元素大小的功能。
循环结构:用于重复执行选择结构和顺序结构的功能。


冒泡排序的子功能

我们来按照功能依次展开说明:

1.交换位置功能:
我们先创建一个数组,在数组中放入元素。

        int[] arr = {1,2,3,5,4};//数组的静态初始化

我们可以把数组看成一列火车,每个下标对应的位置都是一节车厢,一节车厢装着一个元素。

我们可以得到数组下标位置和元素的关系如下:

arr[0] arr[1] arr[2] arr[3] arr[4]
1 2 3 5 4

我们现在要交换5和4元素的位置,使数组的顺序变成{1,2,3,4,5},怎么交换?

常见的方法是定义一个临时变量,用这个临时变量保存两个元素中的一个,相当于做了个备份,再将两个元素中的没有备份的赋值给另一个,把临时变量保存的元素、备份的赋值给那个一开始没有备份的元素,这样就完成了交换。

我们用图片来看更直观:

用代码实现就是这样:

    int temp = arr[3];
    arr[3] = arr[4];
    arr[4] = temp;

可能有细心的小伙伴们好奇,如果我备份的是4不是5呢?
图片安排:

用代码实现就是这样:

    int temp = arr[4];
    arr[4] = arr[3];
    arr[3] = temp;

看好了哈,临时变量的选取不影响互换结果。

2.判断相邻元素的大小功能:
我们使用if条件语句判断相邻元素大小关系是否满足条件。
在两相邻元素关系中,我习惯称下标位置小的元素为"左元素",下标位置大的元素为"右元素"。
根据冒泡排序原理,我们会先比较相邻元素大小,只有满足大小关系的两元素才交换位置。

如果"左元素"大于"右元素"

我们使用交换位置功能交换相邻位置的数据,"左右元素的大小关系"会反转,那么大的元素会在右边,小的元素会在左边。

"右元素"大于"左元素"同理。

3.重复执行和遍历元素的功能
不计交换位置的次数,
假如数组中只有2个元素,两两相较我们最少比较1次才实现整个数组的排序。
假如数组中有3个元素,两两相较,我们最少需要比较3次才实现整个数组的排序。

比较次数 arr[0] arr[1] arr[2]
初始值 1 2 3
1次 2 1 3
2次 2 3 1
3次 3 2 1
假如数组中有4个元素,两两相较,我们最少需要比较6次才能实现整个数组的排序
比较次数 arr[0] arr[1] arr[2]
:-: :-: :-: :-:
初始值 6 7 8
1次 7 6 8
2次 7 8 6
3次 7 8 9
4次 8 7 9
5次 8 9 7
6次 9 8 7

通过观察数组下标位置和比较次数的变化,可以得出关系:

数组中有2个元素,比较并交换1次,即可完成排序。

数组中有3个元素,比较并交换2次,数组下标的循环变量需要回归到0,此时数组中有1个数处在最终位置,不需要交换。
剩下需要比较的元素,相当于只有2个元素数组的情况,数组下标的循环变量需要回归到0,只要比较并交换1次,整个数组即可完成排序,整个过程中数组下标的循环变量需要归零1次。

数组中有4个元素,比较并交换3次,数组下标的循环变量需要回归到0,此时数组中有1个数处在最终位置,不需要交换。
剩下需要比较的元素,相当于只有3个元素数组的情况,数组下标的循环变量需要回归到0,比较并交换2次,剩下需要比较的元素,相当于只有2个元素数组的情况,数组下标的循环变量需要回归到0,只要比较并交换1次,整个数组即可完成排序,整个过程中数组下标的循环变量需要归零3次。

也就是说,长度为x的数组,比较并交换(x-1)次,数组下标的循环变量需要回归到0,需要比较并交换(x-2)次,数组下标的循环变量需要回归到0,比较并交换(x-n)=1次,整个数组即可完成排序,整个过程中数组下标的循环变量需要归零(x-1)次,每次归零后比较并交换的次数要比上一次小1。

我们可以用嵌套for循环实现重复执行和遍历数组元素的功能,根据嵌套循环【1次外循环,1轮内循环】的特点:

外循环变量最小值【i = 0】、最大值【i = 数组长度 - 1】。由于【每次归零后比较并交换的次数要比上一次小1】且外循环变量有自增1的特点,因此内循环变量最小值【j = 0】、最大值【j = 数组长度 - 1 - i】。

所以我们可以写出代码:

        int[] arr = {6,7,8,9};
        System.out.print("初始顺序:");
        for (int i = 0; i < arr.length; i++) {
            System.out.print(arr[i]+",");
        }
        System.out.print("目标顺序:9,8,7,6");
        System.out.println("\n-----------------");

        int temp = 0;
        int count = 0;
        for (int i = 0; i < arr.length - 1; i++) {
            for (int j = 0; j < arr.length - i - 1; j++) {

                System.out.println("第"+(i + 1)+"轮第"+(j + 1)+"次");

                //后小前大,倒序
                if (arr[j + 1] > arr[j]){

                    System.out.print("互换前:");
                    for (int k :
                            arr) {
                        if (k == arr[j])
                            System.out.print("["+k+",");
                        else if(k == arr[j + 1])
                            System.out.print(k+"],");
                        else
                            System.out.print(k+",");
                    }

                    temp = arr[j + 1];
                    arr[j + 1] = arr[j];
                    arr[j] = temp;

                    System.out.print("互换后:");
                    for (int k :
                            arr) {
                        if (k == arr[j])
                            System.out.print("["+k+",");
                        else if(k == arr[j + 1])
                            System.out.print(k+"],");
                        else
                            System.out.print(k+",");
                    }
                    System.out.println();
                }else{
                    System.out.println("不满足条件,没有互换");
                }
                count++;
            }
        }
        System.out.println("-----------------");
        System.out.println("总共比较"+count+"次");

运行结果:

初始顺序:6,7,8,9,目标顺序:9,8,7,6
-----------------
第1轮第1次
互换前:[6,7],8,9,互换后:[7,6],8,9,
第1轮第2次
互换前:7,[6,8],9,互换后:7,[8,6],9,
第1轮第3次
互换前:7,8,[6,9],互换后:7,8,[9,6],
第2轮第1次
互换前:[7,8],9,6,互换后:[8,7],9,6,
第2轮第2次
互换前:8,[7,9],6,互换后:8,[9,7],6,
第3轮第1次
互换前:[8,9],7,6,互换后:[9,8],7,6,
-----------------
总共比较6次


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM