[转载]二叉树逆序遍历的迭代解法
来源:互联网 发布:imagelab mac 下载 编辑:程序博客网 时间:2024/05/22 16:41
原文地址:Binary Tree Post-Order Traversal Iterative Solution
从Hint开始翻译的,前面忽略……
通常,在树里没有父指针的情况下有必要使用基于堆栈的解法。试图理解下简单的逆序遍历二叉树的例子。什么时候应该输出一个节点的值?注意下什么情况是跑遍了整个树。试图用一个变量来存储上一个节点。他对我们爬遍这棵树有什么帮助?
解法:
我们使用prev来存储遍历队列的前一个节点。假设curr为当前节点并在栈的顶端。当prev为curr的父节点时,我们开始向下爬树。在这种情况下,我们尝试去遍历curr的左孩子,如果存在的话(将左孩子压进栈里)。如果(左孩子)不存在,就对右孩子进行。如果左右孩子都不存在(即为叶子节点),输出curr的值并将它删除。
如果prev是curr的左孩子节点,我们是在从左边向上爬树。我们看下curr的右孩子。尝试从右孩子向下遍历(即将右孩子压进栈),否则输出curr的值并将它移出栈。
如果prev是curr的右孩子,则我们在从右边向上爬树。这种情况下,输出curr的值并将它移出栈。
void postOrderTraversalIterative(BinaryTree *root) { if (!root) return; stack<BinaryTree*> s; s.push(root); BinaryTree *prev = NULL; while (!s.empty()) { BinaryTree *curr = s.top(); // we are traversing down the tree if (!prev || prev->left == curr || prev->right == curr) { if (curr->left) { s.push(curr->left); } else if (curr->right) { s.push(curr->right); } else { cout << curr->data << " "; s.pop(); } } // we are traversing up the tree from the left else if (curr->left == prev) { if (curr->right) { s.push(curr->right); } else { cout << curr->data << " "; s.pop(); } } // we are traversing up the tree from the right else if (curr->right == prev) { cout << curr->data << " "; s.pop(); } prev = curr; // record previously traversed node }}
上面的方法比较容易理解,但是有一些冗余代码。我们可以重构掉冗余代码。现在他看起来更简洁了。注意下输出curr值部分的语句块是如何重构成一个单独的另一个语句块。只要迭代器在下次迭代能确保进入else语句块,就不用担心value不会被输出。
void postOrderTraversalIterative(BinaryTree*root) { if(!root) return; stack<BinaryTree*>s; s.push(root); BinaryTree*prev = NULL; while(!s.empty()) { BinaryTree*curr = s.top(); if(!prev || prev->left == curr || prev->right == curr) { if(curr->left) s.push(curr->left); elseif (curr->right) s.push(curr->right); }else if (curr->left == prev) { if(curr->right) s.push(curr->right); }else { cout<< curr->data << " "; s.pop(); } prev= curr; }}
替代解法:
一种替代解法是使用两个栈。尝试在一张纸上解决。我想这十分magical and beautiful。你会认为这种方法很魔幻,但实际上它确实做着逆序前置遍历的工作。也就是说,遍历的顺序是个节点,右孩子跟在左孩子后面。 This yields post-order traversal in reversed order.使用第二个栈可以将它反转为正确的顺序。
工作步骤:
将根节点压进第一个栈。
将节点从第一个栈删除,压进第二个栈。
然后将左孩子压进第一个栈(右孩子跟着)
重复第2、3步骤知道第一个栈为空。
一旦完成,第二个栈被反转好的所有节点。从第二个栈中一个一个移出节点,工作就完成了。
void postOrderTraversalIterativeTwoStacks(BinaryTree *root) { if (!root) return; stack<BinaryTree*> s; stack<BinaryTree*> output; s.push(root); while (!s.empty()) { BinaryTree *curr = s.top(); output.push(curr); s.pop(); if (curr->left) s.push(curr->left); if (curr->right) s.push(curr->right); } while (!output.empty()) { cout << output.top()->data << " "; output.pop(); }}
- [转载]二叉树逆序遍历的迭代解法
- 二叉树三种遍历的递归和迭代解法
- 二叉树遍历的迭代算法
- 二叉树遍历的迭代算法
- 迭代遍历二叉树
- 二叉树的递归、迭代遍历的模板代码
- 二叉树的遍历(递归与迭代)
- 二叉树遍历的所有递归和迭代实现
- 二叉树3中遍历方法的迭代实现
- 二叉树中序遍历的迭代版本
- 二叉树中序遍历的迭代实现
- 二叉树前序遍历的迭代实现
- 二叉树后序遍历的迭代实现
- 二叉树非递归遍历--迭代
- 线性方程组的迭代解法
- 【转载】二叉树的非递归遍历
- 二叉树的遍历的迭代和递归实现方式
- 二叉树的三种遍历方式的递归实现和迭代实现
- Linux手动增加用户组和用户和相关文件
- 开源项目
- IT痴汉的工作现状6-寂寞的夜
- Yii的常用URL和渲染方法
- 书讯: CFHipsterRef: Low-Level Programming on iOS & Mac OS X
- [转载]二叉树逆序遍历的迭代解法
- 电脑突发故障应急处理方法
- 柠檬水
- Hibernate--Query
- NYOJ54 小明的存钱计划
- shel脚本中的一些特殊符号
- java nio MappedByteBuffer 文件映射
- TreeMap内部实现简介
- VS2008 集成Lua解释器