冒泡排序

来源:互联网 发布:淘宝二维码用微信打开 编辑:程序博客网 时间:2024/06/17 11:43

欢迎Java爱好者品读其他算法详解:

简单比较排序:http://blog.csdn.net/ysjian_pingcx/article/details/8652091

选择排序:        http://blog.csdn.net/ysjian_pingcx/article/details/8656048

直接插入排序:http://blog.csdn.net/ysjian_pingcx/article/details/8674454

快速排序:        http://blog.csdn.net/ysjian_pingcx/article/details/8687444

快速排序优化:http://blog.csdn.net/ysjian_pingcx/article/details/8687444


冒泡排序法<详解+优化>
冒泡排序法,是个大学生都听过吧,游泳时也会吹个泡泡什么的,这个排序算法被老师作为排序算法的入门算法,很基础,由于名字比较特别,我就一直记住了,今天想把这个写下来。

冒泡思想:
假如将不同的数放在不同的气泡中,依次是最小的数放在最大的气泡中,那么,我们知道,在水中,这些气泡会上浮,越大越容易上浮,那么,当一连串气泡挨在一起时,两个相邻的气泡就会在浮力东风作用下交换位置,浮力大的,也就是大的气泡上浮,就这样,一次交换下去,最后是最大的气泡在最上面。

冒泡排序:
Bubble sort 属于一种交换排序,两两比较相邻记录的关键字,如果反序则交换,直到没有反序的记录为止。

两两比较:
@反序:两两交换。
@正序:指针后移,下两个记录两两比较。

看一个冒泡排序一轮排序的的过程:


也就是两两比较,以数组为例,比较过程:
第一轮:数组下标为0的元素与1的元素相比,25<36,正序,指针后移,36>21反序,交换36和21,指针后移,36<45正序,指针后移,45<98正序,指针后移,98>13反序,交换98和13,最后98位于为底端,也就是数组的末尾。比较次数为(n-1)
第二轮:还是从数组下标为0开始两两比较,在第一比较后的结果98就不参与比较,比较次数为(n-2);
......
核心比较和交换的代码:
[java] view plain copy
  1. /** 
  2.      * 原始的冒泡排序法,时间复杂度为O(n2) 
  3.      *  
  4.      * @param array 
  5.      */  
  6.     public void bubbleSort(int... array) {  
  7.         int length = array.length;  
  8.         for (int i = 0; i < length - 1; i++) {  
  9.             for (int j = 0; j < length - i - 1; j++) {// 内部循环的边界要比长度小一  
  10.                 if (array[j] > array[j + 1]) {  
  11.                     swap(j, j + 1, array);//相邻的两个元素比较,将大的放到最右边  
  12.                 }  
  13.             }  
  14.         }  
  15.     }  
@注意上边的外部循环的边界是 length-1,因为最后一个元素不用比较了。
[java] view plain copy
  1. for (int i = 0; i < length - 1; i++)  
@内部循环的边界随着外部循环的变化而变化,也就是在前面比较后的记录就不用参与下一轮的比较。
[java] view plain copy
  1. for (int j = 0; j < length - i - 1; j++)  
@swap依然是一个交换数组两个元素的函数:
[java] view plain copy
  1. /** 
  2.      * 内部实现,用于交换数组的两个引用值 
  3.      *  
  4.      * @param beforeIndex 
  5.      * @param afterIndex 
  6.      * @param arr 
  7.      */  
  8.     private void swap(int oneIndex, int anotherIndex, int[] array) {  
  9.         int temp = array[oneIndex];  
  10.         array[oneIndex] = array[anotherIndex];  
  11.         array[anotherIndex] = temp;  
  12.     }  

那么将完整的代码列出来:
[java] view plain copy
  1. /** 
  2.  * 冒泡排序法 
  3.  *  
  4.  * @author PingCX 
  5.  *  
  6.  */  
  7. public class BubbleSort {  
  8.   
  9.     public static void main(String[] args) {  
  10.         BubbleSort bubbleSort = new BubbleSort();  
  11.         int[] array = { 253621459813};  
  12.         System.out.println(Arrays.toString(array));  
  13.         bubbleSort.bubbleSort(array);// 调用快速排序的方法  
  14.         System.out.println(Arrays.toString(array));// 打印排序后的数组元素  
  15.     }  
  16.   
  17.     /** 
  18.      * 原始的冒泡排序法,时间复杂度为O(n2) 
  19.      *  
  20.      * @param array 
  21.      */  
  22.     public void bubbleSort(int... array) {  
  23.         int length = array.length;  
  24.         for (int i = 0; i < length - 1; i++) {  
  25.             for (int j = 0; j < length - i - 1; j++) {// 内部循环的边界要比长度小一  
  26.                 if (array[j] > array[j + 1]) {  
  27.                     swap(j, j + 1, array);//相邻的两个元素比较,将大的放到最右边  
  28.                 }  
  29.             }  
  30.         }  
  31.     }  
  32.   
  33.     /** 
  34.      * 内部实现,用于交换数组的两个引用值 
  35.      *  
  36.      * @param beforeIndex 
  37.      * @param afterIndex 
  38.      * @param arr 
  39.      */  
  40.     private void swap(int oneIndex, int anotherIndex, int[] array) {  
  41.         int temp = array[oneIndex];  
  42.         array[oneIndex] = array[anotherIndex];  
  43.         array[anotherIndex] = temp;  
  44.     }  
  45. }  


小结:冒泡排序法最核心的地方就是两两比较交换了,这种排序法容易被人理解和记忆,实现起来不难,性能稍高于比较排序算法,时间复杂度也是O(n²)

有一个问题来了:就是如果一个数组开始是有序的,照上面的算法,每一次都要进行比较,这样对有序的数组来说是多余的,我们是不是可以做一些改进,在第一轮比较之后,如果发现有序的,就是没有数据交换,后面的比较可以省去,直接跳出循环呢?
----->答案是可以的,这是我们需要一个标记,boolean  flag = true;辅助我们,看看下面的代码:
[java] view plain copy
  1. /** 
  2.      * 优化的冒泡排序法,时间复杂度为O(n2) 
  3.      *  
  4.      * @param array 
  5.      */  
  6.     public void bubbleSort(int... array) {  
  7.         int length = array.length;  
  8.         boolean flag = true//一个标记  
  9.         for (int i = 0; i < length - 1 && flag; i++) {//加这个条件就是当有序的时候就不用重复后面的操作了  
  10.             flag = false;  
  11.             for (int j = 0; j < length - i - 1; j++) {  
  12.                 if (array[j] > array[j + 1]) {  
  13.                     swap(j, j + 1, array);// 相邻的两个元素比较,将大的放到最右边  
  14.                     flag = true;  
  15.                 }  
  16.             }  
  17.         }  
  18.     }  
@上边的代码多了一个 boolean flag = true;
@外部循环的条件也有所改变:
[java] view plain copy
  1. for (int i = 0; i < length - 1 && flag; i++)  
@开始flag为true,能进入循环,已进入循环就将flag = false;:
[java] view plain copy
  1. for (int i = 0; i < length-1 && flag; i++) {//加这个条件就是当有序的时候就不用重复后面的操作了  
  2.     flag = false;//进入循环体,就置为false  
@在内部循环中,如果存在反序,又将flag置为true,下一轮就可以进入,反之就直接退出外部循环了:
[java] view plain copy
  1. if (array[j] > array[j + 1]) {  
  2.     swap(j, j + 1, array);// 相邻的两个元素比较,将大的放到最右边  
  3.     flag = true;//存在反序的就将flag置为true  
  4. }  
这样就解决了有序数组重复比较的问题,对象能有所优化。


完整代码如下:
[java] view plain copy
  1. /** 
  2.  * 优化的冒泡排序法 
  3.  *  
  4.  * @author PingCX 
  5.  *  
  6.  */  
  7. public class BubbleSortOpt {  
  8.   
  9.     public static void main(String[] args) {  
  10.         BubbleSortOpt bubbleSort = new BubbleSortOpt();  
  11.         int[] array = { 253621459813};  
  12.         System.out.println(Arrays.toString(array));  
  13.         bubbleSort.bubbleSort(array);// 调用快速排序的方法  
  14.         System.out.println(Arrays.toString(array));// 打印排序后的数组元素  
  15.     }  
  16.   
  17.     /** 
  18.      * 优化的冒泡排序法,时间复杂度为O(n2) 
  19.      *  
  20.      * @param array 
  21.      */  
  22.     public void bubbleSort(int... array) {  
  23.         int length = array.length;  
  24.         boolean flag = true//一个标记  
  25.         for (int i = 0; i < length-1 && flag; i++) {//加这个条件就是当有序的时候就不用重复后面的操作了  
  26.             flag = false;//进入循环体,就置为false  
  27.             for (int j = 0; j < length - i - 1; j++) {  
  28.                 if (array[j] > array[j + 1]) {  
  29.                     swap(j, j + 1, array);// 相邻的两个元素比较,将大的放到最右边  
  30.                     flag = true;//存在反序的就将flag置为true  
  31.                 }  
  32.             }  
  33.         }  
  34.     }  
  35.   
  36.     /** 
  37.      * 内部实现,用于交换数组的两个引用值 
  38.      *  
  39.      * @param beforeIndex 
  40.      * @param afterIndex 
  41.      * @param arr 
  42.      */  
  43.     private void swap(int oneIndex, int anotherIndex, int[] array) {  
  44.         int temp = array[oneIndex];  
  45.         array[oneIndex] = array[anotherIndex];  
  46.         array[anotherIndex] = temp;  
  47.     }  
  48. }  

上面是对int[] 进行的排序,那么面向对象的这这应用不能只局限于int[] 数组中,也就是任何可以比较的类型都可以用冒泡来排序,下面是优化后的代码的实现:
[java] view plain copy
  1. /** 
  2.  * 冒泡排序法 
  3.  *  
  4.  * @author PingCX 
  5.  *  
  6.  */  
  7. public class BubbleSortTOpt {  
  8.   
  9.     public static void main(String[] args) {  
  10.         BubbleSortTOpt bubbleSort = new BubbleSortTOpt();  
  11.         Integer[] array = { 253621459813};  
  12.         System.out.println("Before sorting:");  
  13.         System.out.println(Arrays.toString(array));  
  14.         bubbleSort.bubbleSort(array);// 调用冒泡排序的方法  
  15.         System.out.println("After sorting:");  
  16.         System.out.println(Arrays.toString(array));// 打印排序后的数组元素  
  17.     }  
  18.   
  19.     /** 
  20.      * 冒泡排序法,时间复杂度为O(n2) 
  21.      *  
  22.      * @param array 
  23.      */  
  24.     public <T extends Comparable<T>> void bubbleSort(T[] array) {  
  25.         int length = array.length;  
  26.         boolean flag = true;  
  27.         for (int i = 0; i < length - 1 && flag; i++) {  
  28.             flag = false;  
  29.             for (int j = 0; j < length - i - 1; j++) {  
  30.                 if (array[j].compareTo(array[j + 1]) > 0) {  
  31.                     swap(j, j + 1, array);// 相邻的两个元素比较,将大的放到最右边  
  32.                     flag = true;  
  33.                 }  
  34.             }  
  35.         }  
  36.     }  
  37.   
  38.     /** 
  39.      * 内部实现,用于交换数组的两个引用值 
  40.      *  
  41.      * @param beforeIndex 
  42.      * @param afterIndex 
  43.      * @param arr 
  44.      */  
  45.     private <T extends Comparable<T>> void swap(int oneIndex, int anotherIndex,  
  46.             T[] array) {  
  47.         T temp = array[oneIndex];  
  48.         array[oneIndex] = array[anotherIndex];  
  49.         array[anotherIndex] = temp;  
  50.     }  
  51. }  


冒泡冒泡,浮力大了,就会上浮,我们要充实自己,沉淀自己...
"做一个丰盈的男人,不虚华,不浮躁,以先锋的姿态去拼搏奋斗;做一个明媚的女子,不倾国,不倾城,以优雅的姿势去摸爬滚打"

欢迎Java爱好者品读其他算法详解:

简单比较排序:http://blog.csdn.net/ysjian_pingcx/article/details/8652091

选择排序:        http://blog.csdn.net/ysjian_pingcx/article/details/8656048

直接插入排序:http://blog.csdn.net/ysjian_pingcx/article/details/8674454

快速排序:        http://blog.csdn.net/ysjian_pingcx/article/details/8687444

快速排序优化:http://blog.csdn.net/ysjian_pingcx/article/details/8687444


原创粉丝点击