1、没有优化的冒泡排序
public static void main(String[] args) {
//冒泡排序,显示升序排列,从小到大
int[] arr = {9,7,5,3,1};
/**
* 本次排序不考虑优化,情况如下:
* 排序思路:
* 第一趟第一次:拿9和7比较,得到的结果 7 9 5 3 1
* 第一趟第二次:拿9和5比较,得到的结果 7 5 9 3 1
* 第一趟第三次:拿9和3比较,得到的结果 7 5 3 9 1
* 第一趟第四次:拿9和1比较,得到的结果 7 5 3 1 9
* 经过第一趟的比较,把9这个最大值排到了最后面,一共有5个元素,比较了四次
*
* 第二趟第一次:拿7和5比较,得到的结果 5 7 3 1 9
* 第二趟第二次:拿7和3比较,得到的结果 5 3 7 1 9
* 第二趟第三次:拿7和1比较,得到的结果 5 3 1 7 9
* 第二趟第四次:拿7和9比较,得到的结果 5 3 1 7 9
* 经过第二趟的比较,把7排到了9前面,一共有5个元素,比较了四次
*
* 第三趟第一次:拿5和3比较,得到的结果 3 5 1 7 9
* 第三趟第二次:拿5和1比较,得到的结果 3 1 5 7 9
* 第三趟第三次:拿5和7比较,得到的结果 3 1 5 7 9
* 第三趟第四次:拿5和9比较,得到的结果 3 1 5 7 9
* 经过第三趟的比较,把5排到了7前面,一共有5个元素,比较了四次
*
* 第四趟第一次:拿3和1比较,得到的结果 1 3 5 7 9
* 第四趟第二次:拿3和5比较,得到的结果 1 3 5 7 9
* 第四趟第三次:拿3和7比较,得到的结果 1 3 5 7 9
* 第四趟第四次:拿3和9比较,得到的结果 1 3 5 7 9
* 经过第四趟的比较,把7这个排到了9前面,一共有5个元素,比较了四次
*
* 从上面可以看出,5个元素比较了4趟,每趟比较了4次,所以得到结论,要比较arr.length-1趟和arr.length-1次
* 因此要通过双层循环来处理
*/
for(int i = 0; i < arr.length-1 ; i++){//外层循环表示趟数
System.out.println("---第"+(i+1)+"趟---");
for(int j = 0; j < arr.length-1 ; j++){//内层循环表示每趟的次数
if(arr[j]>arr[j+1]){
int temp = arr[j];
arr[j] = arr[j+1];
arr[j+1] = temp;
}
System.out.println("第"+(j+1)+"次排序后结果"+Arrays.toString(arr));
}
System.out.println("第"+(i+1)+"趟排序后的结果:"+Arrays.toString(arr));
}
//排序完打印数组
System.out.println("最终排序结果:"+Arrays.toString(arr));
}
运行程序,控制台打印如下:
---第1趟---
第1次排序后结果[7, 9, 5, 3, 1]
第2次排序后结果[7, 5, 9, 3, 1]
第3次排序后结果[7, 5, 3, 9, 1]
第4次排序后结果[7, 5, 3, 1, 9]
第1趟排序后的结果:[7, 5, 3, 1, 9]
---第2趟---
第1次排序后结果[5, 7, 3, 1, 9]
第2次排序后结果[5, 3, 7, 1, 9]
第3次排序后结果[5, 3, 1, 7, 9]
第4次排序后结果[5, 3, 1, 7, 9]
第2趟排序后的结果:[5, 3, 1, 7, 9]
---第3趟---
第1次排序后结果[3, 5, 1, 7, 9]
第2次排序后结果[3, 1, 5, 7, 9]
第3次排序后结果[3, 1, 5, 7, 9]
第4次排序后结果[3, 1, 5, 7, 9]
第3趟排序后的结果:[3, 1, 5, 7, 9]
---第4趟---
第1次排序后结果[1, 3, 5, 7, 9]
第2次排序后结果[1, 3, 5, 7, 9]
第3次排序后结果[1, 3, 5, 7, 9]
第4次排序后结果[1, 3, 5, 7, 9]
第4趟排序后的结果:[1, 3, 5, 7, 9]
最终排序结果:[1, 3, 5, 7, 9]
2、优化后的冒泡排序
从上面我们可以看到,每一趟都进行了4次比较,但是我们能看到有些比较是重复的,比如第一趟的时候已经比较过7和9了,但是第二趟的时候又比较了7和9,这就导致重复比较,效率低。我们可以优化一下,减少比较次数,提高效率。
从上面的打印结果我们可以看出,其实只要比较3次就能得到结果。第一趟的时候需要比较4次,第二趟的时候需要比较3次,,第三趟的时候比较2次,第四趟的时候比较1次就够了。也就是内层循环次数依次减少了,减少的值就是趟数的值,所以如下所示:
public static void main(String[] args) {
//冒泡排序,显示升序排列,从小到大
int[] arr = {9,7,5,3,1};
/**
* 本次排序不考虑优化,情况如下:
* 排序思路:
* 第一趟第一次:拿9和7比较,得到的结果 7 9 5 3 1
* 第一趟第二次:拿9和5比较,得到的结果 7 5 9 3 1
* 第一趟第三次:拿9和3比较,得到的结果 7 5 3 9 1
* 第一趟第四次:拿9和1比较,得到的结果 7 5 3 1 9
* 经过第一趟的比较,把9这个最大值排到了最后面,一共有5个元素,比较了四次
*
* 第二趟第一次:拿7和5比较,得到的结果 5 7 3 1 9
* 第二趟第二次:拿7和3比较,得到的结果 5 3 7 1 9
* 第二趟第三次:拿7和1比较,得到的结果 5 3 1 7 9
* 经过第二趟的比较,把7排到了9前面,一共有5个元素,比较了三次
*
* 第三趟第一次:拿5和3比较,得到的结果 3 5 1 7 9
* 第三趟第二次:拿5和1比较,得到的结果 3 1 5 7 9
* 经过第三趟的比较,把5排到了7前面,一共有5个元素,比较了二次
*
* 第四趟第一次:拿3和1比较,得到的结果 1 3 5 7 9
* 经过第四趟的比较,把7这个排到了9前面,一共有5个元素,比较了一次
*
* 从上面可以看出,5个元素比较了4趟,每趟比较了4次,所以得到结论,要比较arr.length-1趟和arr.length-1次
* 因此要通过双层循环来处理
*/
for(int i = 0; i < arr.length-1 ; i++){//外层循环表示趟数
System.out.println("---第"+(i+1)+"趟---");
for(int j = 0; j < arr.length-1-i ; j++){//内层循环表示每趟的次数,这里循环的次数减去趟数j
if(arr[j]>arr[j+1]){
int temp = arr[j];
arr[j] = arr[j+1];
arr[j+1] = temp;
}
System.out.println("第"+(j+1)+"次排序后结果"+Arrays.toString(arr));
}
System.out.println("第"+(i+1)+"趟排序后的结果:"+Arrays.toString(arr));
}
//排序完打印数组
System.out.println("最终排序结果:"+Arrays.toString(arr));
}
3、存在顺序的数组进行冒泡排序
比如我们的数组int arr = {8,1,2,4,5},如果对这个数组进行升序排列的话,由于该数组的数据已经存在了一定的顺序,所以如果我们还按之前的方式进行比较,就会进行无效的操作,效率也不高。
比如,第一趟比较的时候,8跟后面的元素比较,,得到的结果{1,2,4,5,8},其实最终的结果已经产生了。如果按之前的方式,那么还会进行3趟比较。所以可以用如下的方式改写排序方法:
public static void main(String[] args) throws Exception {
//冒泡排序,显示升序排列,从小到大
int[] arr = {8,1,2,4,5};
for(int i = 0; i < arr.length-1 ; i++){//外层循环表示趟数
System.out.println("---第"+(i+1)+"趟---");
for(int j = 0; j < arr.length-1-i ; j++){//内层循环表示每趟的次数,这里循环的次数减去趟数j
if(arr[j]>arr[j+1]){
int temp = arr[j];
arr[j] = arr[j+1];
arr[j+1] = temp;
}
System.out.println("第"+(j+1)+"次排序后结果"+Arrays.toString(arr));
}
System.out.println("第"+(i+1)+"趟排序后的结果:"+Arrays.toString(arr));
}
//排序完打印数组
System.out.println("最终排序结果:"+Arrays.toString(arr));
System.out.println("--------------下面是最优的排序--------------");
int[] arr2 = {8,1,2,4,5};
for(int i = 0; i < arr2.length-1 ; i++){//外层循环表示趟数
System.out.println("---第"+(i+1)+"趟---");
boolean sort = true;//假设是有序的
for(int j = 0; j < arr2.length-1-i ; j++){//内层循环表示每趟的次数,这里循环的次数减去趟数j
if(arr2[j]>arr2[j+1]){
int temp = arr2[j];
arr2[j] = arr2[j+1];
arr2[j+1] = temp;
//如果进了本循环,说明进行了比较,把sort改成false
sort = false;
}
System.out.println("第"+(j+1)+"次排序后结果"+Arrays.toString(arr2));
}
System.out.println("第"+(i+1)+"趟排序后的结果:"+Arrays.toString(arr2));
//但是如果比较了一趟后,发现sort的值是true,说明此时数组已经是有序的,因此跳出外层循环
if(sort){
break;
}
}
//排序完打印数组
System.out.println("最终排序结果:"+Arrays.toString(arr2));
}
结果如下:
---第1趟---
第1次排序后结果[1, 8, 2, 4, 5]
第2次排序后结果[1, 2, 8, 4, 5]
第3次排序后结果[1, 2, 4, 8, 5]
第4次排序后结果[1, 2, 4, 5, 8]
第1趟排序后的结果:[1, 2, 4, 5, 8]
---第2趟---
第1次排序后结果[1, 2, 4, 5, 8]
第2次排序后结果[1, 2, 4, 5, 8]
第3次排序后结果[1, 2, 4, 5, 8]
第2趟排序后的结果:[1, 2, 4, 5, 8]
---第3趟---
第1次排序后结果[1, 2, 4, 5, 8]
第2次排序后结果[1, 2, 4, 5, 8]
第3趟排序后的结果:[1, 2, 4, 5, 8]
---第4趟---
第1次排序后结果[1, 2, 4, 5, 8]
第4趟排序后的结果:[1, 2, 4, 5, 8]
最终排序结果:[1, 2, 4, 5, 8]
--------------下面是最优的排序--------------
---第1趟---
第1次排序后结果[1, 8, 2, 4, 5]
第2次排序后结果[1, 2, 8, 4, 5]
第3次排序后结果[1, 2, 4, 8, 5]
第4次排序后结果[1, 2, 4, 5, 8]
第1趟排序后的结果:[1, 2, 4, 5, 8]
---第2趟---
第1次排序后结果[1, 2, 4, 5, 8]
第2次排序后结果[1, 2, 4, 5, 8]
第3次排序后结果[1, 2, 4, 5, 8]
第2趟排序后的结果:[1, 2, 4, 5, 8]
最终排序结果:[1, 2, 4, 5, 8]
可以从结构看出,之前的方法要比较4趟,但是现在只要比较2趟就可以了,这样对于有一定顺序的,可以提高效率。