递归遍历
class Solution {
public:
vector<int> result;
void preorder(TreeNode* root,vector<int> &res){
if(!root)return ;
res.push_back(root->val);
preorder(root->left,res);
preorder(root->right,res);
}
vector<int> preorderTraversal(TreeNode* root) {
preorder(root,result);
return result;
}
};
对我来说还比较简单,我自己自学了二叉树的相关知识,比较简单。
迭代遍历
前序遍历
class Solution {
public:
vector<int> preorderTraversal(TreeNode* root) {
stack<TreeNode*> st;
vector<int> result;
if (root == NULL) return result;
st.push(root);
while (!st.empty()) {
TreeNode* node = st.top(); // 中
st.pop();
result.push_back(node->val);
if (node->right) st.push(node->right); // 右(空节点不入栈)
if (node->left) st.push(node->left); // 左(空节点不入栈)
}
return result;
}
};
前序这个思路用了栈的思想,看卡哥思路即可。
中序遍历
class Solution {
public:
vector<int> inorderTraversal(TreeNode* root) {
vector<int> res;
stack<TreeNode*> st;
TreeNode* curr=root;
if(root==NULL)return res;
while(curr || !st.empty()){
if(curr){
st.push(curr);
curr=curr->left;
}
else{
curr=st.top();
res.push_back(curr->val);
curr=curr->right;
st.pop();
}
}
return res;
}
};
这个思路真有点想不出来,但是代码看得懂,总体还是用了递归的思想,先遍历到最左边的结点,再开始处理依次添加到数组中。
对每一个要处理的结点,先判断是否到达了该结点所在子树的最左端结点,若没有,先遍历到最左端结点。
若已经到达最左端结点,则再进入else
条件,添加进数组,并令curr=st.top(); curr=curr->right
,这两步将curr
变成了最左端结点父结点的右节点,便于下一步判断。
后序遍历
class Solution {
public:
vector<int> postorderTraversal(TreeNode* root) {
vector<int> res;
stack<TreeNode*> st;
if(!root)return res;
st.push(root);
while(!st.empty()){
TreeNode* node=st.top();
st.pop();
res.push_back(node->val);
if(node->left)st.push(node->left);
if(node->right)st.push(node->right);
}
reverse(res.begin(),res.end());
return res;
}
};
这个思路是把前序结果倒转,前序懂了这个就比较简单
统一迭代法
中序遍历
class Solution {
public:
vector<int> inorderTraversal(TreeNode* root) {
vector<int> res;
stack<TreeNode*> st;
if(root==NULL)return res;
st.push(root);
while(st.empty()!=true){
TreeNode* node=st.top();
if(node!=NULL){
st.pop();
if(node->right)st.push(node->right);
st.push(node);
st.push(NULL);
if(node->left)st.push(node->left);
}
else{
st.pop();
res.push_back(st.top()->val);
st.pop();
}
}
return res;
}
};
整体思路:先添加右子节点,再添加父结点,加一个null作为标记。
如果遇到null,说明对元素要进行处理,此时将null弹出,并添加该元素入数组res
如果node不为null,说明还可以对当前元素进行下一步遍历,如对右子节点,可以继续遍历以右子节点为根结点的右子树。
前序遍历
class Solution {
public:
vector<int> preorderTraversal(TreeNode* root) {
vector<int> result;
stack<TreeNode*> st;
if (root != NULL) st.push(root);
while (!st.empty()) {
TreeNode* node = st.top();
if (node != NULL) {
st.pop();
if (node->right) st.push(node->right); // 右
if (node->left) st.push(node->left); // 左
st.push(node); // 中
st.push(NULL);
} else {
st.pop();
node = st.top();
st.pop();
result.push_back(node->val);
}
}
return result;
}
};
前序遍历顺序为中左右,所以入栈时反过来变成右左中,添加中结点后入栈一个null作为标记。
每次先遇到null,将中结点加入数组res,然后对左右子节点依次遍历,也是递归的思想,太神奇了我测。
后序遍历
class Solution {
public:
vector<int> postorderTraversal(TreeNode* root) {
vector<int> result;
stack<TreeNode*> st;
if (root != NULL) st.push(root);
while (!st.empty()) {
TreeNode* node = st.top();
if (node != NULL) {
st.pop();
st.push(node); // 中
st.push(NULL);
if (node->right) st.push(node->right); // 右
if (node->left) st.push(node->left); // 左
} else {
st.pop();
node = st.top();
st.pop();
result.push_back(node->val);
}
}
return result;
}
};
对比(重点理解):
对比:
中序:6 5 null 2 4 null 1
前序:6 4 5 null
对4左子树:2 1 4 null
后序:5 null 6 4 null 2 1
做标记null具体要设置在哪个位置,我有了点想法,卡哥思路里说把要处理的节点放入栈之后,紧接着放入一个空指针作为标记。
要搞清楚什么时候我们要处理结点,处理的意思应该就是将结点放入数组中。
中序:左,中,右,null在左的后面,5是根结点,可以视作左节点
前序:中,左,右,null在中的后面
后序:左,右,中,null在左的后面