递归原理
递归是一种解决问题的有效方法,在递归过程中,函数将自身作为子例程调用
当函数作为自身的子例程调用自身时,原问题被拆分成更小的子问题。这样持续的拆分,直到子问题无法进一步拆分时,递归就到了可以解决的地步。
那么分析上面这段话,为了确保递归函数不会无限循环,我们应该确保以下两点:
①一个最小子问题的情况,也称为基本案例(base case)——能够 直接获得该问题的答案而不需要继续拆分。
②一组规则,也成为递推关系,通过该递推关系将原问题拆分为子问题,直到拆分最小子问题的情况。
举栗
给定字符串S,以相反的顺序打印出该字符串
分析:这个问题可以通过逆序遍历直接解决,十分简单,但是如何通过递归来解决它呢?
实现给定一个字符串S,我们将所需的函数定义为print_reverse(S[0-n-1]),那么一开始我们需要将子问题这样拆分:
①调用print_revese,打印出S[1-n-1]的逆序。
②打印出S[0]
这样就实现了逆序数的输出。
那么我们得到了递推关系,进一步来讲,什么时候是最小子问题的情况呢?即无子串为空的情况。
那么代码如下:
下面给一个例题,可以自己练习:
AC代码:
递归函数
对于很多初学者而言,概念也理解了,但是一遇到问题就不知道怎么去想了。主要的困难在于不知道该怎么划分子问题。下面详细讲一下。
一个问题,如果存在递归解决方案,我们可以通过以下的步骤来实施。
我们将问题定义为待实现的函数,其中X是函数的输入,也定义了函数的范围。
那么之后,在函数F(X)中,我们将会。
1.将问题分解为较小的范围
2.调用函数递归地解决X的子问题
3.最后,处理调用递归函数得到的结果来解决X的问题。
举栗
给定链表,交换每两个相邻节点并返回其头节点。例如,对于列表 1-> 2 -> 3 -> 4,我们应当返回新列表 2 -> 1 -> 4 -> 3 的头节点。
我们可以定义swap(head)来实现,其中head指向链表的头结点,函数返回链表中两个相邻结点交换后得到的头结点head.
那么按照上一块列出的步骤,我们应当这么做:
1.首先交换列表的前两个结点即head,head->next
2.然后我们调用swap(head->next->next),交换两个节点之后列表的其他节点。
3.最后我们将swap(head->next->next)返回的子列表头与原来的两个结点相连,形成新的链表,返回链表头。
自己尝试做一下吧: