快速排序, 应用场景: 数据量大且为线性结构时。

短处:有大量重复数据的时候,性能不好
           单向链式结构处理性能不好(一般来说,链式都不使用)

一次排序过程:

1)取一个高位指针和一个低位指针, 暂存低位指针的值temp

从零开始学算法----图解快速排序_代码实现

 

 

 2)移动高位指针,如果值比Temp大,继续移动不做处理,如果比temp小,则取出来放在低位指针的位置上

从零开始学算法----图解快速排序_代码实现_02

 

 

 

3)然后移动低位指针,如果值比temp小则继续移动不做处理,如果比temp大,则取出来放到高位指针的位置

从零开始学算法----图解快速排序_递归_03

 

 

 4)然后再移动高位指针,与步骤2相同

从零开始学算法----图解快速排序_两个指针_04

5)当有值比temp小时, 把它的值赋给低位指针

从零开始学算法----图解快速排序_快速排序_05

 

 

 6)再移动低位指针

从零开始学算法----图解快速排序_代码实现_06

 

 

 7)如此变换直到两个指针重合

从零开始学算法----图解快速排序_重复数据_07

 

 

 8)把temp的值放在指针重合的位置上

从零开始学算法----图解快速排序_两个指针_08

 

 

 9)这样,经过一轮变换后, 我们可以固定一个数(31)的位置, 它前面的都比它小,它后面的都比它大。

然后我们可以利用递归的思想, 对前面部分和后面部分分别排序。

因为每次排序最坏情况下会执行n次, 所以快排的时间复杂度为n*log2N (n 乘以 log以2为底的n的对数 )

看下代码实现:

 1 public static void quickSort(int[] array, int begin, int end) {
 2         if(begin >= end) {
 3             return;
 4         }
 5         int low = begin;
 6         int high = end;
 7         //先找到低位指针的值temp
 8         int temp = array[low];
 9         boolean direction = true;//定义true为高位指针从右向左移动
10         L1:
11         while (low < high) {
12             //查看高位指针的值, 与temp比较
13             //如果比temp大,高位指针前移一位
14             //如果比temp小,高位指针前移一位且把它的值放在低位指针的位置,然后移动低位指针
15             if (direction) {
16                 for (int i = high; i > low; i--) {
17                     if (array[i] <= temp) {
18                         array[low] = array[i];
19                         low++;
20                         high=i;
21                         //执行到这里后我们要改变策略,开始移动低位指针
22                         //所以我们需要定义一个方向direction,在这里取反
23                         direction = !direction;
24                         //然后还需要让程序回到if (direction)之前的位置
25                         //这里不能用break, 因为会直接跳出去
26                         //所以我们在if (direction)之前写个标记
27                         continue L1;
28                     }
29 
30                 }
31                 //如果if里面的代码从未进去,让两个指针重合
32                 high = low;
33                 //移动低位指针的逻辑
34             }else {
35                 //查看低位指针的值,和temp比较
36                 //如果比temp小,指针后移一位
37                 //如果比temp大, 指针后移一位,且把它的值放在高位指针的位置,然后操作高位指针
38                 for (int i = low; i < high; i++) {
39                     if (array[i] >= temp) {
40                         array[high] = array[i];
41                         high--;
42                         low = i;
43                         //执行到这里后我们要改变策略,开始移动高位指针
44                         direction = !direction;
45                         continue L1;
46                     }
47                 }
48                 //如果if里面的代码从未进去,让两个指针重合
49                 low = high;
50             }
51 
52         }
53         //while 循环执行完之后,两个指针重合,low==high
54         //我们把temp的值放在low的位置
55         //此时low(high)左边值的都比它小,右边值的都比它大
56         array[low] = temp;
57         quickSort(array, begin, low-1);
58         quickSort(array, low+1, end);
59     }

注意这里调用递归的地方

我刚开始写的时候写成了这样

quickSort(array, 0, low-1);
quickSort(array, low+1, array.length-1);

结果运行起来总是报stackOverFlowError.   

之所以会这样写,还是没有理解递归的思想。虽然我们整个方法里没有地方去对begin/ end赋值, 但因为递归调用(low-1和low+1)被传进去,所以begin和end的取值时不断在变化的, 不能hardcode. 

看看方法调用及排序结果:

1 @Test
2     fun test(){
3         val array = intArrayOf(4, 7, 91, 10, 21, 14, 22, 1, 62, 103, 5, 10)
4         quickSort(array, 0, array.size - 1)
5         for (i in array.indices) {
6             print(array[i].toString() + " ")
7         }
8     }
从零开始学算法----图解快速排序_重复数据_09