冒泡排序是一种很实用的排序方法,其主要思想是:在要排序的一组数中,对当前还未排好序的数,对从前往后对相邻的两个数依次进行比较和调整,让较大的数往后移(往下移),较小的数往前走(往上冒),即相当于每次找到一个最大值,并且相对于在后面,因此假如一组数有 n个数,只需要比较 n-1 次。例如一组数为 2,3,56,24,36,25,78,96,54。
第一次比较:2,3,24,36,25,56,78,54,96
第二次比较:2,3,24,25,36,56,54,78,96
第三次比较:2,3,24,25,36,54,56,78,96 //数据比较特殊,第三次就完成了
第四次比较:2,3,24,25,36,54,56,78,96
第五次比较:2,3,24,25,36,54,56,78,96
第六次比较:2,3,24,25,36,54,56,78,96
第七次比较:2,3,24,25,36,54,56,78,96
第八次比较:2,3,24,25,36,54,56,78,96
实现代码:
/** * O(n^2) 稳定 * @param array */ public static void sort(int[] array){ // 比较轮数 for (int i = 0; i < array.length - 1; i++) { //有序的数字就是经过的轮数,相邻两两比较,-1操作防止越界 for (int j = 0; j < array.length - i - 1; j++) { int temp = 0; if(array[j] > array[j+1]){ temp = array[j]; array[j] = array[j+1]; array[j+1] = temp; } } } }
优化: 由上面分析可知,改代码在第三次已经达到了有序,但是用上面方法仍然会将剩下的轮数全部比较,因此可以优化上面代码:
public static void sort(int[] array){ // 比较轮数 for (int i = 0; i < array.length - 1; i++) { //每一轮的初始值为true,(如果最终仍为true,说明经过了一轮的比较,都么发生数据的交换,说明已经全部有序) boolean isSort = true; //有序的数字就是经过的轮数,相邻两两比较,-1操作防止越界 for (int j = 0; j < array.length - i - 1; j++) { int temp = 0; if(array[j] > array[j+1]){ temp = array[j]; array[j] = array[j+1]; array[j+1] = temp; // 交换了说明无序,置为false, isSort = false; } } // 退出循环 if (isSort){ break; } } }
优化:若数据右半区已经有序了,但是左半区仍需要排序,但是根据冒泡的相邻两两比较,仍会对所有数据进行比较,其实只需要比较无序的左半区,可以用一个位置量来标记有序区,所以可以再次优化:
public static void sort(int[] array){ int sortLastIndex = 0;//标记最后一次交换的位置 int sortIndex = array.length - 1;//有序区的起始位置,只需要比到这 // 比较轮数 for (int i = 0; i < array.length - 1; i++) { //每一轮的初始值为true,无交换说明有序 boolean isSort = true; for (int j = 0; j < sortIndex; j++) { int temp = 0; if(array[j] > array[j+1]){ temp = array[j]; array[j] = array[j+1]; array[j+1] = temp; // 交换了说明无序,置为false isSort = false; sortLastIndex = j + 1; } } sortIndex = sortLastIndex; if (isSort){ break; } } }