当前位置:网站首页>二叉树非递归遍历
二叉树非递归遍历
2022-07-31 21:33:00 【Massachusetts_11】
1. 遍历一棵树

前、中、后序遍历的路径实际是相同的,都是以如上路径去游历。
前、中、后序访问的结果不同,实际是访问节点的时机不同:
前序:一遇到节点就去访问
中序:访问完左树再去访问
后序:访问完右子树再去访问
如下是B节点的前、中、后序访问时机
2. 非递归遍历
2.1 理解
之前的递归遍历,将一棵树看成一个对称结构:左子树根右子树,借助递归函数,可以进入左右子树进行访问;
但如果想在当前函数内进行迭代访问,之前的左右子问题的方式就很难实现了。
这里我们不妨再看看这个遍历的路径图:

首先沿着最左侧向下走过A-B-D
然后向上,走D的右子树、B的右子树、A的右子树,走完A的右子树回来就代表遍历结束了
这里访问右子树就可以看成是一个子问题——访问以右节点为根的另一棵树,重新回到最一开始;
可以发现左侧节点第一次走到的顺序是从上至下:A-B-D,下一次遇到访问右子树的顺序又是D-B-A,恰好相反,因此可以用栈的结构,从左侧走的时候先把节点依次从上至下存起来,当遍历到底,遇到空的时候再取出栈顶的节点,通过这个节点去访问它的右树;
同时凭借着栈的结构,当进入右树,走到右树的节点,依然入此栈,当右树走完回来,右树所有入栈的节点也都已经取出,又只剩下了之前主干上的节点,还可继续主线逻辑,与递归方式的逻辑相似——不管递归出去的逻辑多复杂,完成了分支任务回来,我的主线任务还要正常进行。
2.2 实现
注:以下只提供了非递归游历整棵树的方法,前、中、后序访问节点的时机未写入,具体见后。
变量定义:

实现:
遍历最左侧节点,同时将他们依次入栈

开始取栈中元素

通过此节点访问它的右树

遍历结束的判断
- 栈中元素取完——栈空
- 同时当前的根节点对应一棵空树

子树为空的情况(返回主干问题):
跳过当前树的遍历,从栈中取下一个节点
当前逻辑刚好可以实现

3. 前、中、后序遍历
前、中、后序遍历唯一的区别就是访问节点的时机不同
每个节点可以看成是有三次被经过:到达初遇,从左边回来再遇,遍历完右子树再遇,
这三次相遇恰好就对应前、中、后序的访问时机,
只需在迭代逻辑中找到这三次相遇的对应部分进行访问,即可完成前、中、后序遍历。

3.1 前序遍历
访问时机:第一次碰到,也就是左侧遍历要入栈的时候

此时访问,进行入栈即可。
vector<int> preorderTraversal(TreeNode* root)
{
vector<int> v;//存储访问出元素
stack<TreeNode*> st;//栈——临时储存节点
TreeNode* cur = root;//用于游历整棵树的指针
while (!st.empty() || cur)
{
//遍历当前树的所有最左侧节点
while (cur)
{
v.push_back(cur->val);
st.push(cur);
cur = cur->left;
}
//取出栈顶节点
TreeNode* tmp = st.top();
st.pop();
//前序遍历右树
cur = tmp->right;//更新root为栈顶节点的右树
}
return v;
}
3.2 中序遍历
访问时机:左侧节点访问已完成,节点出栈,马上要进入右树进行访问的时候

此时访问,进行入栈即可。
vector<int> inorderTraversal(TreeNode* root)
{
vector<int> v;//存储访问出元素
stack<TreeNode*> st;//栈——临时储存节点
TreeNode* cur = root;//用于游历整棵树的指针
while (!st.empty() || cur)
{
//遍历当前树的所有最左侧节点
while (cur)
{
st.push(cur);
cur = cur->left;
}
//取出栈顶节点
TreeNode* tmp = st.top();
st.pop();
v.push_back(cur->val);
//前序遍历右树
cur = tmp->right;//更新root为栈顶节点的右树
}
return v;
}
3.3 后序遍历
在整棵右树访问完成,再次回到这个节点的时候进行访问
由于访问右树是一个多层的迭代遍历,无法在这个单次的代码上直接找到访问的位置
观察后,右子树进行后序遍历的最后一个访问的节点是右树的根节点,访问完这个节点的下一个节点就是当前要访问的节点

所以每次访问完一个节点,都将这个节点进行记录,节点要出栈都先判断栈顶节点对应的右节点是否为已记录节点
- 若是,则出栈并进行访问,同时更新用于记录的节点,此时右树无需访问,直接访问下一个栈顶元素
- 否则说明当前是②的位置,先不出栈,先访问右树,右树回来再出栈
**特殊情况:**当右树为空,这个节点也要访问

如访问B的右树完时候,prev是D,但此时B也得进行访问,所以右树为空也要加入出栈访问的判断条件

vector<int> postorderTraversal(TreeNode* root)
{
vector<int> v;//存储访问出元素
stack<TreeNode*> st;//栈——临时储存节点
TreeNode* cur = root;//用于游历整棵树的指针
TreeNode* prev = nullptr;
while (!st.empty() || cur)
{
//遍历当前树的所有最左侧节点
while (cur)
{
st.push(cur);
cur = cur->left;
}
TreeNode* tmp = st.top();
if (tmp->right == prev || tmp->right == nullptr)
{
st.pop();
v.push_back(tmp->val);
prev = tmp;
cur = nullptr;//下一次循环直接当空树访问下一个栈中节点
}
else
{
cur = tmp->right;//更新root为栈顶节点的右树
}
}
return v;
}
边栏推荐
- How to identify fake reptiles?
- 21. Support Vector Machine - Introduction to Kernel Functions
- Talking about the algorithm security of network security
- Socket回顾与I/0模型
- flowable workflow all business concepts
- Linux环境redis集群搭建「建议收藏」
- Introduction to Audio Types and Encoding Formats in Unity
- sqlite3 simple operation
- [PIMF] OpenHarmony Thesis Club - Inventory of the open source Hongmeng tripartite library [3]
- c语言解析json字符串(json对象转化为字符串)
猜你喜欢

How to debug TestCafe

Flex layout in detail

Short-circuit characteristics and protection of SiC MOSFETs

PCB stackup design

MATLAB program design and application 2.4 Common internal functions of MATLAB

Shell script quick start to actual combat -02

Memblaze发布首款基于长存颗粒的企业级SSD,背后有何新价值?

Flink_CDC construction and simple use
![leetcode: 6135. The longest ring in the graph [inward base ring tree + longest ring board + timestamp]](/img/91/284de3dcbb8d143d85775b314dd41c.png)
leetcode: 6135. The longest ring in the graph [inward base ring tree + longest ring board + timestamp]

Apache EventMesh distributed event-driven multi-runtime
随机推荐
Short-circuit characteristics and protection of SiC MOSFETs
关注!海泰方圆加入《个人信息保护自律公约》
Linux environment redis cluster to build "recommended collection"
利用反射实现一个管理对象信息的简单框架
rj45对接头千兆(百兆以太网接口定义)
OSPFv3的基本配置
Niuke.com brush questions (1)
What is Thymeleaf?How to use.
[NLP] What is the memory of the model!
A shortcut to search for specific character content in idea
sqlite3简单操作
Go1.18 upgrade function - Fuzz test from scratch in Go language
Flex layout in detail
Several methods for deleting specified elements in Golang slices
有一说一,外包公司到底值不值得去?
AI 自动写代码插件 Copilot(副驾驶员)
【AcWing】The 62nd Weekly Match 【2022.07.30】
Implementation of a sequence table
高通cDSP简单编程例子(实现查询高通cDSP使用率、签名),RK3588 npu使用率查询
-xms -xmx(information value)