递归函数

1、什么是递归?

从前有座山,山里有座庙,庙里有个老和尚,正在给小和尚讲故事呢!故事是什么呢?「从前有座山,山里有座庙,庙里有个老和尚,正在给小和尚讲故事呢!故事是什么呢?『从前有座山,山里有座庙,庙里有个老和尚,正在给小和尚讲故事呢!故事是什么呢?……』」

2、函数的嵌套调用

函数内部是可以调用其他函数的,这种调用就叫函数的嵌套调用。

而递归就是函数在其内部直接或间接调用自己。

3、Python中使用递归的注意事项

  1. 必须有明确的退出条件

  2. 每次进入更深一层递归时,问题规模比上次递归都应有所减少

  3. 递归效率不高,递归层数过多会导致栈溢出

  在计算机中,函数调用是通过栈(stack)这种数据结构实现的。每当进入一个函数调用,栈就会加一层栈帧,每当函数返回,栈就会减一层栈帧。由于栈的大小不是无限的,所以,递归调用的次数过多,就会导致栈溢出。)

  查看Python中递归限制:

>>> import sys
>>> sys.getrecursionlimit()
1000

4、常见应用

  4.1 剥皮

def f(x):
    ret = []
    for b in x:
        if isinstance(b, list):
            for a in f(b):
                ret.append(a)
        else:
            ret.append(b)
    return ret

list2 = [11, 22, [33, 44], [55, [66, 77]], [88, [99, [100, [200, [300]]]]]]
ret = f(list2)
print(ret)     #[11, 22, 33, 44, 55, 66, 77, 88, 99, 100, 200, 300]

  4.2 二分法

# 二分查找算法:必须处理有序的列表

################# 二分法基础版
l = [2,3,5,6,8,9,15,18,23,26,33,35,38,59,67,89,90,99]
def find(l,aim):
    mid_index = int(len(l) // 2)
    if l:
        if l[mid_index] < aim:
            new_l = l[mid_index+1 :]
            find(new_l,aim)
        elif l[mid_index] > aim:
            new_l = l[:mid_index]
            find(new_l, aim)
        else:
            print('找到了',mid_index,l[mid_index])
    else:
        print('找不到')
find(l,36)  # 找不到
find(l,18)  # 找到了 2 18     此处的mid_index不对

----------------------------------------------------------------------------------------

################ 二分法升级版
def find(l,aim,start = 0,end = None):
    end = len(l) if end is None else end  #参数end问题
    mid_index = (end - start)// 2 + start  # 计算中间值
    if start <= end:               # 针对找不到的值
        if l[mid_index] < aim:
            return find(l,aim,start=mid_index+1,end=end)
        elif l[mid_index] > aim:
            return find(l, aim, start=start, end=mid_index-1)
        else:
            return mid_index
    else:
        return '找不到该值'

l = [2,3,5,6,8,9,15,18,23,26,33,35,38,59,67,89,90,99]
ret = find(l,18)
print('要找的值对应的下标是:',ret)     # 要找的值对应的下标是: 7

  4.3 递归函数实现三级菜单

menu = {
    '北京':{'海淀':{'五道口':{'soho':{},'网易':{},'google':{}},
                   '中关村':{'爱奇艺':{},'汽车之家':'','youku':{}},
                   '上地':{'百度':{}}
                  },
           '昌平':{'沙河':{'老男孩':'','北航':{}},
                   '天通苑':{},
                   '回龙观':{}
                  },
           '朝阳':{},
           '东城':{}
          },
    '上海':{'闵行':{'人民广场':{'炸鸡店':{}}
                  },
            '闸北':{'火车站':{'携程':{}}
                  },
            '浦东':{}
          },
    '山东':{}
}

l = [menu]
# print(l[-1])    #l[-1]其实就是字典menu
while l:
    for key in l[-1]:   # l[-1]:列表最后一个元素,也就是最新的(可能是新添加的)
        print(key)
    k = input('input>>>').strip()

    if k in l[-1].keys() and l[-1][k]:
        l.append(l[-1][k])
    elif k == 'b':
        l.pop()        #pop() 函数用于移除列表中的一个元素(默认最后一个元素),并且返回该元素的值。
    elif k == 'q':
        break
    elif k not in l[-1].keys():
        print('该地点没找到,请重新从下边列表中选择:')
        print('-' * 20)
    elif not (l[-1][k]):
        print('该地点下辖是空值,请重新从下边列表中选择:')
        print('-'*20)

# 函数实现
    # def threeLM(dic):
    #     while 1:
    #         for k in dic:
    #             print(k)
    #         # print(dic.keys())   #dict_keys(['北京', '上海', '山东'])
    #         key = input('imput>>>').strip()
    #         # print(dic[key])   #{'海淀': {'五道口': {'soho': {}, '网易': {}, 'google': {}}, '中关村': {'爱奇艺': {}, '汽车之家': '', 'youku': {}}, '上地': {'百度': {}}}, '昌平': {'沙河': {'老男孩': '', '北航': {}}, '天通苑': {}, '回龙观': {}}, '朝阳': {}, '东城': {}}
    #         if key == 'b' or key == 'q':
    #             return key
    #         elif key in dic.keys() and dic[key]:
    #             ret = threeLM(dic[key])
    #             if ret == 'q':
    #                 return 'q'
    #         elif (not dic.get(key)) or (not dic[key]):
    #             continue
    #
    # threeLM(menu)

#运行结果:

北京
上海
山东
input>>>北京
海淀
昌平
朝阳
东城
input>>>昌平
沙河
天通苑
回龙观
input>>>回龙观
该地点下辖是空值,请重新从下边列表中选择:
------------------------------
沙河
天通苑
回龙观
input>>>沙河
老男孩
北航
input>>>老男孩
该地点下辖是空值,请重新从下边列表中选择:
------------------------------
老男孩
北航
input>>>b
沙河
天通苑
回龙观
input>>>b
海淀
昌平
朝阳
东城
input>>>b
北京
上海
山东

 

posted @ 2019-04-10 17:12  timetellu  阅读(299)  评论(0编辑  收藏  举报