十六、递归函数和简单算法

一 递归函数

概念:直接或者间接调用自己
必须有一个明确的递归结束条件

# 直接调用
def func():
    print('func')
    func()


func()


# 间接调用
def func1():
    print('func1')
    func2()


def func2():
    print('func2')
    func1()


func1()

python在执行中不会一致递归下去,有一个限制值,一旦超过这个值就会报错,在python中,有方法可以查看和修改这个数值。

import sys

res = sys.getrecursionlimit()  # 查看最大递归次数
print(res)  # 1000

sys.setrecursionlimit(2000)  # 修改递归最大次数
res1 = sys.getrecursionlimit()
print(res1)  # 2000

示例:

# 例子
my_list = [1, [2, [3, [4, [5, [6, [7, [8, [9, [10]]]]]]]]]]
# 需求:打印出列表的每个整型


def get_num(my_list):
    for i in my_list:
        if isinstance(i, int):  
            print(i)
        else:
            get_num(i)


get_num(my_list)

二 简单算法

2.1 二分法

需求:如何在一个有序的列表中找到一个值
逻辑思路:取整个列表的中间值,和要找的值进行比较,如果中间值大于要找的值,则舍弃右边的一半,中间值小于要找的值,则舍弃左边的一半,如果相等则找到。
在新的区间重复上述操作,直到越界都没有找到,就是不存在要找的数。

代码实现:

# 题目:有一个有序列表arr,在有序列表中找到target,并返回其索引,找不到返回-1

# 示例
arr = [-2, 4, 6, 9, 13, 45, 77, 99]
target = 45


def dichotomy():
    n = len(arr)
    # 定义一个区间
    left, right = 0, n - 1  # 这是一个左闭右闭区间 也可以写n 只是在判定边界条件和更新左右区间时有所不同
    while left <= right:  # 因为是一个左闭右闭区间 所以左能等于右 一旦左大于右 则越界 循环结束
        mid = left + (right - left) // 2  # 求区间的中间值 防止溢出
        if target > arr[mid]:  # 说明target在mid的右边
            left = mid + 1  # 更新左区间
        elif target < arr[mid]:  # 说明target在mid的左边
            right = mid - 1  # 更新右区间 因为是左闭右闭 所以右区间要-1
        elif target == arr[mid]:
            return mid
        else:
            return -1


res = dichotomy()
print(res)  # 5

2.2 选择排序

需求:对列表排序
逻辑思路:先取列表的第一个元素,依次和后边的元素进行比较,如果后边的元素小于第一个元素值,则两两交换位置,比较完整个列表,则最小的一个排在了最左边。接着排第二个元素,按照同样的方法可以把第二小的排在第二位。一直排到最后一个的前一位,所有的元素有序。

代码实现:

# 对arr进行排序
arr = [3, 6, 1, 8, 9, 33, -1]


def select_sort():
    n = len(arr)  # arr长度
    for i in range(0, n - 1):  # 循环遍历列表中的每一个值
        j = i + 1  # 循环出的下一个值的索引位置
        while j < n:  # 边界条件 j = n时循环结束
            if arr[j] < arr[i]:  # 如果后面的小于前边的
                arr[i], arr[j] = arr[j], arr[i]  # 两两交换位置
            j += 1  # j每次都自增1 直至越界
    return arr


print(select_sort())  # [-1, 1, 3, 6, 8, 9, 33]

2.3 冒泡排序

需求:对列表排序
逻辑思路:两两进行比较,先取第一个和第二个元素,谁大谁在右,在取右边的后下一个比较,谁大谁在右,依次比较到列表的最后一个值,则最大的排到了最右边,再取第一个元素和第二个元素进行比较,谁大谁在右边,取到倒数第二个停止,则第二大的被排到倒数第二位,重复上述操作,直至整个列表有序。

代码实现:

# 对arr进行排序
arr = [3, 6, 1, 8, 9, 33, -1]


def bubble_sort():
    n = len(arr)
    for i in range(0, n - 1):  # 比较次数 一共需要比较n-1次 所以for循环n - 1次结束
        for j in range(0, n - 1 - i):  # 从第一个元素开始往后比较 排好一个比较的数就少一个
            if arr[j] > arr[j + 1]:  # 判断前一个元素是否大于后一个元素
                arr[j], arr[j + 1] = arr[j + 1], arr[j]  # 前大于后则交换位置
    return arr


print(bubble_sort())  # [-1, 1, 3, 6, 8, 9, 33]

2.3 插入排序

需求:对列表排序
思维逻辑:索引0位置默认有序,从1位置开始排序,和左边的数据比较,小就交换位置,则1位置也做到有序,2位置开始排序,和左比较,小就左移,2位置做到有序,重复上述步骤,直至所有数据都有序。

代码实现:

# 对arr进行排序
arr = [3, 6, 1, 8, 9, 33, -1]


def insert_sort():
    n = len(arr)
    for i in range(1, n):  # 索引0默认是有序的 直接从1位置开始排序
        index = i  # 将i位置的数进行排序
        while arr[index] < arr[index - 1] and index > 0:  # i位置的数和前面已经排好的数进行排序
            arr[index], arr[index - 1] = arr[index - 1], arr[index]  # 右边小于左边就交换位置
            index -= 1  # 下标自减1 直至越界

    return arr


print(insert_sort())  # [-1, 1, 3, 6, 8, 9, 33]

练习

1.尝试编写有参函数将多种用户验证方式整合到其中
直接获取用户数据比对
数据来源于列表
数据来源于文件

# 自定义管理员
user_list = ['jasper', '123']
user_dict = {'name': 'tom', 'pwd': '456'}
# 在创建一个user.txt文件 文件里数据为  jack:789
# 直接拿数据比的话名字为lili密码为666才可通过


def outer(condition):
    def login_auth(func_name):
        def inner(*args, **kwargs):
            username = input('username>>>:').strip()
            password = input('password>>>:').strip()
            # 应该根据用户的需求执行不同的代码
            if condition == '直接比':
                if username == 'lili' and password == '666':
                    res = func_name(*args, **kwargs)
                    return res
                else:
                    print('权限不足')
            elif condition == '列表':
                if username == user_list[0] and password == user_list[1]:
                    res = func_name(*args, **kwargs)
                    return res
                else:
                    print('权限不足')
            elif condition == '字典':
                if username == user_dict.get('name') and password == user_dict.get('pwd'):
                    res = func_name(*args, **kwargs)
                    return res
                else:
                    print('权限不足')
            elif condition == '文件':
                with open(r'user.txt', mode='r', encoding='utf8') as f:
                    name, pwd = f.read().split(':')
                    if username == name and password == pwd:
                        res = func_name(*args, **kwargs)
                        return res
                    else:
                        print('权限不足')
            else:
                print('传入的比较方式有误')

        return inner

    return login_auth


@outer('yyy')
def index():
    print('from index')


index()

2.尝试编写递归函数
推导指定某个人的正确年龄 后一个人比前一个小十岁
eg: A B C D E 已知E是18 求A是多少

def get_age(n):
    if n == 1:
        return 18  # 递归函数结束条件 当n==1时返回e的年龄18
    else:
        return get_age(n - 1) + 10


res = get_age(5)
# 运行流程
# n = 5       return get_age(4) + 10         58
# n = 4       return get_age(3) + 10         48   
# n = 3       return get_age(2) + 10         38
# n = 2       return get_age(1) + 10         28
# n = 1       return 18
print(res)  # 58
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值