Python-递归

目录

 

1.基本概念

2.案例说明


1.基本概念

"""
递归:递“去”,回“归”!

递推:像上边递归实现所拆解,递归每一次都是基于上一次进行下一次的执行,这叫递推

回溯:则是在遇到终止条件,则从最后往回返一级一级的把值返回来,这叫回溯

注意:
1.首先,递归会执行“去”的过程,只需要满足终止条件,就会一直在函数内,带着更新的参数,调用函数自身
2.此时 随着函数每调用一次自身,还没有触发 返回值和到达终止条件,等同于在原来的基础上不断“向下/向内”开辟新的内存空间,所以, 每次调用一次函数,就不是处在同一空间
3.一个普通函数从执行到结束,就是一个开辟空间和释放空间的过程;而递归函数是在调用最外层函数时,先开辟一个最外层空间,每调用一次自身,就会在最外层空间内,再自己开辟本次的空间(所以递归耗内存)
4.return 是返回到函数调用者,递归函数和普通函数也是一样的,所以递归最后一层空间走到尽头(一是:指向完毕,二是:遇到return)遇到return,就要开始返回了,返回到它的调用者(即是阻塞的位置),直到回到最外层空间
"""

2.案例说明

# 排序-快速排序(递归)
def quick_sort_arithmetic(list_tmp):
    """
    注意: 分区虽然没有让整个数组变得有序,但是让基准值找到了自己应该在的位置,多左右两侧重复分                                                
          区动作,每一次分区动作都至少让一个元素找到自己应该在的位置
          1. 在数列之中,选择一个元素作为”基准”(pivot),或者叫比较值。
          2. 数列中所有元素都和这个基准值进行比较,如果比基准值小就移到基准值的左边,如果比基 
             准值大就移到基准值的右边
          3. 以基准值左右两边的子列作为新数列,不断重复第一步和第二步,直到所有子集只剩下一个 
             元素为止。

    例如,假设我现在有一个数列需要使用快排来排序:[39, 33 , 69, 77, 88, 55, 11, 33, 36,39, 
    66, 44, 22],
    快排步骤:
    1. 选取中间的66作为基准值(基准值可以随便选)
    2. 数列从第一个元素11开始和基准值66进行比较,小于基准值,那么将它放入左边的分区中,第二个        
       元素99比基准值66	    大,把它放入右边的分区中。
    3. 然后依次对左右两个分区进行再分区,直到最后只有一个元素
       分解完成再一层一层返回,返回规则是:左边分区+基准值+右边分区

    因为每次将序列切分为2部分,如果切割了n次把元素切割完,序列的长度为m,则2n=m,所以切割的时 
    间复杂度为log(n),在每次切割的时候都会比较所有的元素,需要n次,所以整体的时间复杂度为 
    O(nlog(n))。在比较的过程中元素的位置可能挪动,所以快速排序是不稳定的排序。
    
    """
    if len(list_tmp) < 2:
        return list_tmp
    # 选取基准
    mid_pivot = list_tmp[len(list_tmp) // 2]  # ’//‘ 取整
    # 定义基准值左右两个数列
    left_list, right_list = [], []
    # 从原始数组中移除基准值
    list_tmp.remove(mid_pivot)
    for item in list_tmp:
        # 大于基准值放在右边
        if item > mid_pivot:
            right_list.append(item)
        else:
            # 小于基准值放在左边
            left_list.append(item)
    # 使用迭代进行比较, 递归调用,排列左边和右边的序列
    return quick_sort_arithmetic(left_list) + [mid_pivot] + quick_sort_arithmetic(right_list)

二分查找
"""
1. 二分查找又称折半查找,优点是比较次数少,查找速度快,平均性能好;其缺点是要求待查表为有序表,且插入删除困难。
2. 二分查找的主要思想是:充分利用数组nums已经排好序的特点,我们取数组nums的中间位置(mid)的元素n_1,用n_1与目标数字x进行比较,如果n_1 等于x,那么直接返回n_1的位置mid;如果n_1大于x,则说明x如果在数组中的话,一定是在n_1的左侧;如果n_1小于x,则说明x如果在数组中的话,一定是在n_1的右侧。
3. 二分查找: (1)预处理 —— 如果集合未排序,则进行排序。
                    (2)二分查找 —— 使用循环或递归在每次比较后将查找空间划分为两半。
                    (3)后处理 —— 在剩余空间中确定可行的候选者。
""" 

# 二分查找-一般方法
def binary_search(list_tmp, target):
    """
    一般方法实现二分查找
    二分查找的最基础和最基本的形式。
    初始条件:left = 0, right = length-1
    终止:left > right
    向左查找:right = mid-1
    向右查找:left = mid+1
    :param list_tmp:待查找列表
    :param target:待查找目标元素
    :return:找到返回索引,否则,返回-1
    """
    # 1. 列表排序
    list_tmp_sort = quick_sort_arithmetic(list_tmp)
    # 2. 二分查找
    if len(list_tmp) == 0:
        return -1
    left_num = 0
    right_num = len(list_tmp_sort)
    while left_num <= right_num:
        mid_num = (left_num + right_num) // 2
        if list_tmp_sort[mid_num] == target:
            return mid_num
        elif list_tmp_sort[mid_num] > target: # 向左查找
            right_num = mid_num - 1
        else:
            left_num = mid_num + 1
        # 终止:left > right
    return -1
# 二分查找-递归
def binary_search_recursive(list_tmp, target_num, left, right):
    """
    通过递归实现二分查找,如果找到了要求的数,返回它的索引
    :param list_tmp:待查找列表
    :param target_num:待查找元素
    :param left:查找下限,一般为0
    :param right:查找上限,一般为len(list_tmp) - 1
    :return:存在返回查询到的数的索引,不存在返回-1
    """
    # 1. 列表排序
    list_tmp_sort = quick_sort_arithmetic(list_tmp)
    # 2. 二分查找
    if left <= right:  # 边界
        mid = (left + right) // 2  # 折中取整
        if target_num > list_tmp_sort[mid]: # 向右查找
            left = mid + 1
            return binary_search_recursive(list_tmp_sort, target_num, left, right)  # 每一层都要返回给上一层的调用者
        elif target_num < list_tmp_sort[mid]:
            right = mid - 1
            return binary_search_recursive(list_tmp_sort, target_num, left, right)
        elif target_num == list_tmp_sort[mid]:
            return mid  # 多层函数只会将返回值返回给上一层的调用者
    else:
        return -1
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值