Python 递归、排序和搜索

一、递归

1 生活中的递归

1)我们使用的词典,本身就是递归,为了解释一个词,需要使用更多的词。当你查一个词,发现这个词的解释中某个词仍然不懂,于是你开始查这第二个词,可惜,第二个词里仍然有不懂的词,于是查第三个词,这样查下去,直到有一个词的解释是你完全能看懂的,那么递归走到了尽头,然后你开始后退,逐个明白之前查过的每一个词,最终,你明白了最开始那个词的意思。

2)多年前我五岁的儿子问我「不是每条船都有救生艇的吧?」「怎么会呢?」「也许救生艇上会有一艘更小的救生艇,但是那艘小艇上可能就没有更小的救生艇了。」

3)一个洋葱是一个带着一层洋葱皮的洋葱。

2 递归的原则

  • 递归算法必须有停止条件
  • 递归算法必须改变其状态并向停止条件靠近
  • 递归算法必须递归地调用自己

3 应用场景

3.1 数字累加和

# 3 + 2 + 1
def sum_numbers(num):
    # 1.如果是1,直接返回1 -- 出口
    if num == 1:
        return 1
    # 2.如果不是1,重复执行累加并返回结果
    return num + sum_numbers(num-1)

# 输出结果为6
print(sum_numbers(3))

分析:

 

3.2 n以内的数字阶乘

# 数字阶乘
def Fact(n):
    if n == 1:
        return 1
    return n * Fact(n-1)

3.3 斐波那切数列

# 斐波那契数列
def Fibo(n):
    # 出口
    if n == 1 or n == 2:
        return 1
    else:
        return Fibo(n - 1) + Fibo(n - 2)

分析:

        这样一个数列:1、1、2、3、5、8、13、21、34、……在数学上,斐波那契数列以如下被以递推的方法定义:F(1)=1, F(n)=F(n - 1)+F(n - 2)(n ≥ 2,n ∈ N*)

二、排序

1 快速排序

1.1 规则

  • 从数列中挑出一个基准值。
  • 将所有比基准值小的摆放在基准前面,所有比基准值大的摆在基准的后面(相同的数可以到任一边);在这个分区退出之后,该基准就处于数列的中间位置。
  • 递归地把"基准值前面的子数列""基准值后面的子数列"进行排序。 

1.2 步骤解析

 

1.3 代码实现

# 快速排序
def partition(li,left,right):
    tmp = li[left]
    while left < right:
        while left < right and li[right] >= tmp:  #从右边找比tmp小的数
            right -= 1   #继续从右往左查找
        li[left] = li[right]  #把右边的值写到左边空位上

        while left < right and li[left] <= tmp:
            left += 1
        li[right] = li[left] #把左边的值写到右边空位上

    li[left] = tmp #把tmp归位
    return  left
def quick_sort(li,left,right):
    if left < right : #至少两个元素
        mid = partition(li, left, right)
        quick_sort(li, left, mid-1)
        quick_sort(li, mid+1, right)
li = [5, 7, 4, 6, 3, 1, 2, 9, 8]
quick_sort(li, 0, len(li)-1)
print(li)

1.4 各项指标

        1)快速排序是一个不稳定的排序算法

        2)时间复杂度

                平均:O(nlogn)

                最差:O(n2),退化为冒泡排序

2 归并排序

2.1 概念

        归并排序用的是分治法,把一个大问题化解为k个中问题,每个中问题再化解为k个小问题,直至问题化为最小可解的问题。对这些问题求解,再不断地合并结果,直至合并完毕。

2.2 步骤解析

 

2.3 代码实现

# 归并排序
# 1.将整个数组对半分开,直到只剩一个元素
# 2.从一个元素开始往回进行对比合并,将合并的内容暂且放在一个空列表中
# 定义合并merge函数
def merge(L,R):
    # 将两个排过序的两个列表进行合并并排序
    # 分别用于限定L、R的数据减少情况
    i, j = 0,0
    # 用于存放L与R的合并内容
    res = []
    while i < len(L) and j < len(R):
        # 如果左边的数大于右边的数,就将左边的数先添加到res中,再继续比较(合并的R、L已经排过序)
        # 如果如果右边的数大于左边的数,就将右边的数先添加到res中,再继续比较(合并的R、L已经排过序)
        if L[i] <= R[j]:
            res.append(L[i])
            i += 1
        else:
            res.append(R[j])
            j += 1
    # 因为当 i == len(L) 或者 j == len(R)时,跳出while循环,且每次循环只处理一个列表里的内容,所以其中有一个列表内容会先全部加入res中,另一个列表还剩内容未加进res中。
    # 对未处理完的列表,直接加入res中
    res += R[j:] if i == len(L) else L[i:]
    return res

# 定义排序merge_sort函数
def merge_sort(List):
    length = len(List)
    if length <= 1:
        return List
    else:
        mid = length//2
        left = merge_sort(List[:mid])
        right = merge_sort(List[mid:])
        return merge(left,right)


if __name__ == '__main__':
    List = [9,8,7,5,3,6,11,2,4,1,12]
    print(merge_sort(List))

2.4 各项指标

        不管待排序列表的初始状态如何,都不影响排序的时间复杂度。归并排序一直对待排序列表进行拆分,需要进行logn次拆分,在每一次递归合并中,需要进行n次比较和添加。时间复杂度为 T(n)=nlogn ,再乘每次操作的步骤数(常数,不影响大O记法),所以归并排序的时间复杂度为 O(nlogn) 。

3 冒泡排序

3.1 概念

        冒泡排序(Bubble Sort)也是一种简单直观的排序算法。它重复地走访过要排序的数列,一次比较两个元素,如果他们的顺序错误就把他们交换过来。走访数列的工作是重复地进行直到没有再需要交换,也就是说该数列已经排序完成。

3.2 步骤解析

第一次循环:

第二次循环: 

 

第三次循环: 

 

第四次循环: 

 

 

 3.3 代码实现

# 冒泡排序
def func_sort(n):
    for i in range(n-1): # 控制排序次数
        for j in range(n-1-i): # 控制比较次数
            if L[j]>L[j+1]:
                print('{}比{}大,交换前{}'.format(L[j], L[j + 1], L))
                L[j], L[j + 1] = L[j + 1],L[j]
                print('交换后:{}'.format(L))
            else:
                print("我不用交换{}".format(L))
    print('排序后的列表为:{}'.format(L))
func_sort(len(L))

3.4 各项指标

        时间复杂度是O(n^2),是一种稳定的算法

4 选择排序

4.1 概念

        选择排序(Selection sort)是一种简单直观的排序算法。它的工作原理是每一次从待排序的数据元素中选出最小(或最大)的一个元素,存放在序列的起始位置,所以称为:选择排序

4.2 步骤解析

 

4.3 代码实现

4.4 各项指标

5 插入排序

5.1 概念

        插入排序(Insertion-Sort)的算法描述是一种简单直观的排序算法。它的工作原理是通过构建有序序列,对于未排序数据,在已排序序列中从后向前扫描,找到相应位置并插入。

5.2 步骤解析

5.3 代码实现

# 插入排序
def insertion_sort(sort_list):
    # 注意是从第二个位置开始向前插入元素
    for i in range(1, len(sort_list)):
        # 从第i个元素开始向前比较,如果小于前一个元素,交换位置
        for j in range(i, 0, -1):
            if sort_list[j] < sort_list[j - 1]:
                sort_list[j - 1], sort_list[j] = sort_list[j], sort_list[j - 1]


test_llst = [5, 4, 6, 3, 1, 2]
print(test_llst)
insertion_sort(test_llst)
print(test_llst)

5.4 各项指标

        最优时间复杂度:O(n)
        最坏时间复杂度:O(n2)

三、搜索

1 二分搜索

1.1 概念

        二分搜索是一种在有序数组中查找某一特定元素的搜索算法。搜索过程从数组的中间元素开始,如果中间元素正好是要查找的元素,则搜索过程结束;如果某一特定元素大于或者小于中间元素,则在数组大于或小于中间元素的那一半中查找,而且跟开始一样从中间元素开始比较。如果在某一步骤数组为空,则代表找不到。这种搜索算法每一次比较都使搜索范围缩小一半。

1.2 步骤解析

 1.3 代码实现

# 二分查找
lss = [12, 27, 29, 32, 35, 54, 60, 70, 71, 91]
def b_search(ls, target):
    def bin_search(ls, target, l, r):
        if l > r:
            return -1
        mid = int(l + (r - l) / 2)
        if ls[mid] == target:
            return mid
        elif ls[mid] < target:
            return bin_search(ls, target, mid + 1, r)
        else:
            return bin_search(ls, target, l, mid - 1)
    return bin_search(ls, target, 0, len(ls)-1)
print(b_search(lss, 70))
print(b_search(lss, 222))

1.4 各项指标

        二分查找的时间复杂度为O(log2n)

四、参考

1.Python实现快速排序_想成大神的大艳的博客-CSDN博客_快速排序python

2.归并排序(Python代码)_莱维贝贝、的博客-CSDN博客_python 归并排序 

3.Python二分搜索算法___Miracle__的博客-CSDN博客_python二分查找算法 

4.Python实现冒泡排序详解_芃小黄的博客-CSDN博客_python冒泡排序流程图 

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值