龙空技术网

算法|简单易懂图解使用递归的分治法快速排序

小智雅汇 385

前言:

现在朋友们对“重复排列递归算法有哪些优点和缺点”大约比较注意,咱们都需要剖析一些“重复排列递归算法有哪些优点和缺点”的相关资讯。那么小编同时在网摘上网罗了一些有关“重复排列递归算法有哪些优点和缺点””的相关资讯,希望大家能喜欢,咱们一起来了解一下吧!

分而治之(divide and conquer,D&C)——一种著名的递归式问题解决方法。

D&C算法是递归的。使用D&C解决问题的过程包括两个步骤。

(1) 找出基线条件,这种条件必须尽可能简单。(2) 不断将问题分解(或者说缩小规模),直到符合基线条件。
问题1

假设你有一块1680*640m的土地。你要将这块地均匀地分成方块,且分出的方块要尽可能大,应该怎样分?

你可以从这块地中划出两个640 m×640 m的方块,同时余下一小块地。

也就是:

现在是顿悟时刻:何不对余下的那一小块地使用相同的算法呢?最初要划分的土地尺寸为1680 m×640 m,而现在要划分的土地更小,为640 m×400 m。适用于这小块地的最大方块,也是适用于整块地的最大方块。换言之,你将均匀划分1680 m×640 m土地的问题,简化成了均匀划分640 m×400 m土地的问题!

下面再次使用同样的算法。对于640 m × 400 m的土地,可从中划出的最大方块为400 m × 400 m。这将余下一块更小的土地,其尺寸为400 m × 240 m。

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

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

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

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

以上就是递归的分治法解决问题的思路。

问题2

再来看一个例子,数字数组各元素求和。如,数字数组[2,4,6]的求和。用一个循环很容易解决问题,但这里要用递归的分治法。

第一步:找出基线条件。最简单的数组什么样呢?如果数组不包含任何元素或只包含一个元素,计算总和将非常容易。因此这就是基线条件。

第二步:每次递归调用都必须离空数组更近一步。如何缩小问题的规模呢?下面是一种办法。

这与下面的版本等效。

这两个版本的结果都为12,但在第二个版本中,给函数sum传递的数组更短。换言之,这缩小了问题的规模!

函数sum的工作原理类似于下面这样。

这个函数的运行过程如下。

别忘了,递归记录了状态。

3 快速排序

对排序算法来说,最简单的数组什么样呢?就是根本不需要排序的数组。

因此,基线条件为数组为空或只包含一个元素。在这种情况下,只需原样返回数组——根本就不用排序。

def quicksort(array): if len(array) < 2: return array

我们来看看更长的数组。对包含两个元素的数组进行排序也很容易。

包含三个元素的数组呢?

别忘了,你要使用D&C,因此需要将数组分解,直到满足基线条件。下面介绍快速排序的工作原理。

首先,从数组中选择一个元素,这个元素被称为基准值(pivot)。我们暂时将数组的第一个元素用作基准值。

接下来,找出比基准值小的元素以及比基准值大的元素。

这被称为分区(partitioning)。现在你有:

I 一个由所有小于基准值的数字组成的子数组;

II 基准值;

III 一个由所有大于基准值的数组组成的子数组。

这里只是进行了分区,得到的两个子数组是无序的。但如果这两个数组是有序的,对整个数组进行排序将非常容易。

如果子数组是有序的,就可以像下面这样合并得到一个有序的数组:左边的数组 + 基准值 +右边的数组。在这里,就是[10, 15] + [33] + [],结果为有序数组[10, 15, 33]。

如何对子数组进行排序呢?对于包含两个元素的数组(左边的子数组)以及空数组(右边的子数组),快速排序知道如何将它们排序,因此只要对这两个子数组进行快速排序,再合并结果,就能得到一个有序数组!

quicksort([15, 10]) + [33] + quicksort([])> [10, 15, 33]

不管将哪个元素用作基准值,这都管用。假设你将15用作基准值。

这个子数组都只有一个元素,而你知道如何对这些数组进行排序。现在你就知道如何对包含三个元素的数组进行排序了,步骤如下。

(1) 选择基准值。

(2) 将数组分成两个子数组:小于基准值的元素和大于基准值的元素。

(3) 对这两个子数组进行快速排序。

包含四个元素的数组呢?

假设你也将33用作基准值。

左边的子数组包含三个元素,而你知道如何对包含三个元素的数组进行排序:对其递归地调用快速排序。

因此你能够对包含四个元素的数组进行排序。如果能够对包含四个元素的数组进行排序,就能对包含五个元素的数组进行排序。

根据选择的基准值,对这个数组进行分区的各种可能方式如下。

将任何元素用作基准值都可行,因此你能够对包含五个元素的数组进行排序。同理,你能够对包含六个元素的数组进行排序,以此类推。

下面是快速排序的代码:

附代码:

def quicksort(array):....if len(array) < 2:........return array....else:........pivot = array[0]........less = [i for i in array[1:] if i <= pivot]........greater = [i for i in array[1:] if i > pivot]....return quicksort(less) + [pivot] + quicksort(greater)print(quicksort([10, 5, 2, 3]))

参考: Aditya Bhargava巴尔加瓦著(袁国忠译)的《算法图解-像小说一样有趣的算法入门书》

-End-

标签: #重复排列递归算法有哪些优点和缺点 #递归排序算法 #递归算法实现全排列 #整数划分 递归 #数组递归排序