排序就是将一组对象按照某种逻辑顺序重新排列的过程。
基本思想:通过对带排序系列从前向后(从下标较小的元素开始)依次比较相邻元素的值,若发现逆序则交换,使值较大的元素,逐渐从前移向后部,就像水底下的气泡一样逐渐向上冒。
例:将4,5,6,3,2,1六个数从小到大升序排序。
第一趟排序过程:
4和5比较 5大,所以不交换,数组还是 4,5,6,3,2,1
5和6比较 6大,所以不交换,数组还是 4,5,6,3,2,1
6和3比较 6大,6,3位置进行交换,数组是4,5,3,6,2,1
6和2比较 6大,6,2位置进行交换,数组是4,5,3,2,6,1
6和1比较 6大,6,1位置进行交换,数组是4,5,3,2,1,6
第一次排序结束
从上面也可以看 冒泡排序就是位置i和i+1的元素去比较 ,如果i的元素大那么他们就进行交换(不符合升序,前面的比后面的还大),然后一直比较length-1次
//代码实现
Comparable[] var = {4,5,6,1,2,3};
for(int j = 0;j < var.length-1;j++)
if(compare(var[j],var[j+1]))
exchange(var, j, j+1);
这里用Comparable是为了通用,也可以将其改为其它基本类型,cpmpare()是比较方法,exchange()是交换方法。
/**
* 比较
* @param val1
* @param val2
* @return
*/
public static boolean compare(Comparable val1,Comparable val2) {
return val1.compareTo(val2) > 0;
}
/**
* 交换
* @param var
* @param i
* @param j
*/
public static void exchange(Comparable[] var,int i ,int j) {
Comparable temp = var[i];
var[i] = var[j];
var[j] = temp;
}
如果是降序排序的话我们只需要将比较中的大于号改成小于号即可。
上面我们所做的是第一趟排序只是将数组中最后一个位置的元素排好序了,下面我们将其它位置也排好序,因为每一趟可以确定一个元素的位置,所以我们需要length-1躺(第n-1躺确定了两个元素的位置)。
for(int i = 0;i < var.length -1 ;i++)
for(int j = 0;j < var.length-1;j++)
if(compare(var[j],var[j+1]))
exchange(var, j, j+1);
问题:
当第二趟排序的时候,数组是4,5,3,2,1,6, 6已经有序了所以第二趟的循环中就不用比较他了。
第一趟排序 4,5,3,2,1,6
第二趟排序 4,3,2,1,5,6
第三趟排序 3,2,1,4,5,6
第四趟排序 2,1,3,4,5,6
第五趟排序 1,2,3,4,5,6
所以每次内循环都应该是var.length-1-i。
for(int i = 0;i < var.length -1 ;i++)
for(int j = 0;j < var.length-1-i;j++)
if(compare(var[j],var[j+1]))
exchange(var, j, j+1);
当然你以为这样就比较完美了?
手写出下面 4,5,6,1,2,3数组每趟排序过程
第一趟排序 4,5,1,2,3,6
第二趟排序 4,1,2,3,5,6
第三趟排序 1,2,3,4,5,6
第四趟排序 1,2,3,4,5,6
第五趟排序 1,2,3,4,5,6
这时候你已经发现第四次排序的时候,没有元素需要交换位置,所以排序进行完第四次排序之后应该结束整个循环
//一点小优化
for(int i = 0;i < var.length -1 ;i++) {
boolean flag = false;//标记是否进行交换
for(int j = 0;j < var.length-1-i;j++)
if(compare(var[j],var[j+1])) {
exchange(var, j, j+1);
flag = true;
}
if(!flag) break;
}
行了前面的过程你已经学完了,我们提出几个问题(我copy的)
第一,冒泡排序是原地排序算法吗?冒泡的过程只涉及相邻数据的交换操作,只需要常量级的临时空间,所以它的空间复杂度为 O(1),是一个原地排序算法。
第二,冒泡排序是稳定的排序算法吗?在冒泡排序中,只有交换才可以改变两个元素的前后顺序。为了保证冒泡排序算法的稳定性,当有相邻的两个元素大小相等的时候,我们不做交换,相同大小的数据在排序前后不会改变顺序,所以冒泡排序是稳定的排序算法。
第三,冒泡排序的时间复杂度是多少?最好情况下,要排序的数据已经是有序的了,我们只需要进行一次冒泡操作,就可以结束了,所以最好情况时间复杂度是 O(n)。而最坏的情况是,要排序的数据刚好是倒序排列的,我们需要进行 n 次冒泡操作,所以最坏情况时间复杂度为 O(n2)。
平均时间复杂度 :先去求下最坏时间下的交换操作就是 n的阶乘 1*2…*n。所以交换操作就是n(n-1)/2,最好情况下就是不需要交换,也就是0,取中间值就是n(n-1)/ 4,比较操作肯定要比交换操作多,而复杂度的上限是 O(n2),所以平均情况下的时间复杂度就是 O(n2)。
总结
冒泡排序是平均时间复杂度为O(n2)稳定原地排序算法。