冒泡排序原理
冒泡排序简要来说就是循环让相邻两个元素比较,如果左边的元素比右边的元素大,则左右交换位置,直到数组中所有元素排列完毕为止。
用Java代码表示:
int[] array = new int[] {22,13,45,34,89,14,64};
for(int end = array.length; end > 0; end--) {
for(int begin = 1; begin < end; begin++) {
//如果前面的比后面的大,则交换
if(array[begin] < array[begin - 1]) {
int tmp = array[begin];
array[begin] = array[begin - 1];
array[begin - 1] = tmp;
}
}
}
for(int i = 0;i < array.length;i++) {
System.out.print(array[i] + "_");
}
}
输出结果为
13_14_22_34_45_64_89_
end=array.length时,对应着找到倒数第一个元素并将其放置在最后一个位置,end=arry.length - 1时,对应着找到倒数第二个元素并将其放置在倒数第二个位置…
当end = 1时排序完成。
冒泡排序优化
上面的代码解决了排序的问题,但是性能不够高,可以继续优化。我们可以增加一个是否已经完成排序的标志,在每次扫描相邻元素的时候判断,如果某一次循环中,没有发生相邻元素更换位置,也就是已经排序完成的时候,更改这个排序的标志,从而结束后面多余的扫描判断。
代码:
int[] array = new int[] {22,13,45,34,89,14,64};
for(int end = array.length;end > 0; end--) {
boolean isSorted = true;
for(int begin = 1; begin < end; begin++) {
//如果前面的比后面的大,则交换
if(array[begin] < array[begin - 1]) {
int tmp = array[begin];
array[begin] = array[begin - 1];
array[begin - 1] = tmp;
isSorted = false;
}
}
if(isSorted) {
break;
}
}
for(int i = 0;i < array.length;i++) {
System.out.print(array[i] + "_");
运行结果:
13_14_22_34_45_64_89_
没有问题。
还可以继续优化:
如果序列的尾部提前有序且都比前面的数据大,就可以记录最后一次比较的尾部位置,减少比较次数。
并且再每一轮循环之后,尾部有序的元素又会增加,需要更新这部分元素。也就是记录一下每一轮最后一次交换的位置即可,以后最后一次交换也一定在这个位置之前。
Java代码:
int[] array = new int[] {22,13,45,34,89,14,64};
for(int end = array.length;end > 0; end--) {
int sortedIndex = 1;
for(int begin = 1; begin < end; begin++) {
//如果前面的比后面的大,则交换
if(array[begin] < array[begin - 1]) {
int tmp = array[begin];
array[begin] = array[begin - 1];
array[begin - 1] = tmp;
sortedIndex = begin;
}
}
end = sortedIndex;
}
for(int i = 0;i < array.length;i++) {
System.out.print(array[i] + "_");
}
运行结果仍然正确。
时间复杂度
最好情况,只有一次循环O(n)
最坏何平均情况,O(n^2);
**
补充:
**
稳定性
排序算法的稳定性是指两个相同的数据,在排序之后,相对位置不发生改变
假如有
3,5,1,An,2,A(n+1)
排序后是
1,2,An,A(n+1)3,5
这样的算法就是稳定的。
冒泡排序算法是稳定的。因为在判断是否交换元素时用的是<符号,也就是说如果两个元素大小相等,那么就不会交换位置,元素之间的相对位置也就没有改变。
原地算法
原地算法就是不依赖额外的资源或者依赖少数的额外资源,仅依靠输出来覆盖输入。也就是直接对元素所在的位置进行修改,不会再申请新的空间完成需求。
空间复杂度为 𝑂(1) 的都可以认为是原地算法。
因此冒泡排序是原地算法。