当你所拥有的树是一个二叉搜索树,并且你想要做的仅是在其中查找具有特定值的节点时,那么事情就很简单:无需递归,可以使用简单的循环进行查找,就像其他人指出的那样。
在更一般的情况下,如果你拥有的树不一定是二叉搜索树,并且想要对其执行完全遍历,则最简单的方法是使用递归。但正如你已经了解到的,如果这棵树非常深,则递归将无法工作。
因此,为了避免递归,你必须在C++堆上实现一个栈。你需要声明一个新的StackElement类,它将包含每个本地变量以及原始递归函数所接受的每个参数的成员变量。 (你可能只需要较少的成员变量,当你让代码成功运行后再考虑这个问题。)
你可以将StackElement实例存储在堆栈集合中,也可以使每个StackElement实例包含一个指向其父级的指针,从而完全自己实现堆栈。
因此,你的函数不再以递归方式调用自身,而是简单包含一个循环。你的函数使用关于树的根节点的信息初始化当前StackElement进入循环。其父指针将为null,这是另一种说法,即堆栈为空。
在你的函数递归调用自身的每个位置上,新函数将分配一个新的StackElement实例,初始化它,并使用此新实例作为当前元素重复循环。
在递归版本的函数返回的每个位置上,新函数将释放当前StackElement,弹出位于堆栈顶部的元素,使其成为新的当前元素,并重复循环。
当你找到所要查找的节点时,你只需从循环中断开即可。
或者,如果你现有树的节点支持a)到其“父”节点的链接和b)用户数据(在其中可以存储“访问过”标志),则无需实现自己的堆栈,可以直接原地遍历树:在循环的每次迭代中,首先检查当前节点是否是您寻找的节点;如果不是,则枚举子项,直到找到尚未被访问的子项,然后访问该子项;当你到达叶子节点或所有子节点都已被访问的节点时,然后通过跟随指向父节点的链接进行回溯。此外,如果你有自由在遍历树时销毁树,则甚至不需要“用户数据”的概念:一旦你完成子节点,就释放它并使其为空。