Java实践冒泡排序的优化
引言
排序算法的优化问题一直以来都是算法领域的核心问题。优化一种已存在的算法往往需要借助灵活的思维,长久的探索甚至是天马行空的想象力。本文对冒泡排序的优化过程进行了简单实践。
朴素冒泡排序
public static void bubbleSort(int[] array) {
for(int i = 0;i < array.length - 1;i ++)
for(int j = 0,temp = 0;j < array.length - 1;j++) {
if(array[j] > array[j + 1]) {
temp = array[j];
array[j] = array[j + 1];
array[j + 1] = temp;
}
}
}
循环体优化:
对于冒泡排序,一个最简单的优化思路就是,当一个数组已经排序完成的时候,跳出冒泡循环。我们要做的只是在循环之中添加一个判断条件,如果一轮循环之中都没有发生位置交换,则可以跳出循环。
public static void opt001(int[] array) {
boolean isSorted = true;
for(int i = 0;i < array.length - 1;i ++) {
isSorted = true;
for(int j = 0,temp = 0;j < array.length - 1;j++) {
if(array[j] > array[j + 1]) {
temp = array[j];
array[j] = array[j + 1];
array[j + 1] = temp;
isSorted = false;
}
}
if(isSorted) break;
}
}
循环范围优化
我们通过观察发现,冒泡排序的过程中,数组中会存在一个逐渐变大的 “有序区域” 。换言之,数组靠右侧的元素会比左侧的元素更早地达到有序的状态。这种情况下如果再对右侧元素进行冒泡比较就显得多余。一个合理的优化做法就是判定出一个 “有序边界” ,每一轮循环在到达边界时停止。
public static void opt002(int[] array) {
int border = array.length - 1;
int lastIndex = border;
for(int i = 0;i < array.length - 1;i ++) {
for(int j = 0,temp = 0;j < border;j++) {
if(array[j] > array[j + 1]) {
temp = array[j];
array[j] = array[j + 1];
array[j + 1] = temp;
lastIndex = j;
}
}
border = lastIndex;
}
}
下面的版本结合了以上两种优化:
public static void opt003(int[] array) {
int border = array.length - 1;
int lastIndex = 0;
for(int i = 0;i < array.length - 1;i ++) {
lastIndex = 0;
for(int j = 0,temp = 0;j < border;j++) {
if(array[j] > array[j + 1]) {
temp = array[j];
array[j] = array[j + 1];
array[j + 1] = temp;
lastIndex = j;
}
}
if(lastIndex == 0) break;
border = lastIndex;
}
}
天马行空的优化:双向冒泡(鸡尾酒排序)
冒泡排序中会存在乌龟项,也就是一个本该出现在最左边的数字出现在最右边,这种数字让冒泡排序的效率大大降低了。所以,双向冒泡排序解决了这个问题,因为它的比较过程是双向的,就像一个钟摆。
public static void cockTail(int[] array) {
boolean isSorted = true;
for(int i = 0;i < array.length - 1;i ++) {
isSorted = true;
for(int j = 0,temp = 0;j < array.length - 1;j++) {
if(array[j] > array[j + 1]) {
temp = array[j];
array[j] = array[j + 1];
array[j + 1] = temp;
isSorted = false;
}
}
if(isSorted) break;
for(int j = array.length - 2,temp = 0;j > 0;j--) {
if(array[j] < array[j - 1]) {
temp = array[j - 1];
array[j - 1] = array[j];
array[j] = temp;
isSorted = false;
}
}
if(isSorted) break;
}
}
双向排序plus
这个版本对双向排序的循环体进行了优化(参考上文),可以说是朴素的冒泡排序之中的效率王者,也是简单冒泡排序的一个较完善版本,对不同类型的数组的适应力强。
public static void cockTailPlus (int[] array) {
int border1 = array.length - 1;
int border2 = 0;
int index1 = 0;
int index2 = array.length - 1;
for(int i = 0;i < array.length - 1;i ++) {
index1 = 0;
for(int j = border2,temp = 0;j < border1;j++) {
if(array[j] > array[j + 1]) {
temp = array[j];
array[j] = array[j + 1];
array[j + 1] = temp;
index1 = j;
}
}
if(index1 == 0) break;
border1 = index1;
index2 = array.length - 1;
for(int j = border1,temp = 0;j > border2;j--) {
if(array[j] < array[j - 1]) {
temp = array[j - 1];
array[j - 1] = array[j];
array[j] = temp;
index2 = j;
}
}
if(index2 == array.length - 1) break;
border2 = index2;
}
}