|
| 1 | +###Java冒泡排序 |
| 2 | +####排序算法概述 |
| 3 | +所谓排序,就是使一串记录,按照其中的某个或某些关键字的大小,递增或递减的排列起来的操作。排序算法,就是如何使得记录按照要求排列的方法。排序算法在很多领域得到相当地重视,尤其是在大量数据的处理方面。 |
| 4 | + |
| 5 | +**稳定性**:一个排序算法是稳定的,就是当有两个相等记录的关键字R和S,且在原本的列表中R出现在S之前,在排序过的列表中R也将会是在S之前。 |
| 6 | + |
| 7 | +如果算法是稳定的有什么好处呢?排序算法如果是稳定的,那么从一个键上排序,然后再从另一个键上排序,第一个键排序的结果可以为第二个键排序所用。基数排序就是这样,先按低位排序,逐次按高位排序,低位相同的元素其顺序再高位也相同时是不会改变的。 |
| 8 | + |
| 9 | +排序算法根据是否需要访问外存分为内部排序和外部排序。 |
| 10 | + |
| 11 | +**内部排序**是指待排序列完全存放在内存中所进行的排序过程,适合不太大的元素序列。 |
| 12 | + |
| 13 | +**外部排序**指的是大文件的排序,即待排序的记录存储在外存储器上,待排序的文件无法一次装入内存,需要在内存和外部存储器之间进行多次数据交换,以达到排序整个文件的目的。 |
| 14 | + |
| 15 | + |
| 16 | + |
| 17 | +我们现在要讨论的排序都是内部排序。 |
| 18 | + |
| 19 | +**冒泡排序** |
| 20 | + |
| 21 | +冒泡排序的效率很低,但是算法实现起来很简单,因此很适合作为研究排序的入门算法。 |
| 22 | + |
| 23 | +**基本思想** |
| 24 | + |
| 25 | +对当前还未排好序的范围内的全部数,自上而下对相邻的俩个数依次进行比较和调整,让较大的数下沉,较小的数往上冒。即:每当俩相邻的数比较后发现他们的排序与排序的要求相反时,就将他们交换。每次遍历都可确定一个最大值放到待排数组的末尾,下次遍历,对该最大值以及它之后的元素不再排序(已经排好)。 |
| 26 | + |
| 27 | + |
| 28 | + |
| 29 | +java实现 |
| 30 | + |
| 31 | + public class Sort{ |
| 32 | + |
| 33 | + private int [] array; |
| 34 | + public Sort(int [] array){ |
| 35 | + this.array = array; |
| 36 | + } |
| 37 | + |
| 38 | + //按顺序打印数组中的元素 |
| 39 | + public void display(){ |
| 40 | + for(int i=0;i<array.length;i++){ |
| 41 | + System.out.print(array[i]+"\t"); |
| 42 | + } |
| 43 | + System.out.println(); |
| 44 | + } |
| 45 | + |
| 46 | + //冒泡排序 |
| 47 | + public void bubbleSort(){ |
| 48 | + int temp; |
| 49 | + int len = array.length; |
| 50 | + for(int i=0;i<len-1;i++){ //外层循环:每循环一次就确定了一个相对最大元素 |
| 51 | + for(int j=1;j<len-i;j++){ //内层循环:有i个元素已经排好,根据i确定本次的比较次数 |
| 52 | + if(array[j-1]>array[j]){ //如果前一位大于后一位,交换位置 |
| 53 | + temp = array[j-1]; |
| 54 | + array[j-1] = array[j]; |
| 55 | + array[j] = temp; |
| 56 | + } |
| 57 | + } |
| 58 | + System.out.print("第"+(i+1)+"轮排序结果:"); |
| 59 | + display(); |
| 60 | + } |
| 61 | + } |
| 62 | + } |
| 63 | + |
| 64 | +测试: |
| 65 | + |
| 66 | + public static void main(String[] args) { |
| 67 | + int [] a = {1,5,4,11,2,20,18}; |
| 68 | + Sort sort = new Sort(a); |
| 69 | + System.out.print("未排序时的结果:"); |
| 70 | + sort.display(); |
| 71 | + sort.bubbleSort(); |
| 72 | + } |
| 73 | + |
| 74 | +打印结果: |
| 75 | + |
| 76 | + |
| 77 | + |
| 78 | +**算法分析** |
| 79 | + |
| 80 | +上面的例子中,待排数组中一共有7个数,第一轮排序时进行了6次比较,第二轮排序时进行了5比较,依次类推,最后一轮进行了一次比较。加入元素总数为N,则一共需要的比较次数为: |
| 81 | + |
| 82 | + (N-1)+ (N-2)+ (N-3)+ ...1=N*(N-1)/2 |
| 83 | + |
| 84 | +这样,算法约做了N2/2次比较。因为只有在前面的元素比后面的元素大时才交换数据,所以交换的次数少于比较的次数。如果数据是随机的,大概有一半数据需要交换,则交换的次数为N2/4(不过在最坏情况下,即初始数据逆序时,每次比较都需要交换)。 |
| 85 | + |
| 86 | +交换和比较的操作次数都与N2成正比,由于在大O表示法中,常数忽略不计,冒泡排序的时间复杂度为O(N2)。O(N2)的时间复杂度是一个比较糟糕的结果,尤其在数据量很大的情况下。所以冒泡排序通常不会用于实际应用。 |
| 87 | + |
| 88 | +**冒泡排序的改进** |
| 89 | + |
| 90 | +上面已经分析过,冒泡排序的效率比较低,所以我们要通过各种方法改进。 |
| 91 | + |
| 92 | +最简单的改进方法是加入一标志性变量exchange,用于标志某一趟排序过程中是否有数据交换,如果进行某一趟排序时并没有进行数据交换,则说明数据已经按要求排列好,可立即结束排序,避免不必要的比较过程. |
| 93 | + |
| 94 | +在上例中,第四轮排序之后实际上整个数组已经是有序的了,最后两轮的比较没必要进行。 |
| 95 | + |
| 96 | +改进后的代码如下: |
| 97 | + |
| 98 | + //冒泡排序改进1 |
| 99 | + public void bubbleSort_improvement_1(){ |
| 100 | + int temp; |
| 101 | + int len = array.length; |
| 102 | + |
| 103 | + for(int i=0;i<len-1;i++){ |
| 104 | + boolean exchange = false; //设置交换变量 |
| 105 | + for(int j=1;j<len-i;j++){ |
| 106 | + if(array[j-1]>array[j]){ //如果前一位大于后一位,交换位置 |
| 107 | + temp = array[j-1]; |
| 108 | + array[j-1] = array[j]; |
| 109 | + array[j] = temp; |
| 110 | + |
| 111 | + if(!exchange) exchange =true; //发生了交换操作 |
| 112 | + } |
| 113 | + } |
| 114 | + System.out.print("第"+(i+1)+"轮排序结果:"); |
| 115 | + display(); |
| 116 | + if(!exchange) break; //如果上一轮没有发生交换数据,证明已经是有序的了,结束排序 |
| 117 | + } |
| 118 | + } |
| 119 | + |
| 120 | +用同样的初始数组测试,打印结果如下: |
| 121 | + |
| 122 | + |
| 123 | + |
| 124 | + |
0 commit comments