数据结构 -- 递归

递归的三大要素

1.明确这个函数想要干什么

例如,我定义了一个函数,想要算n的阶乘:

// 算 n 的阶乘(假设n不为0)
def f(n):
	return None 

第二要素:寻找递归结束条件

所谓递归,就是会在函数内部代码中,调用这个函数本身,所以,我们必须要找出递归的结束条件,不然的话,会一直调用自己,进入无底洞。也就是说,我们需要找出当参数为啥时,递归结束,之后直接把结果返回,请注意,这个时候我们必须能根据这个参数的值,能够直接知道函数的结果是什么。

上面那个例子,当 n = 1,2时,那你应该能够直接知道 f(n) 是啥吧?此时,f(1) = 1,f(2) = 2。完善我们函数内部的代码,把第二要素加进代码里面,如下:

#当n为1或者2时,返回的是自己,也意味着函数终止
def f(n):
	if(n<=2):return n

第三要素:找出函数的等价关系式

第三要素就是,我们要不断缩小参数的范围,缩小之后,我们可以通过一些辅助的变量或者操作,使原函数的结果不变。
说白了,就是要找到原函数的一个等价关系式,f(n) 的等价关系式为 n * f(n-1),即f(n) = n * f(n-1)
找出了这个等价,继续完善我们的代码,我们把这个等价式写进函数里。如下:

def f(n):
    if(n<=2):return n
    else:
        return n*f(n-1)

常见递归(使用以上思路):

案例1:斐波那契数列
斐波那契数列的是这样一个数列:1、1、2、3、5、8、13、21、34….,即第一项 f(1) = 1,第二项 f(2) = 1……,第 n 项目为 f(n) = f(n-1) + f(n-2)。求第 n 项的值是多少。

1、第一递归函数功能
假设 f(n) 的功能是求第 n 项的值,代码如下:

#定义函数为实现斐波那契数列
def f(n):
    return None 

2、找出递归结束的条件

显然,当 n = 1 或者 n = 2 ,我们可以轻易着知道结果 f(1) = f(2) = 1。所以递归结束条件可以为 n <= 2。代码如下:

#终止条件
def f(n):
    if (n<=2):return 1

3、找出函数的等价关系式

def f(n):
	#先写递归结束条件
    if (n<=2):return n
    #在写递归的关系条件
    return f(n-1)+f(n-2)

案例2:小青蛙跳台阶

一只青蛙一次可以跳上1级台阶,也可以跳上2级。求该青蛙跳上一个n级的台阶总共有多少种跳法。
思路:
如在三阶台阶的情况:当青蛙第一步跳了一级台阶,那么就只剩下了两级台阶,将问题转化成为两级台阶的跳法,当青蛙第一步跳了两级台阶,那么就只剩下了一级台阶,就将问题转化为了一级台阶的跳法
1阶台阶时,有1种跳法 (1) f(1) = 1
2阶台阶时,有2种跳法 ([2],[1,1]) f(2) = 2
3阶台阶时,有3种跳法([2,1],[1,2],[1,1,1])f(3) = f(2) + f(1)
4阶台阶时,有5种跳法 …f(4) = f(3) + f(2)

n阶台阶时,有 f(n) = f(n-2) + f(n-1) 种跳法

代码实现:

def f(n):
    #1.先确定终止条件:f(0) = 0,f(1) = 1,等价于 n<=2时,f(n) = n。
    if(n<=2):return n
    #n情况的关系
    return f(n-1)+f(n-2)

案例3:反转单链表。

反转单链表。例如链表为:1->2->3->4。反转后为 4->3->2->1

链表的节点定义如下:

#定义链表
class ListNode: 
    def __init__(self,x):
        self.val = x
        self.next = None

#创建[0->1->2->3->4]的链表
def create(arr):
    pre = ListNode(0)
    # pre是固定的开头,tmp为指针
    tmp = pre
    for i in arr:
        print(i)
        tmp.next = ListNode(i)
        tmp = tmp.next
    return pre.next

#输出链表
def print_ll(head):
    tmp = head
    while tmp:
        print(tmp.val)
        tmp=tmp.next
     
def reverse_linkedlist(head):
	#寻找结束条件
    if head is None or head.next is None:
        return head
    #寻找等价关系
    else:
        newhead=reverse_linkedlist4(head.next)
        head.next.next=head
        head.next=None
    return newhead
 
a = create_ll(range(5))
a = reverse_linkedlist(a)
print_ll(a)

#---> 4 3 2 1 0

思路:
把 2->3->4 递归成 4->3->2。不过,1 这个节点我们并没有去碰它,所以 1 的 next 节点仍然是连接这 2。接下来只需要把节点 2 的 next 指向 1,然后把 1 的 next 指向 null。

发布了44 篇原创文章 · 获赞 3 · 访问量 2388

猜你喜欢

转载自blog.csdn.net/xfxlesson/article/details/104632965