我理解简单的递归代码,但有时候它会变得有点复杂。我迷路了,不能真正遵循代码。 例如以下代码(匿名写的):
void reversetree(struct node* head)
{
//first check for the exception whether does it even exit or not
if(head==NULL)
return ;
reversetree(head->left); //reverse call for left child
reversetree(head->right); //same reverse call for right child
//now next these steps will swap the children
struct node* temp=head->left;
head->left=head->right;
head->right=head->left;
//now exit the function and you are done :)
}
6
/ \
3 4
/ \ / \
1 2 8 9
让我们说如果二叉树看起来像这样,有人可以为我做一步一步的逻辑吗?根据我的理解,它首先检查根是否存在,如果是,那么它再次调用左子的函数,直到没有剩下的孩子?所以当交换它的代码被调用时?什么时候开始用合适的孩子调用函数?抱歉,我对递归并不是太明亮。
答案 0 :(得分:0)
如果root不存在,则该函数退出,因为它没有子节点。
是的,处理器将跟随左子项链直到它用完,然后是最后一个节点的右子项的左子项...
对于显示的树,以下是将要发生的事情:
Reverse node 6:
Reverse node 3:
Reverse node 1:
Reverse NULL
Reverse NULL
Swap 1's links to NULL and NULL
Reverse node 2:
Reverse NULL
Reverse NULL
Swap 2's links to NULL and NULL
Swap 3's links to 1 and 2
Reverse node 4:
Reverse node 8:
Reverse NULL
Reverse NULL
Swap 8's links to NULL and NULL
Reverse node 9:
Reverse NULL
Reverse NULL
Swap 9's links to NULL and NULL
Swap 4's links to 8 and 9
Swap 6's links to 3 and 4
在每次调用之前测试NULL 会运行得更快。
交换步骤可以在递归调用之前进行,而不会影响速度或结果。
答案 1 :(得分:0)
通常在处理递归时,人们会倾向于用笔和纸来表达。这是一个很好的练习,但我觉得这样做更容易:
第一种看待它的方式
使用递归函数和执行相同作业的其他函数之间存在无差异。他们都做好自己的工作并返回,以便您的代码在下一行恢复。
想象一下,你有一个可以反转整棵树的工作函数reversetree_external
,这样你就可以用这种方式编写你的函数没有递归:
void reversetree(struct node* head)
{
if(head==NULL)
return ;
// switch left and right
struct node* temp=head->left;
head->left=head->right;
head->right=temp; // There was an error here
// Reverse subtrees
reversetree_external(head->left);
reversetree_external(head->right);
}
所以你需要说服自己的一切就是给出一个像:
这样的论点 6
/ \
3 4
/ \ / \
1 2 8 9
在reversetree_external
撤销两个子树之前变成以下:
6
/ \
4 3
/ \ / \
8 9 1 2
如果您只传递right
和left
中的一个,则在使用reversetree_external
之前不会执行任何操作之前会转到该级别。
如果你传递一个叶节点,例如。 8
结果是相同的8
(交换空指针),而reversetree_external
不会做任何事情,因为它会两次都被NULL
。
事实上,您可以看到reversetree
可以与reversetree_external
做同样的事情,因此您可以只使用reversetree
而不是依赖它。
第二种看待它的方式
现在,以两种方式看待这一点很好,所以反过来,例如。以NULL开头..例如8
的左节点,然后是叶子,然后是使用叶子的树,然后是使用我们事先计算的子树的完整树。
input result
NULL NULL
8 8
9 9
1 1
2 2
4 4
/ \ / \
8 9 9 8
3 3
/ \ / \
1 2 2 1
6 6
/ \ / \
3 4 4 3
/ \ / \ / \ / \
1 2 8 9 9 8 2 1
因此,在我的脑海中进行递归代替我在结果中使用前一个结果,你知道相同的函数会做。例如。我按照过程使用切换3
和4
,两次递归与之前完成的子树转换相同。
第一种方法是如何读取递归代码,第二种方式可能是最简单的方法,以及如何轻松地创建自己的递归函数。您从基本案例开始并测试它们,然后添加一个默认案例,如何将一个稍微复杂的问题变成一个较小的类似问题,最终成为一个基本案例。