我有两个问题, 1)对于任何递归算法,都存在迭代算法,是吗?我认为这是正确的,因为你只需要显式使用堆栈。这个问题已得到证实 Way to go from recursion to iteration
2)可能与上面的问题相同,我真的不认为即使使用递归算法,迭代解决方案也很明显或易于编写。例如:对于后序(LRN)或顺序(LNR)bst遍历,您如何用迭代方法编写它?在这两种情况下,找到插入堆栈的第一个对象并不容易。这就是我被卡住的地方。
有什么建议吗?实际上,我的目的与上面的问题相同,试图找到一种将递归算法改为迭代算法的一般模式。
答案 0 :(得分:0)
我觉得你没有正确地提出这个问题。我将尝试回答关于如何考虑实现有序遍历的迭代版本的问题(我刚刚给出了一些思考并在最近实现它。我觉得我也会帮助自己。鉴于人们知道递归版本。
递归版本中的每个函数调用都试图访问与函数调用关联的节点。对函数进行编码,使得对应于节点的激活帧在它可以完成其主要工作(即访问节点)之前被保存到系统堆栈(该进程的堆栈区域)上。这是因为我们想在访问节点本身之前访问节点的左子树。
在访问左子树之后,返回到我们保存的节点的框架会导致语言环境从内部堆栈弹出相同的内容,现在允许访问我们的节点。
我们必须使用显式堆栈来模仿这种推送和弹出。
template<class T>
void inorder(node<T> *root)
{
// The stack stores the parent nodes who have to be traversed after their
// left sub-tree has been traversed
stack<node<T>*> s;
// points to the currently processing node
node<T>* cur = root;
// Stack-not-empty implies that trees represented by nodes in the stack
// have their right sub-tree un-traversed
// cur-not-null implies that the tree represented by 'cur' has its root
// node and left sub-tree un-traversed
while (cur != NULL || !s.empty())
{
if (cur != NULL)
{
for (; cur->l != NULL; cur = cur->l) // traverse to the leftmost child because every other left child will have a left subtree
s.push(cur);
visit(cur); // visit him. At this point the left subtree and the parent is visited
cur = cur->r; // set course to visit the right sub-tree
}
else
{// the right sub-tree is empty. cur was set in the last iteration to the right subtree
node<T> *parent = s.top();
s.pop();
visit(parent);
cur = parent->r;
}
}
}
理解这一点的最好方法是在每次调用时绘制内部堆栈的功能并返回递归版本。