冒泡排序
简介
冒泡排序(Bubble Sort)
它的工作方式就像是 可乐中的气泡,越轻的气泡就会慢慢的浮到上面,在排序中,越小的元素经过交换也会慢慢的浮现在数列的顶端。
它是最基础的排序算法 优点:
- 便于学习,是最容易了解和实现的排序算法之一
缺点
- 它对于大量元素的排序 是非常没有效率的
实例
让我们来看看具体的案例:
此时此刻存在一个无序的数组,我们希望它能从小到大的排序。
根据冒泡排序的算法思想:一次比较两个相邻的元素,如果顺序错误就将他们交换位置
那么对于上面的无序数组,我们应该先去比较 29 和 10 ,此时我们发现 29 > 10 ,那么我们就需要去将它们交换位置。
将 29 和 10 交换位置之后,继续将 29 和 14 比较,可以发现 29 > 14 , 那么继续交换位置。
将 14 和 29 交换位置之后,继续将 29 和 37 比较,此时 29 < 37 , 这样就不需要交换位置。
然后继续将 37 和 14 比较,存在 37 > 14 , 那么需要交换元素之间的位置。
这样第一轮的排序就完成啦,可乐中最小的气泡就冒出头了。
我们可以将左侧看作无序的,而右侧看作有序的,目前有序的地方只有一个 37 。
OK,让我们来进行第二轮的排序。
将 10 和 14 比较, 因为 14 > 10 ,所以元素位置不会发生改变。
继续将 14 和 29 进行比较,由于 29 > 14 , 所以元素位置不发生变化。
继续进行比较, 这次 14 < 29 需要将元素的位置发生变化。
这个时候,不需要再将 29 和 37 进行比较了,那么有序组有有了两个成员了。
后面同理之下, 第三轮:
第四轮:
第五轮:
这样数组的所有的元素都排列完成,成功从无序数组排列成为一个从小到大的有序数组。
代码
冒泡排序的Java代码:
public static void bubble_sort(int[] arr) {
int temp;
int len = arr.length;
for (int i = 0; i < len - 1; i++) {
for (int j = 0; j < len - 1 - i; j++) {
if (arr[j] > arr[j + 1]) {
temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
}
}
}
}
可以看到代码其实是很简单的,通过一个外循环和一个内循环来进行元素比较, 外循环 = 轮数; 内循环 = 每一轮中元素的一次次比较。
每一次内循环只要比较无序组中的元素,所以条件中要减去有序组的长度也就是外循环的 i 的大小( j < len - 1 - i )。
代码的优化
对于冒泡排序的优化主要体现在减少比较次数。
如果存在一个 相对有序的数组,比如{ 2,1,3,4 },只需要第一轮就可得到一个有序的数组,但是冒泡排序还是会继续无意义的两两比较,这样就浪费了大量的时间。
那么问题来了,我们该怎么优化它呢?
如果在内循环中,元素没有发生一次交换,是不是说明所有元素都是按照顺序排列的。
所以我们可以设置一个标志 flag ,默认为 false,如果内循环中,元素发生了交换,那么可以将 flag 置为 true,在下轮外循环的时候,先检查 flag ,如果 flag 为 false,那么排序就结束了。
所以代码如下:
public static void bubble_sort(int[] arr) {
boolean flag = true;
int temp;
int len = arr.length;
for (int i = 0; i < len - 1 && flag; i++) {
flag = false;
for (int j = 0; j < len - 1 - i; j++) {
if (arr[j] > arr[j + 1]) {
flag = true;
temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
}
}
}
}
将优化前 和 优化后的代码 进行比较:
public static void main(String []args) {
int[] arrs = new int[10000];
for(int i = 0; i < 10000; i++) {
arrs[i] = (int) (Math.random() * (10000 + 1));
}
long time = System.currentTimeMillis();
bubble_sort1(arrs);
long time1 = System.currentTimeMillis();
System.out.println("bubble_sort1 time : " +(time1 - time));
bubble_sort2(arrs);
System.out.println("bubble_sort2 time : " +(System.currentTimeMillis() - time1));
}
从结果看来还是有些效果的:
时间复杂度
在设置标签后,
- 最好的情况:正序的数组,时间复杂度就是O(n)
- 最坏的情况:逆序的数组,时间复杂度是O(n^2)
- 一般情况:杂乱无序的数组,平均时间复杂度就是O(n^2)
总结
冒泡排序是最简单的入门算法之一,算法是程序员需要掌握的基础,对我们的发展会有很大的帮助。