在认识冒泡排序之前,先来了解一下如何衡量一个排序算法的优劣:
- 排序算法的执行效率:一般用时间复杂度来衡量
- 排序算法的内存消耗:一般用空间复杂度来衡量
这里还有一个概念就是:
原地排序:就是指空间复杂度为O(1)的排序算法 - 排序算法的稳定性:
稳定性的排序即:若待排序的集合中存在值相等的元素,经过排序之后,相等元素之间的原有的顺序不会发生改变
下来我们来说说冒泡排序:
1.冒泡排序的思路:将一个无序的数组,通过比较交换,使得每一趟比较下来,一定有一个当前的最大元素或最小元素(由升序排序还是降序排序决定)沉到数组的最后,从而实现有序
2.思路的细化分析:
- 由思路我们可以知道,若一个无序数组有n个元素,那我们需要排序的元素个数其实是n-1个,因为每次的比较都会将最大值元素放到最后,所以到最后一个元素的时候,实际上不需要再进行比较了,它此时一定是最大的。
- 再来看每个元素需要比较的次数,每个元素不需要与自身比较,拿第一个元素来说,它的比较次数是n-1次;当第一趟比较结束后,第二趟比较的时候最后一个数就不用再比较了,所以越往后,每趟比较的次数就会越小(每次减1)。
3.代码实现:
public static void bubbleSort(int[] a){
if(a==null||a.length<=1){
return;
}
for(int i=0;i<a.length-1;i++){
//每趟下来保证最大的元素在最后
for(int j=0;j<a.length-1-i;j++){
if(a[j]>a[j+1]){
int temp = a[j];
a[j] = a[j+1];
a[j+1] = temp;
flag = true;
}
}
}
}
4.代码分析:
- 可以看出,冒泡排序的时间复杂度为O(n^2),空间复杂度为O(1),只需要开辟一点临时空间,是一个稳定的原地排序算法。
- 但其实上述代码有点问题,假设我们现在给定的数组是{1,3,2,4,5},当第二个元素交换之后,数组已经有序,但还是会继续进行后面的比较,比较浪费时间
5.冒泡排序的优化: - 我们可以设置一个标志位flag,只有当数组元素进行交换时,说明此时数组是无序的;若不进行交换,说明此时已经有序;在每趟比较之后进行判断,若已经有序则跳出,排序结束,这样大大提高了执行效率。
- 代码实现:
public static void bbsort(int[] a){
//设置标志位
boolean flag = false;
if(a==null||a.length<=1){
return;
}
for(int i=0;i<a.length-1;i++){
for(int j=0;j<a.length-1-i;j++){
if(a[j]>a[j+1]){
int temp = a[j];
a[j] = a[j+1];
a[j+1] = temp;
flag = true;
}
}
//没有进行交换,此时数组已经有序
if(!flag){
System.out.println("已经有序");
break;
}
}
}
我随机生成了10w条数据,然后分别进行冒泡排序,结果如下:
6.冒泡排序总结:
- 时间复杂度:最好情况下,即数组已经有序的情况下,只需要进行一次冒泡就可以了,所以是O(n);一般情况下,时间复杂度为O(n^2)。
- 空间复杂度:冒泡排序只需要开辟临时空间来交换数组元素,所以空间复杂度是O(1),是原地排序算法。
- 稳定性:数组元素相等的情况,并不会进行交换,所以相等元素的原有顺序不会发生改变,所以是一种稳定性算法。