递归:
- 特点:
当一个复杂的问题可以分解为几个(最简单的就是一个)相对简单的且与原来问题解法相同或者类似的子问题来求解,便称为递归求解。
:
递归工作栈与递归过程:
- 在高级语言中,调用函数与被调用函数之间的链接及信息交换需要通过栈来进行。
- 字数太多,我们直接上图:
递归算法的效率分析:
- 时间复杂度: 大致为O(2^n) (斐波那契以及汉诺塔问题)
- 空间复杂度: O(f(n)) ,f(n) 为递归工作栈中记录的个数与问题规模n的函数关系。
分治法:
- 一种分解-求解的策略,叫做分治法,用来求解递归问题。
分治法满足的三个条件:
(1)能将一个问题转变为一个新的问题,而新的问题与原来的问题解法相同或类同,不同的仅是处理对象(重点),并且这个对象更小,且变化更有规律。 (下面列表反转递归,第二种方法操作的都是同一个列表对象,每次递归操作不同元素)
(2) 可以通过上述转化使问题简化。
(3) 必须有一个明确的递归出口,或称为递归的边界(重点)。
- 演示:
void p(参数列表)
{
if(递归结束条件成立) 可直接求解; // 递归终止条件
else p(娇小的参数); // 递归步骤
}
数据结构是递归的(很多可以递归处理)
- 例如链表, 树形结构等
上解答问题代码:
a = [1, 2, 3, 4, 5, 6, 7, 8]
def rev_list(l):
if len(l) == 1:
return l
elif len(l) == 2: # 可以省略这一步
l[0], l[-1] = l[-1], l[0]
return l
else:
return [l[-1]] + rev_list(l[:-1]) # -1 才算是取最后一位之前的所有
# print(rev_list(a))
# 上述方法会不断的进行 l[:-1] 和 [l[-1]] 的操作,不断地进行浅拷贝效率太低,并且并未改变a,而是返回新的列表
# 从快速排序方法中找到的灵感,我们采用双指针针解决这个问题
def reverse(l, low, height):
""" 用来实现第一个元素 和列表最后一个元素交换位置 """
pivotkey = l[low]
l[low] = l[height] # python里面其实可以一条语句解决 l[low], l[height] = l[height], l[low]
l[height] = pivotkey
low +=1
height -= 1
return low, height
def reverse_di(l, low, height):
""" 实现递归 """
if low <= height:
low, height = reverse(l, low, height) # 完成一次最前面和最后面位置值的交换
reverse_di(l, low, height)
def re_reverse(l):
reverse_di(l, 0, len(l)-1)
re_reverse(a)
print(a)
"""
基本的思想就是,交换第一个和最后一个位置的元素,完全可以把递归改成一般的 while 循环语句。
递归的写法,内部会使用隐藏的栈保存调用函数,过多的占用空间,函数间调用也会损耗性能,
不过递归算法更显而已懂,易于阅读。
"""
- 不在列出 递归的快速排序。