冒泡排序(Bubble sort),是一种较简单的排序算法。这个算法的名字由来是因为越小的元素会经由交换慢慢“浮”到数列的顶端(升序或降序排列),就如同碳酸饮料中二氧化碳的气泡最终会上浮到顶端一样,故名“冒泡排序”。(PS:来源百度百科)
举例来说:36,26,27,2,4,19,50,48来说,会有多趟排序(size - 1),每一趟要排多次(size - k),这里列举出第一趟:
多趟排序的后的结果总结是这样的:
PS:这里留下一个思考,图里留了一个注意字样,在这里数组已经排序好了,但是还是会依次比较,你能想到什么方法优化吗?
它的动态执行过程如下动图所示:
PS:此动图来源于网络。
最坏时间复杂度 | 最好时间复杂度 | 空间复杂度 | 是否稳定 |
---|---|---|---|
O(n^2) | O(n) | O(1) | 稳定 |
public class BubbleSort { public static void main(String[] args) { // 直接定义一个数组 int[] nums = {36,26,27,2,4,19,50,48}; System.out.println("排序前的数组:" + Arrays.toString(nums)); sort(nums); System.out.println("排序前的数组:" + Arrays.toString(nums)); } /* * 对数组进行冒泡排序 * * @param nums 需要排序的数组 * */ private static void sort(int[] nums) { // 数组长度 len int len = nums.length; // 临时变量 temp int temp = 0; // 外层循环控制排序趟数,len个进行len - 1趟 for (int i = 0; i < len - 1; i++) { System.out.println("第"+ (i + 1) +"趟:"); // 内层循环控制比较的次数,第i趟比较i-1次 for (int j = 0; j < len - 1 - i; j++) { // 比较相邻的两个元素,若前面的数字大于后面的,交换位置 if (nums[j] > nums[j+1]) { temp = nums[j+1]; nums[j+1] = nums[j]; nums[j] = temp; } System.out.println(" "+"第"+ (j + 1) +"次:" + Arrays.toString(nums)); } } } }
在这里插一嘴,想起来自己刚接触冒泡排序的时候,感觉那个时候的自己就是一个菜逼,哈哈哈哈哈,不理解两个for的意义,写了好几遍之后还是不理解,似懂非懂。对了,当时还对交换数据位置哪里每次写都要纠结好久,想着怎么交换呀,拿笔在纸上比划半年,才写出来,后来找到了一个小技巧:起手临时变量,中间半交叉,收尾临时变量。仅供参考,大佬勿喷(小声BB)
输出的结果:
从运行的结果可以看出,从红色标记开始,后面的排序的已经是有序的,但是代码还是要往后面执行,因此说明代码是可以进行优化,这里你可以思考一下怎么去优化这个问题。
增加一个标志位,当每次发生交换的时候,就进行标记,如果没有发生交换,不标记,也就是说此时数组已经有序,直接跳出循环,于此同时再记录一下最后一次交换元素的位置,即可完成对这个排序的优化。
代码如下所示:
public class BubbleSort { public static void main(String[] args) { // 直接定义一个数组 int[] nums = {36,26,27,2,4,19,50,48}; System.out.println("排序前的数组:" + Arrays.toString(nums)); sort(nums); System.out.println("排序前的数组:" + Arrays.toString(nums)); } /* * 对数组进行冒泡排序 * * @param nums 需要排序的数组 * */ private static void sort(int[] nums) { // 数组长度 len int len = nums.length - 1; // 记录最后一个交换的位置 int pos = 0; // 临时变量 temp int temp = 0; // 外层循环控制排序趟数,len个进行len - 1趟 for (int i = 0; i < nums.length - 1; i++) { System.out.println("第" + (i + 1) + "趟:"); // 标记位 boolean flag = true; // 内层循环控制比较的次数,第i趟比较i-1次 for (int j = 0; j < len; j++) { // 比较相邻的两个元素,若前面的数字大于后面的,交换位置 if (nums[j] > nums[j + 1]) { temp = nums[j + 1]; nums[j + 1] = nums[j]; nums[j] = temp; // 如果能走到这里说明有有元素交换,还不是有序的,标记为false flag = false; // 最后一次交换元素的位置 pos = j; } System.out.println(" 第" + (j + 1) + "次:" + Arrays.toString(nums)); } // 如果没有元素交换,直接跳出循环 if (flag) { break; } // 把最后一次交换元素的位置赋值给len,即下一次比较到记录位置 len = pos; } } }
输出的结果:
对于优化这块,我觉得并不具备普遍性,如果是在最坏的时间复杂度的情况下,优化与不优化输出的结果都是一样的,所以我们只需要了解冒泡的思想即可。另外加标志位这个思想在实际的开发中也很常用,需要我们多多思考。
水平有限,写的不好的地方,希望大家指出。如果你感觉这篇文章对你有帮助,点赞支持一下