Binary Tree的遍历可分为preorder, inorder, postorder和in-level order四种。前3种可用递归或非递归(基于stack,后进先出),第4种通常用BFS,基于queue(先进先出),也可以用DFS,基于stack。注意这里是Binary Tree,不需要是Binary Search Tree。

preorder遍历非递归模板:
遍历顺序为根、左、右
思路:

  1. 如果根节点非空,将根节点加入到栈中。
  2. 如果栈不空,弹出栈顶节点,将其值加加入到数组中。
    2.1 如果该节点的右子树不为空,将右子节点加入栈中。
    2.2 如果左子节点不为空,将左子节点加入栈中。
  3. 重复第二步,直到栈空。
    代码如下://最终参考版
/*** Definition of TreeNode:* class TreeNode {* public:*     int val;*     TreeNode *left, *right;*     TreeNode(int val) {*         this->val = val;*         this->left = this->right = NULL;*     }* }*/class Solution {
public:/*** @param root: A Tree* @return: Preorder in ArrayList which contains node values.*/vector<int> preorderTraversal(TreeNode * root) {if (!root) return {};vector<int> result;stack<TreeNode*> s;s.push(root);while(!s.empty()) {TreeNode* temp = s.top();s.pop();result.push_back(temp->val);if (temp->right) s.push(temp->right);if (temp->left) s.push(temp->left);}  return result;}
};

in-order非递归模板:(非常重要!!!)
遍历顺序为左、根、右

思路
1. 从根节点开始,开始把左节点挨个压栈,直至最左端的叶节点。
2. 若stack不为空,对node=stack.top(),存入结果。
若node无右节点,则pop,并看node在stack前一个位置(也就是新的stack.top)是不是node的父节点,并且node是它的右节点);若是,也将其pop()。

//注意:根据in-order的特点,如果某个节点无右节点,或者右节点已经访问过,说明这就是根了,应该pop。
若node有右节点,则将其压栈,并将其左节点挨个压栈,直至其左子树的最左端的叶节点。
//注意:根据in-order的特点,如果某个节点还有右节点没访问,那就要先访问右节点,即要先将其压栈。
3. 重复2,直到stack空。

举例如下:
第一个while循环沿着左节点压栈,s={6,5,3,2}, 2是栈顶。
第二个while循环
先将node=s.top()的存入结果(2),然后看node是否有右节点,这里没有,所以pop()。
然后新的node=s.top()存入结果(3),这里因为3有右节点4(这里3不能pop,否则4返回就找不到3了),所以将节点4压栈,s={6,5,3,4}。
然后新的node=s.top()存入结果(4),这里4没有右节点,所以4 pop,然后我们看到4是3的右节点,所以3 pop。然后后面的循环会处理5,6,…。
第三个while循环本质上和第一个while循环一样。

代码如下(参考自九章)://最终参考版
首先访问左子树,将左子树存入栈中,每次将栈顶元素存入结果,如果右子树为空,取出栈顶元素,如果当前元素为栈顶元素右子树,一直弹出至当前元素不为栈顶元素右子树(此处说明访问右子树,根节点已经被访问过,弹出即可)。如果节点右子树不为空,访问右子树,继续循环遍历左子树,存入栈中。

    vector<int> inorderTraversal(TreeNode * root) {vector<int> result;stack<TreeNode *> s;if (!root) return result;while(root) {s.push(root);root=root->left;}while(!s.empty()) {TreeNode* node=s.top();result.push_back(node->val);if (!node->right) {s.pop();while(!s.empty() && (s.top()->right==node)) {node=s.top();s.pop();}} else {node = node->right;while(node) {s.push(node);node=node->left;}}}return result;}

又看了一下代码,之前的解释不是很清楚。现在重新解释一下,上面的if(node->right)这个分支好理解,就是如果当前节点有右节点,那就找到右子树的最左边的节点,并沿途挨个压栈。
难点在于if(!node->right)这个分支,为什么有下面这行代码呢? 因为如果没有之前的if(node->right)处理,也就是s.top()没有右子树的话,那就直接s.pop()就可以了,但之前因为s.top()有右节点,进行了if(node->right)的处理,所以s.top()这个节点要推迟到现在才能s.pop()。为啥不能去掉(s.top()->right==node)呢?因为s.top()这个节点和node不一样,node没有右节点,s.top()不一定没有。如果把s.top()不管三七二十一都pop()掉,那么s.top()的右节点就断了,以后也找不到了。

                while(!s.empty() && (s.top()->right==node)) {node=s.top();s.pop();}

简化版:
事实上每次stack的top push到res里后就可以从stack里面删掉了,不需要留着。注意下面的这个代码可以用于求二叉树的next iterator,但是不能用于求previous iterator。因为栈里面有些信息已经被删掉了。而上面那个版本不光可以求next iterator,也可以求previous iterator(把代码里面的left 和right互换就可以)。

class Solution {public:/*** @param root: A Tree* @return: Inorder in ArrayList which contains node values.*/vector<int> inorderTraversal(TreeNode *root) {if (!root) return {};vector<int> res;stack<TreeNode *> stk;while (root) {stk.push(root);root = root->left;}while (!stk.empty()) {TreeNode *node = stk.top();res.push_back(node->val);stk.pop();if (node->right) {node = node->right;while (node) {stk.push(node);node = node->left;}}}return res;}
};

post-order非递归模板
遍历顺序为左、右、根

  1. 如果根节点非空,将根节点加入到栈中。
  2. 如果栈不空,取栈顶元素(暂时不弹出),
    i. 如果(左子树已访问过或者左子树为空),且(右子树已访问过或右子树为空),则弹出栈顶节点,将其值加入数组,
    ii. 如果左子树不为空,切未访问过,则将左子节点加入栈中,并标左子树已访问过。
    iii. 如果右子树不为空,切未访问过,则将右子节点加入栈中,并标右子树已访问过。
  3. 重复2,直到栈空。

代码如下:

/*** Definition of TreeNode:* class TreeNode {* public:*     int val;*     TreeNode *left, *right;*     TreeNode(int val) {*         this->val = val;*         this->left = this->right = NULL;*     }* }*/class Solution {
public:/*** @param root: A Tree* @return: Postorder in ArrayList which contains node values.*/vector<int> postorderTraversal(TreeNode * root) {vector<int> result;stack<TreeNode *> s;TreeNode * current = root, * lastVisited = NULL;if (!root) return vector<int>();s.push(root);while(!s.empty()) {current = s.top();if (!lastVisited || current == lastVisited->left || current == lastVisited->right) {if (current->left) {s.push(current->left);} else if (current->right) { //note! the else is needed here!!!s.push(current->right);}} else if (current->left == lastVisited) {if (current->right) {s.push(current->right);}} else {result.push_back(current->val);s.pop();}   lastVisited = current;}return result;}
};

下面这个版本更好。//最终参考版
使用栈进行二叉树后序遍历,首先对左子树进行遍历压入栈中,直至左子树为空,然后访问右子树。故每个节点会被访问两次,当节点被第二次访问时,即curr->right=lastvisit时,该节点出栈。

class Solution {public:vector<int> postorderTraversal(TreeNode *root) {vector<int> result;stack<TreeNode *> myStack;TreeNode *current = root, *lastVisited = NULL;while (current != NULL || !myStack.empty()) {while (current != NULL) {myStack.push(current);current = current->left;}current = myStack.top(); if (current->right == NULL || current->right == lastVisited) {myStack.pop();result.push_back(current->val);lastVisited = current;current = NULL;} else {current = current->right;}}return result;}
};

上面的几种解法还是没有统一风格,下面是链接
https://www.jianshu.com/p/49c8cfd07410
给出的更统一的模板。非常好。

//更简单的非递归前序遍历
void preorderTraversalNew(TreeNode *root, vector<int> &path)
{stack< pair<TreeNode *, bool> > s;s.push(make_pair(root, false));bool visited;while(!s.empty()){root = s.top().first;visited = s.top().second;s.pop();if(root == NULL)continue;if(visited){path.push_back(root->val);}else{s.push(make_pair(root->right, false));s.push(make_pair(root->left, false));s.push(make_pair(root, true));}}
}
//更简单的非递归中序遍历
void inorderTraversalNew(TreeNode *root, vector<int> &path)
{stack< pair<TreeNode *, bool> > s;s.push(make_pair(root, false));bool visited;while(!s.empty()){root = s.top().first;visited = s.top().second;s.pop();if(root == NULL)continue;if(visited){path.push_back(root->val);}else{s.push(make_pair(root->right, false));s.push(make_pair(root, true));s.push(make_pair(root->left, false));}}
}//更简单的非递归后序遍历
void postorderTraversalNew(TreeNode *root, vector<int> &path)
{stack< pair<TreeNode *, bool> > s;s.push(make_pair(root, false));bool visited;while(!s.empty()){root = s.top().first;visited = s.top().second;s.pop();if(root == NULL)continue;if(visited){path.push_back(root->val);}else{s.push(make_pair(root, true));s.push(make_pair(root->right, false));s.push(make_pair(root->left, false));}}
}

in-level order 非递归版
思路: 用queue。
一开始将root放入queue中,然后进入while(!queue.empty()),若queue不为空,则按queue中有多少元素(queue.size()),不断取queue.front(),将其值存入结果,再将其左右节点push进queue。周而往复,直到queue空。
代码如下:

/*** Definition of TreeNode:* class TreeNode {* public:*     int val;*     TreeNode *left, *right;*     TreeNode(int val) {*         this->val = val;*         this->left = this->right = NULL;*     }* }*/class Solution {
public:/*** @param root: A Tree* @return: Level order a list of lists of integer*/vector<vector<int>> levelOrder(TreeNode * root) {vector<vector<int> > result;if (!root) return result;queue<TreeNode *> q;q.push(root);while(!q.empty()) {vector<int> vec;int size=q.size();for (int i=0; i<size; ++i) {TreeNode* node=q.front();q.pop();   vec.push_back(node->val);if (node->left) q.push(node->left);if (node->right)q.push(node->right);}result.push_back(vec);} return result; }
};

另外还有二叉树Zigzag遍历,见
https://blog.csdn.net/roufoo/article/details/103946959

还有二叉树按vertical order遍历,见
https://blog.csdn.net/roufoo/article/details/103943335

还有二叉树Morris遍历

再来一个二叉树非递归模板,即直接用一个stack模拟系统调用,context存储系统调用中应该保留的信息。这里采用vector而不是stack做栈是因为希望修改stack.top()。

前序遍历


/*** Definition for a binary tree node.* struct TreeNode {*     int val;*     TreeNode *left;*     TreeNode *right;*     TreeNode() : val(0), left(nullptr), right(nullptr) {}*     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}*     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}* };*/struct Context {TreeNode* node;int step;Context(TreeNode* _node = NULL, int _step = 0) : node(_node), step(_step) {}
};class Solution {
public:vector<int> preorderTraversal(TreeNode* root) {vector<Context> s;s.push_back(Context(root, 0));vector<int> res;while (!s.empty()) {if (s.back().node == NULL) {//root为空,直接返回s.pop_back();} else if (s.back().step == 0) {s.back().step = 1;res.push_back(s.back().node->val);//if (s.back().step == 0) s.pop_back();} else if (s.back().step == 1) {s.back().step = 2;s.push_back(Context(s.back().node->left, 0));} else if (s.back().step == 2) {s.back().step = 3;s.push_back(Context(s.back().node->right, 0));} else if (s.back().step == 3) {//表示当前栈顶的左右子节点都处理完了,这是为了跟step==0做区分,step==0是当前栈顶还没开始处理左右字节点的情况。s.pop_back();}}return res;  }
};

中序遍历:

/*** Definition for a binary tree node.* struct TreeNode {*     int val;*     TreeNode *left;*     TreeNode *right;*     TreeNode() : val(0), left(nullptr), right(nullptr) {}*     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}*     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}* };*/struct Context {TreeNode* node;int step;Context(TreeNode* _node = NULL, int _step = 0) : node(_node), step(_step) {}
};class Solution {public:vector<int> inorderTraversal(TreeNode* root) {vector<Context> s;s.push_back(Context(root, 0));vector<int> res;while (!s.empty()) {if (s.back().node == NULL) {//root为空,直接返回s.pop_back();} else if (s.back().step == 0) {s.back().step = 1;s.push_back(Context(s.back().node->left, 0));//if (s.back().step == 0) s.pop_back();} else if (s.back().step == 1) {s.back().step = 2;res.push_back(s.back().node->val);} else if (s.back().step == 2) {s.back().step = 3;s.push_back(Context(s.back().node->right, 0));} else {//表示当前栈顶的左右子节点都处理完了,这是为了跟step==0做区分,step==0是当前栈顶还没开始处理左右字节点的情况。s.pop_back();}}return res;      }
};

后序遍历:

/*** Definition for a binary tree node.* struct TreeNode {*     int val;*     TreeNode *left;*     TreeNode *right;*     TreeNode() : val(0), left(nullptr), right(nullptr) {}*     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}*     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}* };*/struct Context {TreeNode* node;int step;Context(TreeNode* _node = NULL, int _step = 0) : node(_node), step(_step) {}
};class Solution {public:vector<int> postorderTraversal(TreeNode* root) {vector<Context> s;s.push_back(Context(root, 0));vector<int> res;while (!s.empty()) {if (s.back().node == NULL) {//root为空,直接返回s.pop_back();} else if (s.back().step == 0) {s.back().step = 1;s.push_back(Context(s.back().node->left, 0));} else if (s.back().step == 1) {s.back().step = 2;s.push_back(Context(s.back().node->right, 0));} else {res.push_back(s.back().node->val);s.pop_back();}}return res;  }
};

注意后序遍历中,根节点最后处理,可以顺便弹栈,所以它不用加step=3的情况。为了便于和前序和中序统一版本,也可以加step=3的情况,结果一样。

/*** Definition for a binary tree node.* struct TreeNode {*     int val;*     TreeNode *left;*     TreeNode *right;*     TreeNode() : val(0), left(nullptr), right(nullptr) {}*     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}*     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}* };*/struct Context {TreeNode* node;int step;Context(TreeNode* _node = NULL, int _step = 0) : node(_node), step(_step) {}
};class Solution {public:vector<int> postorderTraversal(TreeNode* root) {vector<Context> s;s.push_back(Context(root, 0));vector<int> res;while (!s.empty()) {if (s.back().node == NULL) {//root为空,直接返回s.pop_back();} else if (s.back().step == 0) {s.back().step = 1;s.push_back(Context(s.back().node->left, 0));} else if (s.back().step == 1) {s.back().step = 2;s.push_back(Context(s.back().node->right, 0));} else if (s.back().step == 2) {s.back().step = 3;res.push_back(s.back().node->val);} else {s.pop_back();}}return res;  }
};

附加一个最好的中序遍历非递归模板,非常简洁。

class Solution {public:/*** @param root: A Tree* @return: Inorder in ArrayList which contains node values.*/vector<int> inorderTraversal(TreeNode *root) {stack<TreeNode *> stk;vector<int> res;while (root || !stk.empty()) {while (root) {stk.push(root);root = root->left;}root = stk.top();stk.pop();res.push_back(root->val);root = root->right;}return res;}
};

Binary Tree 非递归遍历模板小结(经典!)相关推荐

  1. 【我的算法笔记】后序非递归遍历模板及其应用

    目录 前言 非递归后序遍历算法模板 求树的深度 打印值为x的节点的所有祖先 求节点t,s最近公共祖先节点 输出从每个叶子节点到根节点的逆路径 前言 本篇文章主要介绍非递归后序遍历的算法,并且在这个算法 ...

  2. 6-4 二叉树的非递归遍历 (25分)_本周小结!(二叉树)

    给「代码随想录」一个星标吧! ❝ 以后每周加上一个本周小结怎么样? ❞ 本周小结 发现大家周末的时候貌似都不在学习状态,周末的文章浏览量和打卡情况照工作日差很多呀,可能是本周日是工作日了,周六得好好放 ...

  3. 二叉树的非递归遍历(统一的模板)

    二叉树的非递归遍历 前言 树的存储结构 先序遍历 先序的递归遍历 先序的非递归遍历 中序遍历 中序的递归遍历 中序遍历的非递归算法 后序遍历 后序的递归遍历 后序的非递归遍历 层次遍历 层次遍历获得每 ...

  4. C++版二叉树非递归遍历

    C++版二叉树非递归遍历 文章目录 C++版二叉树非递归遍历 一.二叉树前序遍历 二.二叉树中序遍历 三.二叉树后序遍历 一.二叉树前序遍历 /*** Definition for a binary ...

  5. [Alg] 二叉树的非递归遍历

    1. 非递归遍历二叉树算法 (使用stack) 以非递归方式对二叉树进行遍历的算法需要借助一个栈来存放访问过得节点. (1) 前序遍历 从整棵树的根节点开始,对于任意节点V,访问节点V并将节点V入栈, ...

  6. 二叉树学习之非递归遍历

    二叉树递归遍历可谓是学过数据结构的同仁都能想一下就能写出来,但在应聘过程我们常常遇到的是写出一个二叉树非递归遍历函数,接着上篇文章写二叉树的非递归遍历,先难后易,一步一步的来. 先上代码: #incl ...

  7. java 建树源码_Java实现的二叉树常用操作【前序建树,前中后递归非递归遍历及层序遍历】...

    import java.util.ArrayDeque; import java.util.Queue; import java.util.Stack; //二叉树的建树,前中后 递归非递归遍历 层序 ...

  8. 非递归遍历N-ary树Java实现

    2019-03-25 14:10:51 非递归遍历二叉树的Java版本实现之前已经进行了总结,这次做的是非递归遍历多叉树的Java版本实现. 在非递归遍历二叉树的问题中我个人比较推荐的是使用双whil ...

  9. 二叉树的链式结构的非递归遍历

    二叉树的链式结构的非递归遍历 一. 非递归前序遍历和非递归中序遍历 1.    Stack.h #ifndef__STACK_H__ #define__STACK_H__ #include<st ...

最新文章

  1. 十三水牌型 图片_鬼灭之刃:鳄鱼揭开十三型的秘密,缘一亲自演示
  2. eclipse提示edit source lookup path的问题
  3. 03.Python基础--控制流语句-顺序结构-判断结构-循环语句
  4. Vue.js 动态为img的src赋值
  5. 关于虚拟机下linux共享Windows文件的解决方案
  6. “约见”面试官系列之常见面试题之第一百零六篇之css只在当前组件中起作用(建议收藏)
  7. 【spark系列3】spark开发简单指南
  8. GARFIELD@02-21-2005
  9. 2019蓝桥杯省赛心得
  10. IAR(For STM32) 安装,配置,工程创建,下载,调试
  11. thinkphp5 自定义分页样式
  12. java程序员 技术成长路线
  13. Linux 命令(159)—— hostname 命令
  14. 「SwiftUI」延迟执行代码
  15. SS00007.algorithm——|ArithmeticMachine.v07|——|Machine:监督学习算法.v06|
  16. 每日自动签到签退的程序
  17. MST53XXB 35V,200mA,1.9uA,低压线性稳压器
  18. 单片机8x8点阵让数字0从右到左依次显示循环
  19. 建模小白一定要知道的8款软件
  20. lisp标定高程_基于Auto Lisp的局部高程点批量检查与修改技术

热门文章

  1. Solidworks入门学习作业记录(一)
  2. java 所有事件类型以及事件实现的方法
  3. 为什么越来越多的老码农准备上岸?
  4. OpenSSL密码库算法笔记——第5.1.2章 椭圆曲线算法集
  5. @NotNull与@NonNull使用笔记
  6. c语言上机题库20套题,C语言上机试题1-20套
  7. 中国矿业大学软件工程菜鸟笔记
  8. 使用Java实现数据库编程
  9. Fiddler4抓包PC、移动端https请求
  10. win10控制面板里没java_win10安装java以及java配置遇到的坑