快速排序

134 阅读4分钟

本章内容

  • 学习分而治之。有时候,你可能会遇到使用任何已知的算法都无法解决的问题。优秀的 算法学家遇到这种问题时,不会就此放弃,而是尝试使用掌握的各种问题解决方法来找 出解决方案。分而治之是你学习的第一种通用的问题解决方法。
  • 学习快速排序——一种常用的优雅的排序算法。快速排序使用分而治之的策略。

前一章深入介绍了递归,本章的重点是使用学到的新技能来解决问题。我们将探索分而治之(divide and conquer,D&C)——一种著名的递归式问题解决方法。

本书将深入算法的核心。只能解决一种问题的算法毕竟用处有限,而D&C提供了解决问题的 思路,是另一个可供你使用的工具。面对新问题时,你不再束手无策,而是自问:“使用分而治 之能解决吗?”

在本章末尾,你将学习第一个重要的D&C算法——快速排序。快速排序是一种排序算法,速 度比第2章介绍的选择排序快得多,实属优雅代码的典范。

4.1 分而治之

D&C并不那么容易掌握,我将通过三个示例来介绍。首先, 介绍一个直观的示例;然后,介绍一个代码示例,它不那么好看, 但可能更容易理解;最后,详细介绍快速排序——一种使用D&C 的排序算法。

假设你是农场主,有一小块土地。

1.png

你要将这块地均匀地分成方块,且分出的方块要尽可能大。显然,下面的分法都不符合要求。

2.png

如何将一块地均匀地分成方块,并确保分出的方块是最大的呢?使用D&C策略!D&C算法 是递归的。使用D&C解决问题的过程包括两个步骤。 (1) 找出基线条件,这种条件必须尽可能简单。

(2) 不断将问题分解(或者说缩小规模),直到符合基线条件。

下面就来使用D&C找出前述问题的解决方案。可你能使用的最大方块有多大呢?

首先,找出基线条件。最容易处理的情况是,一条边的长度是另一条边的整数倍。

3.png

如果一边长25 m,另一边长50 m,那么可使用的最大方块为 25 m×25 m。换言之,可以将 这块地分成两个这样的方块。

现在需要找出递归条件,这正是D&C的用武之地。根据D&C的定义,每次递归调用都必须 缩小问题的规模。如何缩小前述问题的规模呢?我们首先找出这块地可容纳的最大方块。

4.png

你可以从这块地中划出两个640 m×640 m的方块,同时余下一小块地。现在是顿悟时刻:何 不对余下的那一小块地使用相同的算法呢?

5.png

最初要划分的土地尺寸为1680 m×640 m,而现在要划分的土地更小,为640 m×400 m。适 用于这小块地的最大方块,也是适用于整块地的最大方块。换言之,你将均匀划分1680 m×640 m 土地的问题,简化成了均匀划分640 m×400 m土地的问题!

欧几里得算法

前面说“适用于这小块地的最大方块,也是适用于整块地的最大方块”,如果你觉得这一 点不好理解,也不用担心。这确实不好理解,但遗憾的是,要证明这一点,需要的篇幅有点长, 在本书中无法这样做,因此你只能选择相信这种说法是正确的。如果你想搞明白其中的原因, 可参阅欧几里得算法。可汗学院很清楚地阐述了这种算法,网址为www.khanacademy.org/computing/c…

下面再次使用同样的算法。对于640 m × 400 m的土地,可从中划出的最 大方块为400 m × 400 m。

6.png

这将余下一块更小的土地,其尺寸为400 m × 240 m。

7.png

你可从这块土地中划出最大的方块,余下一块更小的土地,其尺寸为240 m × 160 m。

8.png

接下来,从这块土地中划出最大的方块,余下一块更小的土地。

9.png

余下的这块土地满足基线条件,因为160是80的整数倍。将这块土地分成两个方块后,将不 会余下任何土地!

10.png

因此,对于最初的那片土地,适用的最大方块为80 m× 80 m。

11.png