快速排序

快速排序(Java)

声明:此文章参考https://www.cnblogs.com/c4isr/p/4603980.html

一、原理(分治法)

  1. 先从数列中取出一个数作为基准数。
  2. 分区过程,将比这个数大的数全放到它的右边,小于或等于它的数全放到它的左边。
  3. 再对左右区间重复第二步,直到各区间只有一个数

二、时间复杂度

  时间复杂度为O(nlog2n)~O(n2),空间复杂度O(log2n),此排序是不稳定的

三、代码实现

  这里主要是有三种选取基准元的方法,不同选取基准元的方法有不同的用处,还有一些快速排序的优化算法,具体可以看文章开头的链接

  1. 固定基准元(基本的快速排序方法)
  2. 随机基准元(在待排序列是部分有序时,固定选取基准元使快排效率底下,要缓解这种情况,就引入了随机选取基准元)
  3. 三数取中基准元(虽然随机选取基准时,减少出现不好分割的几率,但是还是最坏情况下还是O(n^2),要缓解这种情况,就引入了三数取中选取基准)
  1 /**
  2      * 划分数组
  3      * @param arr 数组
  4      * @param low 起始位置
  5      * @param high 结束位置
  6      */
  7     public int partition(int arr[],int low,int high) {
  8         //如果传入的参数不符合,结束
  9         if (arr == null || low < 0 || high >= arr.length) {
 10             new Exception("输出不合法!");
 11         }
 12         //固定基准元为数组第一位
 13         int point = arr[low];
 14         while (low < high) {
 15             //如果从后往前与基准值比较,发现比基准值大,则下标减一
 16             while (low < high && arr[high] >= point){
 17                 high--;
 18             }
 19             //从后往前遍历完后,将该位置上的值赋给数组第一位(此时数组第一位已被复制到point中,可以认为现在它是空的)
 20             arr[low] = arr[high];
 21             //同理,从前往后与基准值比较,比基准值小,则下标加一
 22             while (low < high && arr[low] <= point){
 23                 low++;
 24             }
 25             //同理,arr[high]上的值已经被上一个的arr[low]复制,所以也可以认为现在这个位置是空的,可以进行复制(挖空原理)
 26             arr[high] = arr[low];
 27         }
 28         //最后将基准值赋给最后一个空位置,补全数组
 29         arr[low] = point;
 30         return low;
 31     }
 32 
 33     /**
 34      * 随机选取基准值
 35      * 选取之后与数组首位进行交换,等到进行快速排序时,直接选取首位,就相当于随机选择了基准值
 36      * @param arr
 37      * @param left
 38      * @param right
 39      */
 40     public void referenceValue(int arr[],int left, int right) {
 41         //随机选择一个基准,预防待排数据有序,选择的数据是left-right之间
 42         Random random = new Random();
 43         int randomPoint = random.nextInt(right - left +1) + left;
 44         System.out.println("选择的基准数下标为:" + randomPoint + "\n基准数为:" + arr[randomPoint]);
 45         System.out.println("arr[" + randomPoint + "]与数组arr[" + left + "]进行交换");
 46         System.out.println("=========================");
 47         swap(arr,randomPoint,left);
 48     }
 49 
 50     /**
 51      * 三数取中基准元,并将确定好的基准元与数组首位交换
 52      * @param arr
 53      * @param low
 54      * @param high
 55      */
 56     public void partitionMedianOfThree(int[] arr, int low, int high){
 57         int mid = low + (high + -low) / 2;
 58         if (arr[mid] > arr[high])
 59         {
 60             swap(arr, mid, high);
 61         }
 62         if (arr[low] > arr[high])
 63         {
 64             swap(arr, low, high);
 65         }
 66         //将中间大小的数与第一个数交换
 67         if (arr[mid] > arr[low])
 68         {
 69             swap(arr, mid, low);
 70         }
 71     }
 72 
 73     /**
 74      * 固定基准元排序
 75      * @param arr
 76      * @param left
 77      * @param right
 78      */
 79     public void sort(int[] arr, int left, int right) {
 80         if (left < right) {
 81             int boundary = partition(arr,left,right);
 82             sort(arr, left, boundary - 1);
 83             sort(arr, boundary + 1, right);
 84         }
 85     }
 86 
 87     /**
 88      * 随机基准元排序
 89      * @param arr
 90      * @param left
 91      * @param right
 92      */
 93     public void sortRandom(int[] arr, int left, int right) {
 94         if (left < right) {
 95             referenceValue(arr,left,right);
 96             int boundary = partition(arr,left,right);
 97             sort(arr, left, boundary - 1);
 98             sort(arr, boundary + 1, right);
 99         }
100     }
101 
102     /**
103      * 三数取中基准元快速排序
104      * @param arr
105      * @param left
106      * @param right
107      */
108     public void sortMedianOfThree(int []arr, int left, int right) {
109         if (left < right) {
110             partitionMedianOfThree(arr,left,right);
111             int boundary = partition(arr,left,right);
112             sort(arr, left, boundary - 1);
113             sort(arr, boundary + 1, right);
114         }
115     }
116 
117     /**
118      * 交换函数
119      * @param arr
120      * @param left
121      * @param right
122      */
123     public void swap(int arr[],int left,int right) {
124         int temp = arr[left];
125         arr[left] = arr[right];
126         arr[right] = temp;
127     }
128 
129 
130     @Test
131     public void quickSort(){
132         int[] arr = new int[10];
133         for (int i = 0; i < arr.length; i++) {
134             arr[i] = (int) (Math.random()*100);
135         }
136         System.out.println("------原始数据------\n"+
137                 Arrays.toString(arr));
138         // sort(arr,0, arr.length - 1);
139         // sortRandom(arr,0,arr.length - 1);
140         sortMedianOfThree(arr,0,arr.length - 1);
141         System.out.println("------排序结果-------");
142         System.out.println(Arrays.toString(arr));
143     }
原文地址:https://www.cnblogs.com/xiayiLL/p/15651342.html