04_第四章 快速排序(分而治之)

本章内容:

  • 学习分而治之(divide and conquer,D&C    递归式问题解决方案)。分而治之是学习的第一种通用解决方法。
  • 学习快速排序法——一种优雅的排序算法。比第二章介绍的选择排序快的多。使用的是分而治之的策略。

 

目录

分而治之

快速排序

再谈大O表示法


分而治之

分而治之并非可用于解决问题的算法,而是一种解决思路。

使用分而治之策略解决问题的过程包括两个步骤:

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

实例一:

比如编写求解一个数字数组之和的函数

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

第二步,缩小规模。如何将一个数组缩小规模,可以每一次都从数组中提取一个数字,然后将这个数字和剩下的数组进行求和,这样数组的规模便可以缩小。采用递归的手段,因此每一次调用,都会离基线条件更近一步。

def sum(arr):
    if arr == []:
    #基线条件
        return 0
    else:
        number = arr.pop()
        newarr = arr
        return  number+sum(newarr)
print(sum([1,2,3,4]))

提示:编写设计数组的递归函数时候,基线条件通常是数组为空或者只包含一个元素。陷入困境时,请检查基线条件是不是这玩样的。

实例二:

比如有一块土地,你要将这块地均匀分成方块,且分出来的方块尽可能的大

第一步,找到基线条件。最容易的处理情况是,一边的长度是第二条边的整数倍

第二步,缩小规模。比如现在是一大块方地(1680*640)那么可以将其划分为两个(640*640)的正方形以及一个(640*400)的矩形,那么那块(640*400)的便是缩小规模后的土地,依次类推。

(欧几里得算法:适用这小块地的最大方块,也是适用于整块地的最大方块。哈哈哈记住这个便可以了。对于这一个过程最好还是画一下图,对每一步的过程都画一画)

def find_min_squre(a,b):
    #假设现在那块地其中一边长a,另外一边长b
    x = max(a,b)
    y = min(a,b)
    #找出两条边中较长边和短边
    if x == 2*y:
        return y
    #要是符合基线条件那么直接输出最小边,即为可切最大正方形的边长
    else:
        return find_min_squre(x%y,y)
    #这个x%y的意思是求出原来的长方形切去若干个正方形后剩下的长度
print(find_min_squre(1680,640))

输出结果是80



 快速排序

快速排序是一种常用的排序算法,比选择排序快很多。例如,c语言中标准库中的函数qsort实现的就是快速排序。快速排序也是使用的是分而治之的方法。下面使用快速排序对数组进行排序。

基线条件:

    数组为空或者是只包含一个元素。在这种情况下,只需返回原数组——根本不需要排序。

缩小规模:

    需要将数组进行分解,直至达到基线条件。要是有多个元素,首先从数组中选择一个元素,这个元素称之为基准值(pivot)。接下来,找出比这个基准值小的元素以及比这个基准值大的元素,这个被称为分区(pratitioning)。

此时则会有:

  1. 基准值
  2. 一个由所有小于基准值的元素构成的一个子数组
  3. 一个由所有大于基准值的元素构成的一个子数组

这个里面的子数组是无序的。

若是这两个字数组都是有序的,那么是不是

    原来的数组排序 = 其中一个有序的子数组 + 基准值 + 另外一个有序的子数组

其实,很容易就可以想到了,这两个无序的子数组变成有序的子数组也是采用相同的方法,即取出基准值然后分成两个子数组,分而治之。比如找个例子,有个数组 [4,5,2,7,1,3] 要采用这个方法进行排序。

这里用从大到小的方式排列,也就是把大的数组放在左边

  1.   [4,5,2,7,1,3] 
  2.   [5,7] + 4 + [2,1,3]
  3. ( [7] + 5 + [ ] )+ 4 +( [3] + 1 + [1] )
def quicksort(arr):
    if len(arr) < 2:
        return arr
    else:
        pivot = arr[0]
        smaller = [i for i in arr[1:] if i <= pivot]
        bigger = [i for i in arr[1:] if i > pivot]
        return quicksort(smaller) + [pivot] + quicksort(bigger)
print(quicksort([4,5,2,7,1,3]))

输出结果为   [1, 2, 3, 4, 5, 7]

 

 

 

再谈大O表示法

快速排序的独特之处在于选择的基准值,快速排序的平均时间为 O(n*log n)。一般情况下,直接随机取基准值就好。

常见的大O运算时间
算法 二分查找 简单查找 快速排序 选择排序 旅行商问题算法
快 --> 慢 O(log n) O(n) O(n*log n) O(log n*n) O(log n!)

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

你可能感兴趣的:(Python算法)