Java排序算法之快速排序


一、算法原理

  基於分治的思想,是冒泡排序的改進型。首先在數組中選擇一個基准點(該基准點的選取可能影響快速排序的效率,后面講解選取的方法),然后分別從數組的兩端掃描數組,設兩個指示標志(low指向起始位置,high指向末尾),首先從后半部分開始,如果發現有元素比該基准點的值小,就交換low和high位置的值,然后從前半部分開始掃秒,發現有元素大於基准點的值,就交換low和hi位置的值,如此往復循環,直到low>=high,然后把基准點的值放到hi這個位置。一次排序就完成了。以后采用遞歸的方式分別對前半部分和后半部分排序,當前半部分和后半部分均有序時該數組就自然有序了。

二、算法舉例

三、算法實現

 

 1 /**
 2      * 查找出中軸(默認是最低位low)的在numbers數組排序后所在位置
 3      *
 4      * @param array 待查找數組
 5      * @param lo   開始位置
 6      * @param hi  結束位置
 7      * @return  中軸所在位置
 8      */
 9     static int getMiddle(int []array,int lo,int hi) {
10         //固定的切分方式
11         int key=array[lo];
12         while(lo<hi){
13             //從后半部分向前掃描
14             while(array[hi]>=key&&hi>lo){
15                 hi--;
16             }
17             array[lo]=array[hi];
18             //從前半部分向后掃描
19             while(array[lo]<=key&&hi>lo){
20                 lo++;
21             }
22             array[hi]=array[lo];
23         }
24         array[hi]=key;
25         return hi;
26     }
27 
28     /**
29      *
30      * @param numbers 帶排序數組
31      * @param low  開始位置
32      * @param high 結束位置
33      */
34     static int[] quickSort(int[] numbers,int low,int high) {
35         if(low < high) {
36             int middle = getMiddle(numbers,low,high); //將numbers數組進行一分為二
37             quickSort(numbers, low, middle-1);   //對低字段表進行遞歸排序
38             quickSort(numbers, middle+1, high); //對高字段表進行遞歸排序
39         }
40         return numbers;
41     }

  快速排序的時間復雜度為O(NlogN)。

四、算法優化

  對於基准位置的選取一般有三種方法:固定切分,隨機切分和三取樣切分。固定切分的效率並不是太好,隨機切分是常用的一種切分,效率比較高,最壞情況下時間復雜度有可能為O(N2).對於三數取中選擇基准點是最理想的一種。

 1 /**
 2      *
 3      * @param array 待排序的數組
 4      * @param lo 開始位置
 5      * @param hi 結束位置
 6      * @return 基准值所在位置
 7      */
 8     static int partition(int []array,int lo,int hi){
 9         //三數取中
10         int mid=lo+(hi-lo)/2;
11         if(array[mid]>array[hi]){
12             swap(array[mid],array[hi]);
13         }
14         if(array[lo]>array[hi]){
15             swap(array[lo],array[hi]);
16         }
17         if(array[mid]>array[lo]){
18             swap(array[mid],array[lo]);
19         }
20         int key=array[lo];
21 
22         while(lo<hi){
23             while(array[hi]>=key&&hi>lo){
24                 hi--;
25             }
26             array[lo]=array[hi];
27             while(array[lo]<=key&&hi>lo){
28                 lo++;
29             }
30             array[hi]=array[lo];
31         }
32         array[hi]=key;
33         return hi;
34     }
35 
36     /**
37      * 交換a,b的值
38      * @param a 待交換a
39      * @param b 待交換b
40      */
41     static void swap(int a,int b){
42         int temp=a;
43         a=b;
44         b=temp;
45     }
46 
47     /**
48      *
49      * @param array 帶排序數組
50      * @param lo  開始位置
51      * @param hi 結束位置
52      */
53     static int[] sort(int[] array,int lo ,int hi){
54         if(lo>=hi){
55             return array;
56         }
57         int index=partition(array,lo,hi);
58         sort(array,lo,index-1);
59         sort(array,index+1,hi);
60         return array;
61     }

  快速排序在序列中元素很少時,效率將比較低,不然插入排序,因此一般在序列中元素很少時使用插入排序,這樣可以提高整體效率。

測試用例:

  1 package recursion;
  2 
  3 import java.util.Arrays;
  4 
  5 /**
  6  * @author zsh
  7  * @company wlgzs
  8  * @create 2019-02-17 15:32
  9  * @Describe 快速排序
 10  */
 11 public class QuickSort {
 12 
 13     /**
 14      * 查找出中軸(默認是最低位low)的在numbers數組排序后所在位置
 15      *
 16      * @param array 待查找數組
 17      * @param lo   開始位置
 18      * @param hi  結束位置
 19      * @return  中軸所在位置
 20      */
 21     static int getMiddle(int []array,int lo,int hi) {
 22         //固定的切分方式
 23         int key=array[lo];
 24         while(lo<hi){
 25             //從后半部分向前掃描
 26             while(array[hi]>=key&&hi>lo){
 27                 hi--;
 28             }
 29             array[lo]=array[hi];
 30             //從前半部分向后掃描
 31             while(array[lo]<=key&&hi>lo){
 32                 lo++;
 33             }
 34             array[hi]=array[lo];
 35         }
 36         array[hi]=key;
 37         return hi;
 38     }
 39 
 40     /**
 41      *
 42      * @param numbers 帶排序數組
 43      * @param low  開始位置
 44      * @param high 結束位置
 45      */
 46     static int[] quickSort(int[] numbers,int low,int high) {
 47         if(low < high) {
 48             int middle = getMiddle(numbers,low,high); //將numbers數組進行一分為二
 49             quickSort(numbers, low, middle-1);   //對低字段表進行遞歸排序
 50             quickSort(numbers, middle+1, high); //對高字段表進行遞歸排序
 51         }
 52         return numbers;
 53     }
 54 
 55     /**
 56      *
 57      * @param array 待排序的數組
 58      * @param lo 開始位置
 59      * @param hi 結束位置
 60      * @return 基准值所在位置
 61      */
 62     static int partition(int []array,int lo,int hi){
 63         //三數取中
 64         int mid=lo+(hi-lo)/2;
 65         if(array[mid]>array[hi]){
 66             swap(array[mid],array[hi]);
 67         }
 68         if(array[lo]>array[hi]){
 69             swap(array[lo],array[hi]);
 70         }
 71         if(array[mid]>array[lo]){
 72             swap(array[mid],array[lo]);
 73         }
 74         int key=array[lo];
 75 
 76         while(lo<hi){
 77             while(array[hi]>=key&&hi>lo){
 78                 hi--;
 79             }
 80             array[lo]=array[hi];
 81             while(array[lo]<=key&&hi>lo){
 82                 lo++;
 83             }
 84             array[hi]=array[lo];
 85         }
 86         array[hi]=key;
 87         return hi;
 88     }
 89 
 90     /**
 91      * 交換a,b的值
 92      * @param a 待交換a
 93      * @param b 待交換b
 94      */
 95     static void swap(int a,int b){
 96         int temp=a;
 97         a=b;
 98         b=temp;
 99     }
100 
101     /**
102      *
103      * @param array 帶排序數組
104      * @param lo  開始位置
105      * @param hi 結束位置
106      */
107     static int[] sort(int[] array,int lo ,int hi){
108         if(lo>=hi){
109             return array;
110         }
111         int index=partition(array,lo,hi);
112         sort(array,lo,index-1);
113         sort(array,index+1,hi);
114         return array;
115     }
116 
117     /**
118      * insertSort(arr,k) 遞歸實現插入排序
119      * 找重復:insertSort(arr,k-1) 將k-1個排序后,把arr[k]插入到前面的數據中 --子問題
120      * 找變化:變化的量應該作為參數 k。
121      * 找邊界:出口 終止的條件 k == 0
122      */
123     static int[] insertSort(int[] arr,int k){
124         if (k == 0){
125             return arr;
126         }
127         //對前k-1個元素排序
128         insertSort(arr,k-1);
129         //把k位置上的元素插入到前面的部分
130         int x = arr[k];
131         int index = k -1;
132         while (index >= 0 && x <arr[index]){
133             arr[index+1] = arr[index];
134             index--;
135         }
136         arr[index+1] = x;
137         return arr;
138     }
139 
140     /**
141      * 優化后的快速排序算法
142      * @param array 待排序數組
143      * @param lo 開始位置
144      * @param hi 結束位置
145      * @return 已排序的數組
146      */
147     static int[] quick(int []array ,int lo,int hi){
148         if(hi-lo+1<10){
149             return insertSort(array,array.length-1);
150         }else{
151             return sort(array,lo,hi);
152         }
153     }
154 
155     public static void main(String[] args) {
156         int[] arr = new int[]{6,3,7,4,1,5,8,9,5,44,6,5};
157         System.out.println(Arrays.toString(quickSort(arr,0,arr.length-1)));
158         System.out.println(Arrays.toString(sort(arr,0,arr.length-1)));
159         System.out.println(Arrays.toString(quick(arr,0,arr.length-1)));
160     }
161 }

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM