秒懂算法 | 快速排序算法中的分治思想
讲解快速排序的分治递归算法。
快速排序是C.R.A.Hoare于1962年提出的一种划分交换排序,其基本思想是通过一趟扫描将待排序的元素分割成独立的三个序列:第一个序列中所有元素均不大于基准元素、第二个序列是基准元素、第三个序列中所有元素均大于基准元素。由于第二个序列已经处于正确位置,因此需要再按此方法对第一个序列和第三个序列分别进行排序,整个排序过程可以递归进行,最终可使整个序列变成有序序列。
01
问题分析——分与治的方法
(1) 分解:快速排序的分解是基于基准元素的,所以首先要选定一个元素作为基准元素,然后以选定的基准元素为标杆,将其他元素分成两部分,一部分不大于基准元素,另一部分大于基准元素。
(2) 基准元素的选取:从待排序序列中选取的基准元素是决定算法性能的关键。基准元素的选取应该遵循平衡子问题的原则,即使得划分后的两个子序列的长度尽量相同。基准元素的选择方法有很多种,常用的有以下5种。
① 取第一个元素。即以待排序序列的首元素作为基准元素。
② 取最后一个元素。即以待排序序列的尾元素作为基准元素。
③ 取位于中间位置的元素。即以待排序序列的中间位置的元素作为基准元素。
④ “三者取中的规则”。即在待排序序列中,将该序列的第一个元素、最后一个元素和中间位置的元素进行比较,取三者之中值作为基准元素。
⑤ 随机取一个元素作为基准元素。
(3) 治理:递归不大于基准元素的子序列,然后再递归大于基准元素的子序列,这样不大于基准元素的子序列和大于基准元素的子序列都有序了。基准元素位于正确的位置,整个序列就都有序了,完成了排序的目的。边界条件为子序列且为空或只有1个元素。
02
算法设计
将待排序的n个元素放到列表lis中,用left和right记录子问题在lis中的位置及规模,基准元素记为pivot。首先定义一个partition()函数完成分解任务,然后采用递归方法完成子问题的排序。
在划分过程中,选取待排序元素的第一个元素作为基准元素,然后从左向右、从右向左两个方向轮流找出位置不正确的元素,将其交换位置。该过程一直持续到所有元素都比较结束。最后将基准元素放到正确的位置。
划分操作伪码描述如下:
算法:quickSort(lis,left,right)
输入:待排序序列、子问题的边界left和right
输出:有序序列lis
if left < right:
j ← partition1(lis,left,right)
quickSort(arr, left, j-1)
quickSort(arr, j+1, right)
03
实例构造
给定序列23,15,10,50,93,12,2,68,采用快速排序方法将其升序排列。
(1) 初始序列,如图3-31所示,23为基准元素,i=0,j=8。
■ 图3-31划分初始状态
(2) 从左向右扫描元素:先推动i指针,后比较,若i指向的元素小于或等于基准元素,则继续推动指针、再比较,直到i指向的元素比基准元素大为止,此时i指向的元素位置不正确,应该在右子序列中,所以应该调走,如图3-32所示。
■ 图3-32i指针停止状态
(3) 从右向左扫描元素:先推动j指针,后比较,若j指向的元素大于基准元素,则继续推动指针、比较,直到j指向的元素比基准元素小或相等为止,此时j指向的元素位置不正确,应该在左子序列中,所以应该调走,如图3-33所示。
■ 图3-33j指针停止状态
(4) 交换i指向的元素和j指向的元素,如图3-34所示。
■ 图3-34元素交换后的状态
(5) 由于i<j,所以继续循环,推动i指针,直到i指向的元素大于基准元素;推动j指针,直到j指向的元素小于或等于基准元素,如图3-35所示。
■ 图3-35i指针和j指针第二次扫描停止的状态
(6) 此时i>j,跳出while(True)循环,将基准元素与j指向的元素交换位置,则j便是基准元素的位置,如图3-36所示。
■ 图3-36基准元素放到正确位置的状态
(7) 递归处理左子序列12,15,10,递归处理右子序列93,50,62,68。递归结束的时候,左右子序列均有序了,整个序列也都有序了,如图3-37所示。
■ 图3-37左右子问题递归结束的状态
实例讲解
算法设计与分析(Python版)
精彩回顾
秒懂算法
下期预告
秒懂算法
动态规划算法的基本思想
矩阵连乘问题
0-1背包问题的动态规划改进算法——跳跃点算法
子集树模型——0-1背包问题的回溯算法
满m叉树模型——图的m可着色问题的回溯算法
排列树模型——旅行商问题的分支限界法
最大网络流的增广路算法
蒙特卡罗算法
02
参考书籍
《算法设计与分析》
ISBN:9787302570721
定价:59.90元
03
精彩推荐