冒泡排序(Bubble Sort)是一种简单的排序算法。它重复地走访过要排序的数列,一次比较两个元素,如果两个元素的顺序错误就把它们交换过来。走访数列的工作是重复地进行直到没有顺序交换产生,也就是说该数列已经排序完成。这个算法的名字由来是因为越小的元素会经由交换慢慢“浮”到数列的顶端。
冒泡排序算法的核心思想如下:
①比较相邻的元素。如果第一个比第二个大,就交换他们两个的顺序。
②对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对。在这一点,最后的元素总会是最大的数。
③针对所有的元素重复以上的步骤,除了最后一个。
④持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较。
由于冒泡排序是一种常见的排序方式,针对于其性能的优化也是很有必要的,下面我用java语言来介绍一下我自己的优化方式。希望能有同行的朋友一起探讨探讨。
普通冒泡
/**
* 校验数组是否为空的方法
* @param arr
*/
public static void check(int[] arr) {
if(arr==null||arr.length<1){
System.out.println("数组为空");
return;
}
}
/**
* 普通冒泡升序排序
* @param arr
*/
public static void sort(int[] arr) {
check(arr);
//外层循环次数
int len = arr.length-1;
//临时变量
int temp = 0;
for(int i = 0;i<len;i++){//外层循环
for(int j = 0;j<len-i;j++){//内层循环
if(arr[j]>arr[j+1]){//前一个数比后一个数大则交换
temp = arr[j];
arr[j] = arr[j+1];
arr[j+1] = temp;
}
}
}
}
外层优化
/**
* 冒泡排序外层优化
*
* 问题:
* 有的冒泡经过第一轮的交换已经是有序的了,如:2 1 3 4。此时就没必要再继续循环,
* 外层的循环次数怎么去控制一下?
*
*
* 思想:
* 用一个标识变量flag来判断一下,当前数组是否已经有序,
* 即内层如果发生了交换就继续循环,内层未发生交换表明数组已经有序,
* 如果有序就退出循环,即优化外层的循环次数,这样可以明显的提高冒泡排序的性能。
*
* @param arr
*/
public static void sort1(int[] arr) {
check(arr);
//外层循环次数
int len = arr.length-1;
//临时变量
int temp = 0;
//判断内层是否发生了交换的标志,false表示没有发生交换,true表示发生了交换
boolean flag = false;
for(int i = 0;i<len;i++){//外层循环
for(int j = 0;j<len-i;j++){//内层循环
if(arr[j]>arr[j+1]){//前一个数比后一个数大则交换
temp = arr[j];
arr[j] = arr[j+1];
arr[j+1] = temp;
flag = true;//发生了交换
}
}
if(flag == false){//内层循环一次之后判断是否发生了交换,如果没有则直接结束整个循环
break;
}
}
}
内层优化
/**
* 冒泡排序内层优化
*
* 问题:
* 内存循环虽然发生了交换,但是假如一次循环之后第3个位置之后的元素已经有了顺序,
* 下次循环时还会再次比较第3个位置之后的元素,此时就没必要再继续比较位置3之后的元素
* 怎么去控制一下?
*
*
* 思想:
* 用一个标识变量loc来记录每次内层循环中最后一次交换的位置,即loc位置后面的元素已经有序
* 下次循环只需要循环到loc位置即可,依次类推,直到所有元素都有序为止。
*
*
* @param arr
*/
public static void sort2(int[] arr) {
check(arr);
//外层循环次数
int len = arr.length-1;
//临时变量
int temp = 0;
//记录每次内层循环最后交换元素的位置
int loc = 0;
//控制内层循环次数
int count = 0;
for(int i = 0;i<len;i++){//外层循环
count = len-i;//初始内存循环次数
for(int j = 0;j<count;j++){//内层循环
if(arr[j]>arr[j+1]){//前一个数比后一个数大则交换
temp = arr[j];
arr[j] = arr[j+1];
arr[j+1] = temp;
loc = j;//记录每次内层循环最后交换元素的位置
}
}
count = loc;//下次循环次数loc次
}
}
内外层结合
/**
* 冒泡排序内外层优化同时用
*
* @param arr
*/
public static void sort3(int[] arr) {
check(arr);
//外层循环次数
int len = arr.length-1;
//临时变量
int temp = 0;
//记录每次内层循环最后交换元素的位置
int loc = 0;
//控制内层循环次数
int count = 0;
//判断内层是否发生了交换的标志,false表示没有发生交换,true表示发生了交换
boolean flag = false;
for(int i = 0;i<len;i++){//外层循环
count = len-i;//初始内存循环次数
for(int j = 0;j<count;j++){//内层循环
if(arr[j]>arr[j+1]){//前一个数比后一个数大则交换
temp = arr[j];
arr[j] = arr[j+1];
arr[j+1] = temp;
loc = j;//记录每次内层循环最后交换元素的位置
flag = true;//内层发生了交换
}
}
if(flag == false){//没有发生交换则表明已经有序,退出循环
break;
}
count = loc;//下次循环次数loc次
}
}
几种优化性能测试
这里我采用随机数随机生成相同元素个数的数组来进行性能测试:
/**
* 随机生成一个整型数组
* @param begin 随机数开始位置
* @param end 随机数结束为止(不包含)
* @param len 整型数组长度
* @return
*/
public static int[] createArr(int begin,int end,int len) {
int[] arr = new int[len];
for (int i = 0; i < arr.length; i++) {
//生成一个随机数
ThreadLocalRandom localRandom = ThreadLocalRandom.current();
int nextInt = localRandom.nextInt(begin, end);
arr[i] = nextInt;
}
return arr;
}
public static void main(String[] args) {
int[] arr = createArr(0, 1000000, 100000);
System.out.println("=================普通冒泡排序========================");
long start = System.currentTimeMillis();
sort(arr);
long end = System.currentTimeMillis();
System.out.println("普通冒泡排序用时:"+(end-start));
System.out.println("=================外层优化冒泡排序========================");
long start1 = System.currentTimeMillis();
sort1(arr);
long end1 = System.currentTimeMillis();
System.out.println("外层优化冒泡排序用时:"+(end1-start1));
System.out.println("=================内层优化冒泡排序========================");
long start2 = System.currentTimeMillis();
sort2(arr);
long end2 = System.currentTimeMillis();
System.out.println("内层优化冒泡排序用时:"+(end2-start2));
System.out.println("=================内外层优化冒泡排序========================");
long start3 = System.currentTimeMillis();
sort3(arr);
long end3 = System.currentTimeMillis();
System.out.println("内外层优化冒泡排序用时:"+(end3-start3));
}
Eclipse中排序用时测试结果:
可以看出,排序的数列包含的元素一旦过多,外层优化的效果相对于内层是有明显的优势的,如果实际开发中需要用到冒泡排序,可以采用外层优化的方式来提高排序效率。