資料結構與演算法 排序演算法 快速排序【詳細步驟圖解】
阿新 • • 發佈:2020-05-23
# 快速排序
給定一個序列:`22 33 49 47 33' 12 68 29`
進行快速排序
## 主要思想
- 從序列中,任選一個記錄`k`作為**軸值 `pivot`**
選擇策略:
- 第一個元素
- 最後一個元素
- 中間元素
- 隨機選擇
- 將剩餘的元素,分割成 **左子序列 L** 和 **右子序列 R**
- L 中所有元素都 < k, R 中所有元素都 > k
- 對 L 和 R遞迴進行快排,直到子序列中有 0 個 或者 1 個元素,退出
## 圖解
初始陣列:
選定`47`為軸值`pivot`
![image-20200522200024944](https://gitee.com/Pineapple47/DataStructureAndAlgorithm/raw/master/排序_快速排序20200522200026.png)
`pivot`與最後一個值`29`進行交換(**==把`pivot`放到最後面==**)
![image-20200522200152016](https://gitee.com/Pineapple47/DataStructureAndAlgorithm/raw/master/排序_快速排序20200522200153.png)
**接下來,以`pivot=47`為界,分成左子序列 `L `和右子序列 `R`**
比`47`大的都放在右邊,比`47`小的都放在左邊(用的交換)
**遍歷陣列**
- 兩個指標`left`和`right`
- 當`left != right`的時候
- 若`arr[left]`的,小於等於`pivot`,且`left < right`的時候,`left`右移
- 如果`left`和`right`未相遇,把`left`的值賦給`right`對應的值
- `arr[right] = arr[left]`
- `left`指標停止移動,輪到`right`移動
- 當`arr[right]`的值,大於等於`pivot`,且`right > left`的時候,`right`左移
- 如果`left`和`right`未相遇。把`right`的值賦給`left`對應的值
- `arr[left] = arr[right]`
- `right`指標停止移動,輪到`left`移動
- **注意:軸值用`pivot`儲存**
### 第一輪分割序列
![image-20200522213014584](https://gitee.com/Pineapple47/DataStructureAndAlgorithm/raw/master/排序_快速排序20200522213015.png)
`pivot=47`和最後一個值互換
![image-20200522205447912](https://gitee.com/Pineapple47/DataStructureAndAlgorithm/raw/master/排序_快速排序20200522205454.png)
`22 <= 47`,`left`向右移動
![image-20200522205623534](https://gitee.com/Pineapple47/DataStructureAndAlgorithm/raw/master/排序_快速排序20200522210121.png)
`33 <= 47`,`left`向右移動
![image-20200522205648022](https://gitee.com/Pineapple47/DataStructureAndAlgorithm/raw/master/排序_快速排序20200522210109.png)
`49 > 47`,不滿足`arr[left] <= pivot`
把`left`的值賦給`right`
`arr[right] = arr[left]`
![image-20200522210144784](https://gitee.com/Pineapple47/DataStructureAndAlgorithm/raw/master/排序_快速排序20200522210148.png)
**賦值過後,`left`不動,`right`向左移動**
![image-20200522211704648](https://gitee.com/Pineapple47/DataStructureAndAlgorithm/raw/master/排序_快速排序20200522211706.png)
`68 >= 47`,right向左移動
![image-20200522211823993](https://gitee.com/Pineapple47/DataStructureAndAlgorithm/raw/master/排序_快速排序20200522211830.png)
`12 < 47`,不滿足`arr[right] >= pivot`
把`right`的值賦給`left`
`arr[left] = arr[right]`
![image-20200522211941103](https://gitee.com/Pineapple47/DataStructureAndAlgorithm/raw/master/排序_快速排序20200522211942.png)
**賦值過後,`right`不動,`left`向右移動**
![image-20200522212237784](https://gitee.com/Pineapple47/DataStructureAndAlgorithm/raw/master/排序_快速排序20200522212242.png)
`29 < 47`,`left`向右移動
![image-20200522212313112](https://gitee.com/Pineapple47/DataStructureAndAlgorithm/raw/master/排序_快速排序20200522212314.png)
`33' < 47`,`left`向右移動
![image-20200522215707618](https://gitee.com/Pineapple47/DataStructureAndAlgorithm/raw/master/排序_快速排序20200522215708.png)
向右移動後,`left == right`,退出迴圈
將`pivot`賦給`arr[left]`
![image-20200522215538138](https://gitee.com/Pineapple47/DataStructureAndAlgorithm/raw/master/排序_快速排序20200522215539.png)
**至此,第一輪分割序列完成**
### 第二輪分割序列 --- 左子序列
經過第一輪分割,`47`左邊的是左子序列,右邊是右子序列
**第二輪對左子序列分割,選擇中間值作為`pivot`**
![image-20200522223949257](https://gitee.com/Pineapple47/DataStructureAndAlgorithm/raw/master/排序_氣泡排序20200522223950.png)
`12和33'`進行交換
![image-20200522220137128](https://gitee.com/Pineapple47/DataStructureAndAlgorithm/raw/master/排序_快速排序20200522220142.png)
`22 > 12`,不滿足`arr[left] <= pivot`
把`arr[left]`賦給`arr[right]`
`arr[right] = arr[left]`
![image-20200522220327264](https://gitee.com/Pineapple47/DataStructureAndAlgorithm/raw/master/排序_快速排序20200522220328.png)
**賦值過後,`left`不動,`right`向左移動**
`29、33'、33`都比`12`大,所以`right`一直移動到下圖位置
![image-20200522220446889](https://gitee.com/Pineapple47/DataStructureAndAlgorithm/raw/master/排序_快速排序20200522220448.png)
`33 > 12`,`right`繼續向左移動
![image-20200522220515361](https://gitee.com/Pineapple47/DataStructureAndAlgorithm/raw/master/排序_快速排序20200522220516.png)
此時`right == left`,終止迴圈
把`pivot`賦給`arr[left]`
![image-20200522220557616](https://gitee.com/Pineapple47/DataStructureAndAlgorithm/raw/master/排序_快速排序20200522220559.png)
**至此,左子序列1也分割完成了**
#### 小結
快排就是一個遞迴的過程,分割得到左子序列
再對左子序列進行快排分割,得到左子序列的左子序列....
處理完左邊,再去處理右邊的右子序列
### 第三輪分割序列 --- 右子序列
右子序列只有`47、68、49`,選擇`48`作為**軸值 pivot**
![image-20200522220854832](https://gitee.com/Pineapple47/DataStructureAndAlgorithm/raw/master/排序_快速排序20200522220929.png)
`pivot`和最後一個值交換
![image-20200522221012928](https://gitee.com/Pineapple47/DataStructureAndAlgorithm/raw/master/排序_快速排序20200522221014.png)
`47、49`都比`pivot=68`小,`left`一直向右移動,直到`left == right`
![image-20200522221104705](https://gitee.com/Pineapple47/DataStructureAndAlgorithm/raw/master/排序_快速排序20200522221106.png)
分割之後,只剩下左子序列:`47、49`
`47、49`,選`49`作為軸值,得到左子序列`47`
子序列只剩下一個元素`47`,就不必排序了,右邊排序結束
**結果:`47、49、68`**
## C++實現
**選擇中間的值作為軸值**
```C++
#include
#include
#include
#include
#include
#include
#include
#include
#include