冒泡排序算法的运作如下:
1.比较相邻的元素。如果第一个比第二个大,就交换他们两个。
2.对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对。这步做完后,最后的元素会是最大的数。
3.针对所有的元素重复以上的步骤,除了最后一个。
4.持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较。
具体如何进行移动呢?让我们来看一个例子:
有8个数组成上面一个无序数列:5,8,6,5,9,2,1,7,目标是从小到大排序。
按照冒泡排序的思想,过程如下:
首先让5和8比较,8比5大,故两者不进行交换。
接下来8和6比较,8比6大,两者进行交换。
继续8和3比较,交换8和3的位置。
继续8和9比较,9比8大,两者不进行交换。
然后比较9和2,9比2大,两者进行交换。
接下来比较9和1,9比1大,两者进行交换。
在最后比较9和7,9大于7,两者进行交换。
经过上面的冒泡排序的第一轮运作。数列最右侧元素可以认为是一个有序区域,有序区域目前只有一个元素。
接下来进行如上的7轮排序得到最终的有序数列:
第六轮、第七轮、第八轮排序:
第六轮排序:
第七轮排序:
第八轮排序:
问题分析:在6-8轮中我们待排序的数列早就已经是有序的数列的,可是冒泡排序依旧进行比较。
算法改进1:在进行每一轮的排序工作时判断数列是否有序,如已经是有序的数列则将排序工作提早结束。
算法改进2:算法改进的关键点在于对数列有序区的界定。
按照冒泡排序的逻辑,有序区的长度和排序的轮数是相等的。比如第一轮排序过后的有序长度为1,第二轮排序后有序长度是2……但是实际情况是这样子的吗?实际上,数列真正的有序区可能会大于这个长度。那么后面的许多元素的比较是没有意义的。解决思路:在每一轮排序的最后,记录下最后一个元素交换的位置,那个位置也就是无序数列的边界,再往后就是有序区了。
基本的冒泡排序代码:
//冒泡排序函数 版本1
private static void SortBubbling(int[] arr_Native) {
int temp;
for (int i = 0; i < arr_Native.length-1; i++) { //外循环只需要比较arr.length-1次就可以
for (int j = 0; j < arr_Native.length-i-1; j++) { //内循环需要比较arr_Native.length-i-1
if (arr_Native[j]>arr_Native[j+1]) {
temp=arr_Native[j];
arr_Native[j]=arr_Native[j+1];
arr_Native[j+1]=temp;
}
}
}
}
算法改进1后的代码:
//冒泡排序函数 版本2
//利用boolean变量isSored作为标记。如果在本轮排序中,元素有交换,说明数列无序;如果没有元素交换,说明数列已然有序,直接跳出大循环
private static void SortBubbling2(int[] arr_Native) {
int temp;
for (int i = 0; i < arr_Native.length-1; i++) { //外循环只需要比较arr.length-1次就可以
boolean isSored = true;
for (int j = 0; j < arr_Native.length-i-1; j++) { //内循环需要比较arr_Native.length-i-1
if (arr_Native[j]>arr_Native[j+1]) {
temp=arr_Native[j];
arr_Native[j]=arr_Native[j+1];
arr_Native[j+1]=temp;
isSored = false;
}
}
if (isSored) {
break;
}
}
}
算法改进2后的代码:
private static void SortBubbling3(int[] arr_Native) {
int temp;
//记录最后一次交换的位置
int lastExchangeIndex = 0;
//无序数列的边界,每次比较只需要比到这里为止
int sortBorder = arr_Native.length-1;
for (int i = 0; i < arr_Native.length-1; i++) { //外循环只需要比较arr.length-1次就可以
boolean isSored = true;
for (int j = 0; j < sortBorder; j++) { //内循环需要比较arr_Native.length-i-1
if (arr_Native[j]>arr_Native[j+1]) {
temp=arr_Native[j];
arr_Native[j]=arr_Native[j+1];
arr_Native[j+1]=temp;
isSored = false;
lastExchangeIndex = j;
}
}
sortBorder=lastExchangeIndex;
if (isSored) {
break;
}
}
}