排序与查找实例(三):快速排序

来源:互联网 发布:u盘安装linux系统教程 编辑:程序博客网 时间:2024/05/19 15:19

    快速排序算法和归并排序类似,都是属于分治算法。

    快速排序使用分治法(Divide and conquer)策略来把一个串行(list)分为两个子串行(sub-lists)。

    步骤为:

          从数列中挑出一个元素,称为 “基准”(pivot),重新排序数列,所有元素比基准值小的摆放在基准前面,所有元素比基准值大的摆在基准的后面(相同的数可以到任一边)。在这个分区退出之后,该基准就处于数列的中间位置。这个称为分区(partition)操作。递归地(recursive)把小于基准值元素的子数列和大于基准值元素的子数列排序。

虽然快速排序是分治算法,但其中主要的操作是分区操作,这个操作的复杂性应该是线性的。划分的实现由很多种,朴素的实现是选取第一个元素和最后一个元素作为基准作为划分。算法导论一书给出的partition 函数是取最后一个元素作为基准,然后通过一遍循环交换元素。代码虽然简洁,但是初看起来不太易懂,建议在纸上模拟下过程。此种方法相对来说交换元素的次数也比较多,后面会给出一种优化的操作。

    具体实现如下:

    

/**  

*@Title: QuickSort.java

*@Package sortandsearch

*@Description: TODO

*@author peidong 

*@date 2017-5-10 上午9:34:54

*@version V1.0  

*/

packagesortandsearch;

 

/**

 * @ClassName: QuickSort

 * @Description: 快速排序实例

 * @date 2017-5-10 上午9:34:54

 * 

 */


publicclass QuickSort {

 

       static int num = 0;  //快排的比较次数

       /**

        *

       * @Title: partition

       * @Description: 快排的核心,划分比较

       * @param arr

       * @param low

       * @param high

       * @return   

       * @return int   

       * @throws

        */

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

              //临时变量,用于保存初始值

              int key = arr[low];

             

              //开始比较

              while(low < high){

                     while(low < high&& arr[high] >= key){  //从后向前查找直到小的

                            high--;

                            num++;

                     }

                     //找到之后进行交换

                     arr[low] = arr[high]; //(此时因low=high或data[high]<key)将high下标处的数赋给low下标处的数,保证data[low]<key

                    

                     while(low < high&& arr[low] <= key){  //从前向后找,直到找到大的

                            low++;

                            num++;

                     }

                    

                     //找到之后交换

                     arr[high] = arr[low]; //(此时因low=high或data[low]>key)将low下标处的数赋给high下标处的数,保证data[high]>key

              }

             

              //查找完成之后进行赋值

              arr[low] = key;

              return low;

       }

      

       /**

        *

       * @Title: quickSort

       * @Description: 快排,递归

       * @param arr

       * @param low

       * @param high

       * @return   

       * @return int[]   

       * @throws

        */

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

              if(low < high){

                     int res = partition(arr,low, high);

                     //递归排序

                     quickSort(arr, low, res);//对low到result下标间数进行排序

                     quickSort(arr, res + 1,high); //对result+1到high下标间数进行排序

              }

              return arr;

       }

       /**

        *@Title: main

        *@Description: 测试用例

        *@param args   

        *@return void   

        *@throws

        */

       public static void main(String[] args) {

              // TODO Auto-generated method stub

              int[] arr = {8, 5, 7, 1, 99, 44,78, 22};

             

              System.out.println("原始数组:");

              for(int a : arr){

                     System.out.print(a + "");

              }

             

              int[] res = quickSort(arr, 0,arr.length - 1);

             

              System.out.println();

              System.out.println("快排后数组");

             

              for(int a : res){

                     System.out.print(a + "");

              }

             

              System.out.println();

              System.out.println("比较次数:" + num);

       }

 

}

 

快排的时间复杂度,最好的情况下是O(nlgn),最坏的情况下位O(n^2)。当待排序数据基本无序时,快排的速度是最快的,而当数据是基本有序时,其反而是最慢的。