recursion
recursion
(受归并排序
与树遍历
的启发)
归并排序的代码见归并排序
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/*求长子兄弟树的高度的算法*/
int Height(EBNode * t) // 求 t 的高度
{
if (t == NULL) return 0; // 空树的高度为 0
int maxsh = 0;
EBNode * p = t -> eson; // p 指向 t 结点的长子
while (p != NULL)
{
EBNode * q = p -> brother; // q 临时保存结点 p 的兄弟结点
int sh = Height(p); // 递归求结点 p 的子树的高度
maxsh = max(maxsh, sh); // 求结点 t 的所有子树的最大高度
p = q;
}
return maxsh + 1;
}
(1) 明确递归终止条件
” 切记写递归算法必须写终止条件,否则便是无限循环!”
- 归并排序算法中有一行很容易忽略的语句:
1
2
// 这一句必须加上!!因为当递推到只有一个结点的时候,这句话就是终止条件!
if (!head || !head->next) return head;
乍一看以为只是一句异常处理,其实是终止条件!因为当递推到只有一个结点的时候,就不需要也不能够再一分为二、对左右递归排序了,这就是我们的终止情况。
如果不写这一句,那么会导致无限循环!
- 在求树的高度的算法中:
1
2
EBNode * p = t -> eson; // p 指向 t 结点的长子
while (p != NULL)
若当前结点为叶子结点,则p=NULL,直接跳过循环,执行return maxsh+1
。
(2)总是被递归绕晕怎么办?
不要试图模拟递归,人脑是模拟不过来的。要给予我们的算法充分的信心,相信它能自己处理好。
- 首先,只模拟一下第一层递归的过程,浅尝辄止
以文首的Height(p)
算法为例,首先模拟一下:
- 对于一个根结点t,直接下到其长子结点p(因为根节点没有兄弟),然后对p调用
Height(p)
求出以p为根结点的子树的高度 ; - 然后,置
maxsh=Height(p)
; - 接着令
p=p->brother
,遍历p的所有兄弟结点,并依次对它们使用Height(p)
,如果有Height(p)
大于当下的maxsh
,就更新maxsh=Height(p)
; - 至于这些
Height(p)
到底是怎么实现的,我们并不关心; - 如此,我们就得到了以这个t为根节点的子树的高度
- 然后,我们模拟一下终止条件
- 当p指向了一个叶子结点的时候,
p=t->eson
,故而p=NULL
,所以直接跳过循环; - 那么,我们现在能够做的,只有将maxsh
+1
,表示高度因为这个叶子结点的存在又多了一层; - 那么,这个
maxsh+1
的操作是否对各层次的递推都有效呢?由于每次递推到新的一个子结点,就说明高度又多了一层,所以在循环外部添加一句return maxsh+1;
,就能使得在Height()
的每一次递推中,都使maxsh+1,显然是合理的;
此外,要明晰的是,“递”和“推”的代码是两部分:
“[递]”的代码要放在[while循环里],因为要逐层递推知道不符合while条件;
而“[归]”,即在回归的过程中解决问题的代码,是放在[while循环外面]的;
(因为是在 每次从下一层跳回上一层的时候 执行解决问题的代码)
(3)递归是在“归”的过程中解决问题的
比如Height算法,就是在 从叶子结点逐层回归到根节点的过程中 ,每次都令高度+1,最后得到总高度的。
![[991dbb82935a3d3f4e94b728730adfe.jpg]]
补充:可以看看这个链接:怎么理解递归
This post is licensed under CC BY 4.0 by the author.