图解算法(四)

快速排序

1.分而治之

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

D&G,通过三个实例来介绍。

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

你要将这块地均匀分成方块,且分出的方块要尽可能的大。

如何将一块地均匀分成方块,并确保分出的方块是最大的呢?使用D&C策略。D&C算法是递归的。使用D&C解决问题的过程包括两个步骤。

(1)找出基线条件,这种条件必须尽可能简单

(2)不断将问题分解,直到符合基线条件。

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

如果一边长25m,另一边长50m,那么可使用25x25.

然后,找出递归条件,这就用到D&C,根据D&C的定义,每次递归调用都必须缩小问题的规模。如何缩小问题的规模呢?我们首先找出这块地的可容纳的最大方块。

根据欧几里得算法可证——适用于小地块的最大方块,也适用于整块地的最大方块。

所以我们只需要不停地分割最小的方块,直到余下的土地满足基线条件。

再看一个例子,给定一个数字数组[2,4,6]。

你需要建这些数字相加,并返回结果。使用循环很容易完成这种任务。

def sum(arr):
   total = 0
   for x in arr:
      total +=x
   return total

print sum([1,2,3,4])

但是如何使用递归函数完成这种任务呢?

第一步,找出基线条件。最简单的数组就是只包含一个元素或者不包含

第二步,每次递归调用都必须离空数组更近一步。

def sum(arr):
  if arr == []:
    return 0
  else:
    return arr[0]+sum(arr[1::])

print sum([1,2,3,4])

 2.快速排序

 快速排序是一种常用的排序算法,比选择排序快得多。

下面使用快速排序对数组进行排序。对排序算法来说,最简单的数组是什么样的呢?就是不需要排序的数组——空数组或只有一个元素的数组。

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

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

对于包含多个元素的数组,要使用D&C,需要将数组进行分解,直到满足基线条件。

首先,从数组中选取一个元素,这个元素被称为基准值。(稍后说明如何选取合适的基准值,暂定第一个元素)

接下来,找出比基准值小的元素以及比基准值大的元素,这被称为分区。现在我们拥有:

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

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

如何对子数组进行排序呢?只需要对这两个子数组在进行快速排序,再合并结果,就能得到一个有序的数组。

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

 

posted @ 2019-05-05 10:43  听风的dog  阅读(338)  评论(0编辑  收藏  举报