冒泡排序有多种不同的写法,其中主要的区别就是性能的不同
这篇文章将逐步改进冒泡排序,使得冒泡排序不断进化
原始人
先看代码
public void getSortArray(int array[]) {
int temp = 0;
for (int i = 0; i < array.length - 1; i++) {
for (int j = 0; j < array.length - i - 1; j++) {
if (array[j] > array[j + 1]) {
temp = array[j];
array[j] = array[j + 1];
array[j + 1] = temp;
}
}
}
}
原始人的代码就是简单 ,简单看看就能看的差不多,这里面有一个很重要的地方:i 与 j 的取值问题
我当时看到代码时不仅要问,i 与 j 为什么要这样取值呢?
答曰:
-
对于 i 的 取值 :冒泡排序的目的就是 通过每次的交换,将最大的值交换到一串数字的最后,因为 i 是最外层循环的控制变量,因此 i 就代表着循环的次数,假设外层循环了3次 ,那么这串数字的最后3个数就已经有序了。所以,如果这串数字长度为 n ,那么显然外层只要循环 n - 1 次就使得数列有序了。因此外层循环次数为 array.length -1 次。
-
对于 j 的取值:n 次外层循环使得数列最后 n 个为有序而且有序区的每个数必然比前面的都大,因此在每次的内层循环,没有必要再让 j 从 0 --> array.length - 1,只要从 0 --> array.length - i - 1
原始人进化
先看代码
public void secondSortArray(int array[]) {
int temp = 0;
boolean sorted = false;
for (int i = 0; i < array.length - 1; i++) {
sorted = false;
for (int j = 0; j < array.length - i - 1; j++) {
if (array[j] > array[j + 1]) {
temp = array[j];
array[j] = array[j + 1];
array[j + 1] = temp;
sorted = true;
}
}
if(sorted == false) {
break;
}
}
}
最重要的就是添加了 sorted 这个布尔变量
为什么要添加这个变量呢?
看一个数列:1 2 3 4 5 8 7 显然这个序列只通过一次就可以有序,但是实际上要经过 21 次循环
- 求冒泡排序(原始人阶段) 的计算公式:n(n-1)/ 2 其中 n 为数列的长度
这显然太耗费时间了,加上一个布尔变量,如果一次内部循环没有经过变量交换,那么就说明已经排序完成了,因此就结束排序。
原始人再进化
看代码
public void thirdSortArray(int array[]) {
int temp = 0;
int count = 0;
int boundary = array.length - 1;
boolean sorted = false;
for (int i = 0; i < array.length - 1; i++) {
sorted = false;
for (int j = 0; j < boundary; j++) {
count++;
if (array[j] > array[j + 1]) {
temp = array[j];
array[j] = array[j + 1];
array[j + 1] = temp;
sorted = true;
boundary = j;
}
}
if (sorted == false) {
break;
}
}
}
例如 2 1 3 5 6 7 8 这个数列,如果让我们人来进行排序,那么你会怎么做?我们会找一个边界,这个边界的右侧都是比左侧大的数而且已经有序,此后就只看这个边界左侧的数字。
那么把这个事情交给程序呢?我们也需要让程序找到这个边界,这个边界找到了,那么此后程序再进行数字比较的时候就更加省时省力。
如何让程序找到这个边界?重中之重就是:找到最后一次进行两数字交换的位置,这个位置就是边界!
知道了这里,那么代码也就很好看懂了(代码引进了第一次进化)
为了说明三者之间效率的差距,在内层循环设置一个变量count 计算整个排序过程的执行次数
public void firstSortArray(int array[]) {
int temp = 0;
int count = 0;
for (int i = 0; i < array.length - 1; i++) {
for (int j = 0; j < array.length - i - 1; j++) {
count++;
if (array[j] > array[j + 1]) {
temp = array[j];
array[j] = array[j + 1];
array[j + 1] = temp;
}
}
}
System.out.println("执行次数:"+count);
}
另外两个的代码我就不贴了
对[ 2, 1, 3, 4, 5,6] 这个数组进行排序,得到结果分别为:
执行次数:15
最终结果:123456
执行次数:9
最终结果:123456
执行次数:5
最终结果:123456
可以看到,效率差距还是很明显的