开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第10天,点击查看活动详情
题目分析
给你二叉树的根节点 root ,返回它节点值的访问顺序。
示例:
//树和节点的定义
/**
* 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) {}
* };
*/
前序遍历
栈操作示例
思路分析
- 前序遍历中节点访问顺序是:根节点--左孩子--右孩子
- 此示例中,当根节点A不为空时,访问当前值记录到结果数组中,再依次访问根节点的左孩子B和右孩子C
- 在访问根节点的左孩子B时,将左孩子也作为根节点,将此节点值记录到结果数组中,再依次访问此节点B的左孩子和右孩子,依次类推
- 例如此题中先将1记录到res结果数组,再访问1的左孩子2和右孩子3
- 此时访问左孩子2,此时2作为根节点,将2记录到结果数组中,再访问2的左孩子4和右孩子null
- 此时访问左孩子4,此时4作为根节点,将4记录到结果数组中,再访问4的左孩子null和右孩子6
- 由于左孩子为空,所以此时访问右孩子6,将6记录到结果数组中,再将6作为根节点,访问6的左孩子null和右孩子7
- 到节点7时,将7记录到结果数组中,但是7的左孩子和右孩子都是null,所以1节点的左子树访问结束,此时访问右子树,节点1的右孩子是3,此时将3记录到结果数组中,再访问3的左孩子和右孩子,直至结束
代码实现
class Solution {
public:
vector<int> preorderTraversal(TreeNode* root) {
//当根节点为空时,返回空
if (root==nullptr) return {};
//深度遍历需定义栈,便于返回上一节点
//为什么使用栈呢???因为栈是后进先出,当访问节点依次回退时,也是先回退到后访问的节点
stack<TreeNode*> stk;
//定义vector容器,依次记录访问的节点的值
vector<int> res;
//首先将根节点入栈
stk.emplace(root);
//当栈不为空时,对栈里面的元素进行访问
while(!stk.empty()){
//定义一个节点类型的指针,指向栈顶,记录下栈顶元素
TreeNode* node=stk.top();
//将栈顶元素出栈
stk.pop();
//访问栈顶元素的左右子节点和根节点,由于入栈是先入的后访问,所以先序遍历入栈顺序是右子节点、左子节点、根节点
if(node->right) stk.emplace(node->right);
if(node->left) stk.emplace(node->left);
res.emplace_back(node->val);
}
return res;
}
};
中序遍历
栈操作示例
思路分析
- 中序遍历中节点访问顺序是:左孩子--根节点--右孩子
- 此示例中,当根节点A不为空时,访问该节点的左孩子B,当B的左孩子为空时,输出B,此时B便作为根节点,再访问B的右孩子c
- 当c节点不为空时,再访问c的左孩子,直至左孩子为空,依次重复以上操作
- 此题中先访问1,1的左孩子2不空
- 访问左孩子2,2的左孩子4不空
- 访问左孩子4,此时4的左孩子为空,则将4作为根节点输出到结果数组,再访问4的右孩子6
- 6不空,将6作为根节点访问其左孩子null,此时将6加入结果数组
- 访问6的右孩子7,右孩子7不空,但是7的左孩子空,此时将7作为根节点输出到结果数组中,因为7的右孩子也是空,所以此时节点2的左子树访问完毕,此时再将2作为根节点加入结果数组
- 2没有右孩子,2的父节点--1的左子树访问完毕,将根节点1加入结果数组,再依次访问节点1的右子树,依次类推
代码实现
class Solution {
public:
vector<int> inorderTraversal(TreeNode* root) {
stack<TreeNode*> sta;
vector<int> res;
if(root==nullptr) return {};
//先将node指向根节点,此时栈还是空
TreeNode* node=root;
//当栈不为空或者第一个根节点不为空时
while(!sta.empty()||node!=nullptr){
while(node){
//当前节点不为空时,将节点入栈
sta.push(node);
//访问当前节点的左孩子,直到左孩子为空时,跳出循环,左孩子访问结束,返回上一层父节点,访问根节点,在依次对右子树进行左孩子访问,重复此操作
node=node->left;
}
//通过抛出栈顶元素向上访问
node=sta.top();
sta.pop();
res.push_back(node->val);
//节点指向根节点的右孩子,依次进行以上循环(访问左孩子,根节点,右孩子)
node=node->right;
}
return res;
}
};
后序遍历
栈操作示例
思路分析
思路同上
代码实现
class Solution {
public:
vector<int> postorderTraversal(TreeNode* root) {
stack<TreeNode*> sta;
vector<int> res;
TreeNode* node=root;
//记录访问的上一个节点
TreeNode* prev=nullptr;
if(node==nullptr) return {};
while(!sta.empty()||node!=nullptr){
//先依次访问左孩子
while(node){
sta.push(node);
node=node->left;
}
//此时node是空,往上访问
node=sta.top();
sta.pop();
//此时访问右子树,有两种情况,右孩子为空和右不为空,此时是右孩子不为空,并且没有被访问过
if(node -> right && node -> right != prev){
sta.emplace(node);
node = node -> right;
}
//
else{
res.emplace_back(node -> val);
prev = node;
node = nullptr;
}
}
return res;
}
};
重点
清楚栈操作