java面试 排序方法总结

阿超 发表于 2009-12-03 10:17 | 来源: | 阅读 172 次

1、冒泡排序 Bubble Sort

      最简单的排序方法是冒泡排序方法。这种方法的基本思想是,将待排序的元素看作是竖着排列的“气泡”,较小的元素比较轻,从而要往上浮。在冒泡排序算法中我们要对这个“气泡”序列处理若干遍。所谓一遍处理,就是自底向上检查一遍这个序列,并时刻注意两个相邻的元素的顺序是否正确。如果发现两个相邻元素的顺序不对,即“轻”的元素在下面,就交换它们的位置。显然,处理一遍之后,“最轻”的元素就浮到了最高位置;处理二遍之后,“次轻”的元素就浮到了次高位置。在作第二遍处理时,由于最高位置上的元素已是“最轻”元素,所以不必检查。一般地,第i遍处理时,不必检查第i高位置以上的元素,因为经过前面i-1遍的处理,它们已正确地排好序。这个算法可实现如下。

算法如下:

/**

    *冒泡排序

    *@paramsrc待排序数组

    */

   void doBubbleSort(int[] src)

   {

      int len=src.length;

      for(int i=0;i<len;i++)

      {

          for(int j=i+1;j<len;j++)

          {

             int temp;

             if(src[i]&gt;src[j])

             {

                 temp=src[j];

                 src[j]=src[i];

                 src[i]=temp;

             }           

          }

          printResult(i,src);

      }    

   }

2、选择排序 Selection Sort

选择排序的基本思想是:对待排序的记录序列进行n-1遍的处理,第1遍处理是将L[1..n]中最小者与L[1]交换位置,第2遍处理是将L[2..n]中最小者与L[2]交换位置,……,第i遍处理是将L[i..n]中最小者与L[i]交换位置。这样,经过i遍处理之后,前i个记录的位置就已经按从小到大的顺序排列好了。当然,实际操作时,也可以根据需要,通过从待排序的记录中选择最大者与其首记录交换位置,按从大到小的顺序进行排序处理。

算法如下:

      /**

    *选择排序

    *@paramsrc待排序的数组

    */

   void doChooseSort(int[] src)

   {

      int len=src.length;

      int temp;

      for(int i=0;i<len;i++)

      {

          temp=src[i];

          int j;

          int samllestLocation=i;//最小数的下标

          for(j=i+1;j<len;j++)

          {

             if(src[j]<temp)

             {

                 temp=src[j];//取出最小值

                 samllestLocation=j;//取出最小值所在下标

             }

          }

          src[samllestLocation]=src[i];

          src[i]=temp;

          printResult(i,src);

      }

   }

3、插入排序 Insertion Sort

插入排序的基本思想是,经过i-1遍处理后,L[1..i-1]己排好序。第i遍处理仅将L[i]插入L[1..i-1]的适当位置,使得L[1..i]又是排好序的序列。要达到这个目的,我们可以用顺序比较的方法。首先比较L[i]和L[i-1],如果L[i-1]≤ L[i]騆[1..i]已排好序,第i遍处理就结束了;否则交换L[i]与L[i-1]的位置,继续比较L[i-1]和L[i-2],直到找到某一个位置j(1≤j≤i-1),使得L[j] ≤L[j+1]时为止。简言之,插入排序就是每一步都将一个待排数据按其大小插入到已经排序的数据中的适当位置,直到全部插入完毕。插入排序方法分直接插入排序和折半插入排序两种,这里只介绍直接插入排序,折半插入排序留到“查找”内容中进行。在下面的插入排序算法中,为了写程序方便我们可以引入一个哨兵元素L[0],它小于L[1..n]中任一记录。所以,我们设元素的类型ElementType中有一个常量-∞,它比可能出现的任何记录都小。如果常量-∞不好事先确定,就必须在决定L[i]是否向前移动之前检查当前位置是否为1,若当前位置已经为1时就应结束第i遍的处理。另一个办法是在第i遍处理开始时,就将L[i]放入L[0]中,这样也可以保证在适当的时候结束第i遍处理。下面的算法中将对当前位置进行判断。

算法如下:

   /**

    *插入排序(WHILE循环实现)

    *@paramsrc待排序数组

    */

   void doInsertSort1(int[] src)

   {

      int len=src.length;

      for(int i=1;i<len;i++)

      { 

          int temp=src[i];

          int j=i;

          while(src[j-1]&gt;temp)

          {

             src[j]=src[j-1];

             j–;

             if(j<=0)

                 break;

          }

          src[j]=temp;

          printResult(i+1,src);

      }

   }

   /**

    *插入排序(FOR循环实现)

    *@paramsrc待排序数组

    */

   void doInsertSort2(int[] src)

   {

      int len=src.length;

      for(int i=1;i<len;i++)

      {

          int j;

          int temp=src[i];

          for(j=i;j&gt;0;j–)

          {

             if(src[j-1]&gt;temp)

             {

                 src[j]=src[j-1];

               

             }else//如果当前的数,不小前面的数,那就说明不小于前面所有的数,

                  //因为前面已经是排好了序的,所以直接通出当前一轮的比较

                 break;

          }

          src[j]=temp;

          printResult(i,src);

      }

   }

 

4:快速排序

是对冒泡排序的一种改进。它的基本思想是:通过一躺排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一不部分的所有数据都要小,然后再按次方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列。最坏情况的时间复杂度为O(n2),最好情况时间复杂度为O(nlog2n)。

  假设要排序的数组是A[1]……A[N],首先任意选取一个数据(通常选用第一个数据)作为关键数据,然后将所有比它的数都放到它前面,所有比它大的数都放到它后面,这个过程称为一躺快速排序。一趟快速排序的算法是:

 1)、设置两个变量I、J,排序开始的时候I:=1,J:=N;

 2)以第一个数组元素作为关键数据,赋值给X,即X:=A[1];

 3)、从J开始向前搜索,即由后开始向前搜索(J:=J-1),找到第一个小于X的值,两者交换;

 4)、从I开始向后搜索,即由前开始向后搜索(I:=I+1),找到第一个大于X的值,两者交换;

 5)、重复第3、4步,直到I=J;

 例如:待排序的数组A的值分别是:(初始关键数据X:=49)

                 A[1]    A[2]    A[3]    A[4]    A[5]     A[6]    A[7]:

                   49       38      65      97      76      13       27

进行第一次交换后:  27       38      65      97      76      13       49

                 ( 按照算法的第三步从后面开始找)

进行第二次交换后:  27       38      49      97      76      13       65

                ( 按照算法的第四步从前面开始找&gt;X的值,65&gt;49,两者交换,此时I:=3 )

进行第三次交换后:  27       38      13      97      76      49       65

( 按照算法的第五步将又一次执行算法的第三步从后开始找)

进行第四次交换后:  27       38      13      49      76      97       65

( 按照算法的第四步从前面开始找大于X的值,97&gt;49,两者交换,此时J:=4 )

    此时再执行第三步的时候就发现I=J,从而结束一躺快速排序,那么经过一躺快速排序之后的结果是:27       38      13     49      76      97       65,即所以大于49的数全部在49的后面,所以小于49的数全部在49的前面。

    快速排序就是递归调用此过程——在以49为中点分割这个数据序列,分别对前面一部分和后面一部分进行类似的快速排序,从而完成全部数据序列的快速排序,最后把此数据序列变成一个有序的序列,根据这种思想对于上述数组A的快速排序的全过程如图6所示:

初始状态                       {49    38    65    97    76    13    27}  

进行一次快速排序之后划分为     {27    38    13}    49  {76    97    65}

分别对前后两部分进行快速排序   {13}   27   {38}

                              结束        结束   {49   65}   76   {97}

                                                  49  {65}        结束

                                                      结束

                        图6   快速排序全过程

 

1)、设有N(假设N=10)个数,存放在S数组中;

2)、在S[1。。N]中任取一个元素作为比较基准,例如取T=S[1],起目的就是在定出T应在排序结果中的位置K,这个K的位置在:S[1。。K-1]<=S[K]<=S[K+1..N],即在S[K]以前的数都小于S[K],在S[K]以后的数都大于S[K];

3)、利用分治思想(即大化小的策略)可进一步对S[1。。K-1]和S[K+1。。N]两组数据再进行快速排序直到分组对象只有一个数据为止。

如具体数据如下,那么第一躺快速排序的过程是:

数组下标: 1     2     3     4     5     6     7     8     9     10

         45    36    18    53    72    30    48    93    15     36

         I                                                       J

(1)     36    36    18    53    72    30    48    93    15     45

(2)     36    36    18    45    72    30    48    93    15     53

(3)     36    36    18    15    72    30    48    93    45     53

(4)     36    36    18    15    45    30    48    93    72     53

(5)     36    36    18    15    30    45    48    93    72     53

通过一躺排序将45放到应该放的位置K,这里K=6,那么再对S[1。。5]和S[6。。10]分别进行快速排序。

   /**

    * 交换指定数组a的两个变量的值

    * @param a 数组应用

    * @param i 数组下标

    * @param j 数组上标

    */

   public static void swap(int a[], int i, int j) {      

       if(i == j) return;

       int tmp = a[i];

       a[i] = a[j];

       a[j] = tmp;

    }

    /**

    *

    * @param array 待排序数组

    * @param low 数组下标下界

    * @param high 数组下标上界

    * @return pivot

    */

   public static int partition(int array[], int low, int high) {

       //当前位置为第一个元素所在位置

       int p_pos = low;

       //采用第一个元素为轴

       int pivot = array[p_pos];

               for (int i = low + 1; i <= high; i++) {

            if (array[i] < pivot) {           

                              p_pos++;

                swap(array, p_pos, i);

            }

       }

        swap(array, low, p_pos);

        return p_pos;

    }

   /**

    * 快速排序实现

    * @param array

    * @param low

    * @param high

    */

   public static void quickSort(int array[], int low, int high) {

        if (low < high) {

            int pivot = partition(array, low, high);

            quickSort(array, low, pivot – 1);

           quickSort(array, pivot + 1, high);

       }

   }

    子类的static方法和父类有同名、同参数的static方法,但他们之间没什么覆盖、继承的关系,你调用的 时候看是用那个类名引用了,用子类的类名就调用子类的static方法,用父类类名就调用父类的static方法。  static   顾名思义,就是静态的,他是方法的,他属于这个类,由于是类的方法,他可以直接引用类名来引用方法,他既不能被子类覆盖,也不能被子类继承。简单的说,他是在编译的时候就和类帮定在一起了,不能被运行时动态加载。

关键字:
喜欢Java豆技术站点的文章,那就通过 RSS Feed 功能订阅阅读吧!

我要评论

*

* 绝不会泄露



返回首页 | 关于我们 | 联系我们 | 广告合作 | 网站地图 | 友情链接 | 版权声明 | 模板设计