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 }

猜你喜欢

转载自www.cnblogs.com/zsh-blogs/p/10391541.html