冒泡排序的思想,我们要把相邻的元素两两比较,根据大小来交换元素的位置
代码如下:
public int[] bubbleSort(int array[]) {
int temp = 0;
for(int i = 0;i<array.length;i++) {
for(int j = 1;j < array.length;j++) {
if(array[j-1] > array[j]) {
temp = array[j];
array[j] = array[j-1];
array[j-1] = temp;
}
}
}
return array;
}
时间复杂度为O(n^2),空间复杂度为O(1)
在某次内循环时候已经有序了,外循环就不需要再进行下去,所以可以通过设置标记来结束多余的循环。
public int[] bubbleSort(int[] array) {
int temp = 0;
for(int i = 0;i < array.length;i++) {
boolean isSorted = true;//每一轮遍历初始为true
for(int j = 1;j < array.length;j++) {
if(array[j-1] > array[j]) {
temp = array[j];
array[j] = array[j-1];
array[j-1] = temp;
isSorted = false;//有交换说明还未有序
}
}
if(isSorted) {
break;//有序了就不用再继续循环
}
}
return array;
}
为了说明这种优化,下面举一个例子:
array: 5,6,4,2,8,9,10
第一次遍历:5和6不交换 -> 5,6,4,2,8,9,10
··················6和4交换 -> 5,4,6,2,8,9,10
··················6和2交换 -> 5,4,2,6,8,9,10
··················6和8不交换 -> 5,4,2,6,8,9,10
··················8和9不交换 -> 5,4,2,6,8,9,10
··················9和10不交换 -> 5,4,2,6,8,9,10
*这个数列的特点是前半部分无序,后半部分有序
所以有序区不需要进行交换,如果能对有序区进行界定,就可以免去没有意义的比较
那么如何避免这种情况呢?可以在每一轮排序最后,记录最后一次交换的下标,那个位置就是无序数组的边界,再往后就是有序的。
优化代码如下:
public int[] bubbleSort(int[] array) {
int temp = 0;
//记录最后一次交换的下标
int lastExchangeIndex = 0;
//记录无序区域的最右边界
int right = array.length-1;
for(int i = 0;i < array.length;i++) {
//有序标记,每一轮遍历初始为true
boolean isSorted = true;
for(int j = 1;j < right;j++) {
if(array[j-1] > array[j]) {
temp = array[j];
array[j] = array[j-1];
array[j-1] = temp;
isSorted = false;//有交换说明还未有序
lastExchangeIndex = j-1;//把无序边界作为最后一次交换下标
}
}
right = lastExchangeIndex;
if(isSorted) {
break;//有序了就不用再继续循环
}
}
return array;
}
鸡尾酒排序就是像钟摆一样,第一轮从左到右,第二轮从右到左…
public int[] sort(int[] array) {
int temp = 0;
for(int i = 0;i < array.length/2;i++) {
//有序标记,每一轮遍历初始为true
boolean isSorted = true;
//奇数轮,从左往右交换
for(int j = i;j < array.length-i-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;
}
isSorted = true;//在偶数轮前将有序标记重新置为true
//偶数轮,从右往左
for(int j = array.length-1-i;j>i;j--) {
if(array[j-1] > array[j]) {
temp = array[j];
array[j] = array[j-1];
array[j-1] = temp;
isSorted = false;
}
}
if(isSorted) {
break;//有序了就不用再继续循环
}
}
return array;
}
这是鸡尾酒排序的原始实现,一个大循环套两个小循环,第一个循环从左到右,第二个从右到左。
是否可以进一步优化??? 参考优化2的方法:对每一轮的有序区进行界定,代码如下:
public int[] sort(int[] array) {
int temp = 0;
int lastRightExchangeIndex = 0;//右侧最后交换下标
int lastLeftExchangeIndex = 0;//左侧最后交换下标
int right = array.length-1;//无序序列右边界
int left = 0;//无序序列左边界
for(int i = 0;i < array.length/2;i++) {
//有序标记,每一轮遍历初始为true
boolean isSorted = true;
//奇数轮,从左往右交换
for(int j = left;j < right;j++) {
if(array[j] > array[j+1]) {
temp = array[j];
array[j] = array[j+1];
array[j+1] = temp;
isSorted = false;//有交换说明还未有序
lastRightExchangeIndex = j;
}
}
right = lastRightExchangeIndex;
if(isSorted) {
break;
}
isSorted = true;//在偶数轮前将有序标记重新置为true
//偶数轮,从右往左
for(int j = right;j>left;j--) {
if(array[j-1] > array[j]) {
temp = array[j];
array[j] = array[j-1];
array[j-1] = temp;
isSorted = false;
lastLeftExchangeIndex = j;
}
}
left = lastLeftExchangeIndex;
if(isSorted) {
break;//有序了就不用再继续循环
}
}
return array;
}