题解 | #易理解的二叉树不同顺序遍历的迭代统一实现#
实现二叉树先序,中序和后序遍历
https://www.nowcoder.com/practice/a9fec6c46a684ad5a3abd4e365a9d362
在考虑二叉树的深度优先遍历问题时(包括前序、中序、后序遍历),递归方法是最清晰易理解且好实现的一种,但考虑到递归算法的效率,通常不推荐使用递归。
利用栈辅助实现的迭代方法提高了遍历算法的效率,但嵌套循环的方法看起来不易理解,写起来也容易出错。并且对于不同的遍历顺序,代码结构差异较大,更容易产生错误。
因此,为了使迭代实现不仅高效,而且能够像递归方法一样简洁易理解,这里介绍一种迭代实现不同顺序遍历的统一写法,方便理解和记忆。
核心思路
其核心思路来源于这样一个结论:二叉树的不同顺序遍历过程中经过结点的路线一样,只是访问各结点的时机不同。
- 先序遍历:第1次遇到节点时访问,第1次遇到在“遍历”该节点的左子树之前;
- 中序遍历:第2次遇到节点时访问,第2次遇到在“遍历”该节点的左子树之后,在”遍历“右子树之前;
- 后序遍历:第3次遇到节点时访问,第3次遇到在“遍历”右子树之后。
注:“遍历”指沿下图中的路线经过。
因此在模拟系统栈的过程中,使用一个计数变量来记录结点入栈出栈的次数,以便能够根据不同的遍历顺序需要在合适的时机(先序:第1次遇见,中序:第2次,后续:第3次)访问结点。
具体的c++代码实现如下:
/** * struct TreeNode { * int val; * struct TreeNode *left; * struct TreeNode *right; * TreeNode(int x) : val(x), left(nullptr), right(nullptr) {} * }; */ class Solution { public: /** * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可 * * * @param root TreeNode类 the root of binary tree * @return int整型vector<vector<>> */ vector<vector<int> > threeOrders(TreeNode* root) { // write code here vector<int> preOrder, inOrder, postOrder; stack<pair<TreeNode*, int>> st; st.push(make_pair(root, 1)); int cnt; //记录遇到结点的次数 // 模拟系统栈的过程 while (!st.empty()) { root = st.top().first; cnt = st.top().second; st.pop(); if (!root) continue; if (cnt == 1) { // 第一次遇到结点,只会往其左孩子走 preOrder.push_back(root->val);//前序遍历在第一次遇到结点时访问 // 先将结点入栈,然后是其左孩子 st.push(make_pair(root, 2)); st.push(make_pair(root->left, 1)); } else if (cnt == 2) { // 第二次遇见结点,表示左孩子已经遍历完了,接下来遍历右孩子 inOrder.push_back(root->val);//中序遍历在第二次遇到结点时访问 st.push(make_pair(root, 3)); st.push(make_pair(root->right, 1)); } else { // 第三次遇到结点,表示以该结点为根的子树遍历完成 postOrder.push_back(root->val);//后序遍历在第三次遇到结点时访问 } } vector<vector<int> > res = {preOrder, inOrder, postOrder}; return res; } };