我真的需要你帮助我正确理解递归。我可以理解基本的递归和他们的逻辑,如斐波那契
int factorial(int n)
if(n <=1)
return n
else
return(n*factorial(n-1))
这很容易,函数在n
变为零之前保持调用阶乘,最后将所有结果相乘。但是像树遍历这样的递归对我来说很难理解
void inorderTraverse(Node* head)
if(head!=NULL){
inorderTraverse(head->left)
cout << head-> data
inorderTraverse(head->right)
}
}
这里我失去了逻辑,如果第一次递归调用将返回到函数,该函数如何进入cout行或如何显示正确的子数据。我真的需要你的帮助。
谢谢
答案 0 :(得分:1)
按字母顺序排列的二叉搜索树:
B
/ \
A C
inorderTraverse(&A)
将首先下降到A
并打印它(递归打印任何子树),然后打印B
,然后下降到C
并打印它(递归打印任何子树)子树)。
所以在这种情况下,A B C
。
对于更复杂的树:
D
/ \
B E
/ \
A C
这将打印为A B C D E
。注意原始树是如何在D
左侧,所以首先打印完整;问题被简化为起始问题的较小实例。这是递归的本质。打印下一个D
,然后打印D
右侧的所有内容(仅E
)。
请注意,在此实现中,节点不了解其父节点。递归意味着此信息存储在调用堆栈中。您可以使用迭代实现替换整个事物,但是您需要一些类似堆栈的数据结构来跟踪通过树向后移动 。
答案 1 :(得分:1)
顺序遍历说你需要遍历为左 - 右 - 右。对于一个级别,我们可以用左右根格式打印。但是随着级别的增加,你需要以相同的方式使你的算法遍历。所以你需要首先打印leftSubtree然后打印那个subTree的根,然后在每个级别打印右边的subTree。
递归代码inorderTraverse(head->left)
告诉节点不为空,转到树的左侧。一旦它到达结尾,它就打印出左边节点,然后打印该子树的根节点,并执行whtever操作。 leftSubTree你需要在Right subTree上执行相同的操作,这就是你编写inorderTraverse(head->right)
的原因。通过创建3级树开始调试。快乐学习。
答案 2 :(得分:1)
尝试想象二叉树,然后从root开始遍历它。你总是向左走。如果没有更多的左手,那么你就去吧,之后你就去吧。然后你将以root(从右侧)完成。
与思想迷宫相似。您可以选择始终向左转。 (你总是碰到左墙)。最后,如果没有其他出口,您将在出口处或在入口处返回。
在这段代码中,重要的是你在body中有两个递归调用。第一个是左子树,第二个是右子树。完成后,一个函数将返回到您启动的节点。
答案 3 :(得分:1)
二进制搜索树具有以下属性:对于每个节点,左子树包含的值小于当前节点的值,右子树包含更大的值。
因此,对于给定节点按顺序生成其子树中的值,函数需要:
如果你认为你的函数最初是一个处理子树的黑盒子,那么递归会神奇地出现
基本上,诀窍是最初将函数视为调用操作的简写方式,而不必担心它是如何实现的。如果你这样抽象地想到它,并且你注意到当前问题的解决方案可以通过将相同的功能应用于当前问题的子集来实现,那么就会有一个递归。
同样,订单后的遍历归结为: