本篇文章结合结合leetcode(94、144、145 二叉树的中序、前序、后序遍历方式)中的三道题,介绍树的前序、中序、后序遍历的递归和非递归实现。先简单介绍一下,三种方式遍历时的特征:
preorder: root left right.
inorder: left root right
postorder: left right root
描述一个二叉树:
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
递归版(前、中、后):
class Solution {
public:
vector<int> res;
vector<int> preorderTraversal(TreeNode* root) {
if(!root) return {};
res.push_back(root->val);
preorderTraversal(root->left);
preorderTraversal(root->right);
return res;
}
};
class Solution {
public:
vector<int> res;
vector<int> inorderTraversal(TreeNode* root) {
if(!root) return {};
inorderTraversal(root->left);
res.push_back(root->val);
inorderTraversal(root->right);
return res;
}
};
class Solution {
public:
vector<int> res;
vector<int> postorderTraversal(TreeNode* root) {
if(!root) return {};
postorderTraversal(root->left);
postorderTraversal(root->right);
res.push_back(root->val);
return res;
}
};
非递归版本(前、中、后):
此时需要使用到第三方数据结构stack,利用栈来存储中间值。
因为在过程中遍历到的各个节点的顺序和其最后在res中的顺序不一致。如在中序遍历中需要先找到左子树(的最左端节点)。
class Solution {
public:
vector<int> preorderTraversal(TreeNode* root) {
if(!root) return {};
vector<int> res;
TreeNode* p = root;
stack<TreeNode*> st;
while(!st.empty() || p){
while(p){
//在左子树之前将根节点的值插入到res中取
res.push_back(p->val);
//再将左子树压栈
st.push(p);
p = p->left;
}
if(!st.empty()){ //栈非空 出栈
p = st.top();
st.pop();
p = p->right;//找其右子树
}
}
return res;
}
};
class Solution {
public:
vector<int> inorderTraversal(TreeNode* root){
if(!root) return {};
vector<int> res;
TreeNode* p = root;
stack<TreeNode*> st;
while(!st.empty() || p){
while(p){
//先将左子树压栈
st.push(p);
p = p->left;
}
if(!st.empty()){ //栈非空 出栈
p = st.top();
st.pop();
res.push_back(p->val);//此时记录数据在result中
p = p->right;
}
}
return res;
}
};
后序遍历的不同就在于,它需要先访问左右节点再访问root节点。
那么问题就在于, 从栈中弹出节点(node)之后,它是left or right?
所以我们在过程中记录一下它的前一个节点(前驱节点 preNode)即可!!!
class Solution {
public:
vector<int> postorderTraversal(TreeNode* root) {
//后序遍历的顺序 left right root
if(!root) return {};
vector<int> res;
TreeNode* p = root; //移动节点
stack<TreeNode*> st;
TreeNode* preNode = NULL; //设置一个前驱节点
while(!st.empty() || p){
while(p){
//先将左子树(的"左侧节点")压栈
st.push(p);
p = p->left;
}
if(!st.empty()){ //栈非空
p = st.top(); //取栈顶元素
if(p->right == NULL || p->right == preNode){
st.pop(); //出栈
res.push_back(p->val);
preNode = p; //更新前驱节点
p = NULL; //当前节点已经压栈 则存储它的p节点可以注释为NULL 以防止后面混乱!!!
}
else{ //继续寻找右子节点
p = p->right;
}
}
}
return res;
}
};
以上就是这篇的全部内容,有问题处烦请各位提出,谢谢!