目录

  • 概念
  • 举例
  • 原理
  • 第一版代码实现
  • 第一版缺点
  • 第一版优化
  • 第二版代码实现
  • 第二版缺点
  • 第二版优化
  • 第三版代码实现
  • 🌟个人总结
  • 最后


概念

冒泡排序是一种基础的交换排序。像汽水中的气泡一样向上浮动。

举例

5

8

6

3

9

2

1

7

将8个数字组成的数列按照从小到大顺序排序。

原理

相邻元素两两比较,元素大的放到右边,值相等不交换。

过程如下:

冒泡排序java实现 冒泡排序java解析_冒泡排序java实现

每一轮都会遍历所有元素,进行两两比较,所以说一共需要遍历7轮(元素数量-1),平均时间复杂度是O(n2)。

第一版代码实现

import java.util.Arrays;

public class bubbleSort {
    public static void sort(int[] array) {
        for (int i = 0; i < array.length - 1; i++) {
            for (int j = 0; j < array.length - i - 1; j++) {
                int tmp = 0;
                if (array[j] > array[j + 1]) {
                    tmp = array[j];
                    array[j] = array[j+1];
                    array[j+1] = tmp;
                }
            }
            System.out.println("第"+(i+1)+"轮"+Arrays.toString(array));
        }
    }

    public static void main(String[] args) {
        int[] array = new int[]{5,8,6,3,9,2,1,7};
        sort(array);
        System.out.println("最后排序结果是"+Arrays.toString(array));

    }
}

运行结果:

冒泡排序java实现 冒泡排序java解析_冒泡排序_02

第一版缺点

可以发现,第六轮之后已经有序,代码却还是又进行了第七轮。若需要排序的序列为{3,4,2,1,4,5,6,7,8},那么按照以上版本

冒泡排序java实现 冒泡排序java解析_冒泡排序java实现_03


可以看出,第3轮已经排好序,程序却又做了4轮的无用功。

第一版优化

这种情况下,如果可以判断出数列已经有序,并作出标记,就可以不必执行剩下几轮排序,提前结束工作。

第二版代码实现

import java.util.Arrays;

public class bubbleSort {
    public static void sort(int[] array) {
        for (int i = 0; i < array.length - 1; i++) {
            //有序标记,每一轮初始值都是true
            boolean isSorted = true;
            for (int j = 0; j < array.length - i - 1; j++) {
                int tmp = 0;
                if (array[j] > array[j + 1]) {
                    tmp = array[j];
                    array[j] = array[j+1];
                    array[j+1] = tmp;
                    //本轮有元素交换,所以不是有序数列,标记为false,还需要下一轮判断
                    isSorted = false;
                }
            }
            //若本轮没有元素交换,跳出循环
            if(isSorted){
                break;
            }
            System.out.println("第"+(i+1)+"轮"+Arrays.toString(array));
        }
    }

    public static void main(String[] args) {
        int[] array = new int[]{3,4,2,1,5,6,7,8};
        sort(array);
        System.out.println("最后排序结果是"+Arrays.toString(array));

    }
}

这一版增加了一个布尔变量isSorted作为标记,若在本轮中有元素交换,则说明数列无序,继续执行下一轮排序;若没有元素交换,则说明数列已经有序,直接跳出大循环。

运行结果:

冒泡排序java实现 冒泡排序java解析_System_04

第二版缺点

看一下每一轮中两两元素交换的过程

冒泡排序java实现 冒泡排序java解析_算法_05

图中可以发现,其实5,6,7,8这四个数字已经是有序的了,程序却又进行两两比较,这个过程其实duck不必。

第二版优化

可以在每一轮排序后,记录下来最后一次元素交换的位置,该位置就是无序数列的边界,再往后就是有序区了。

第三版代码实现

import java.util.Arrays;

public class bubbleSort {
    public static void sort(int[] array) {
        //记录最后一次交换的位置
        int lastExchangeIndex = 0;
        //无序数列的边界,每次比较只需要比到这里为止
        int sortBoder = array.length - 1;
        for (int i = 0; i < array.length - 1; i++) {
            //有序标记,每一轮初始值都是true
            boolean isSorted = true;
            for (int j = 0; j < sortBoder; j++) {
                int tmp = 0;
                if (array[j] > array[j + 1]) {
                    tmp = array[j];
                    array[j] = array[j+1];
                    array[j+1] = tmp;
                    //本轮有元素交换,所以不是有序数列,标记为false,还需要下一轮判断
                    isSorted = false;
                    //更新为最后一次交换元素的位置
                    lastExchangeIndex = j;
                }
            }
            sortBoder = lastExchangeIndex;
            //若本轮没有元素交换,跳出循环
            if(isSorted){
                break;
            }
            System.out.println("第"+(i+1)+"轮"+Arrays.toString(array));
        }
    }

    public static void main(String[] args) {
        int[] array = new int[]{3,4,2,1,5,6,7,8};
        sort(array);
        System.out.println("最后排序结果是"+Arrays.toString(array));

    }
}

运行结果:

冒泡排序java实现 冒泡排序java解析_System_06

每一轮交换详情

冒泡排序java实现 冒泡排序java解析_System_07


这一版的代码中,sortBorder是无序数列的边界。在每一轮排序过程中,处于sortBorder之后的代码就不需要进行比较。这就是

第一轮中5,6,7,8不需要比较;

第二轮中4,5,6,7,8不需要比较;

第三轮中,3,4,5,6,7,8不需要比较

🌟个人总结

  • 冒泡排序思想:

相邻元素两两比,不符要求换位置。
一共比较length轮,每轮比较length次。

  • 冒泡排序复杂度:
    O(n2)—O(n)—O(n2)—O(1)[平均—最好—最坏—空间复杂度]
  • 冒泡排序特点:稳定
  • 冒泡排序代码框架:
定义最后交换的位置
定义每一轮需要交换的元素的边界
for(int i = 0;i<数组长度;i++){	//外循环控制排序的轮次
	假设数组已经是有序的了,接下来看本轮是否有元素交换
	for(int j = 0;j < 边界;j++){		//内循环控制每一轮中元素的交换
		如果左边大于右边{
			两数交换
			
			记录交换的最后位置
			因为有元素交换了,所以本轮数组是无序的
		}
	}

	标记边界
	本轮没有元素交换,说明数组已经有序,跳出外循环		
}
  • 根据框架默写一遍完整代码:
    新建文件:Sort.java
import java.util.Arrays;
public class Sort {
	public static void bubbleSort(int[] arr) {
		int lastExchangeIndex = 0;		//最后交换位置
		int sortBorder = arr.length - 1;		//无序数列边界
		for(int i = 0;i < arr.length - 1;i++){		//外循环控制轮次
			boolean isSorted = true;		//有序标记
			for(int j = 0;j < sortBorder;j++){		//内循环控制元素交换次数
				if(arr[j] > arr[j+1]){
					int temp = arr[j];
					arr[j] = arr[j+1];
					arr[j+1] = temp;
					
					lastExchangeIndex = j;
					isSorted = false;
				}
			}
			sortBorder = lastExchangeIndex;
			if(isSorted)
				break;
		}
	}

	public static void main(String[] args) {
		int[] arr = {3,4,2,1,5,6,7,8};
		bubbleSort(arr);
		System.out.println(Arrays.toString(arr));	
	}
}

冒泡排序java实现 冒泡排序java解析_数据结构_08


nace!

最后

其实这并不是最优的,还有一种排序算法是基于冒泡排序的一种升级排序法:鸡尾酒排序。