一、二叉树的前序遍历
给你二叉树的根节点
root
,返回它节点值的 前序 遍历。
思路:
结合前序遍历的性质(头左右)可知,需要容器存储已经遍历过的节点以便于找到后面的节点,并结合遍历的顺序可知需要不断记录左再遍历左的左。而这一特征与栈的后进先出(接收左后,先加入右再加入左,一直保持左后进先出)的性质一致
利用栈实现:
- 初始:将root加入stk中
- cycle直到stk为空:记录top的值后弹出,并按先右后左的顺序压入子节点
代码:
class Solution {
public:
vector<int> preorderTraversal(TreeNode* root) {
vector<int> ret;
if(root==nullptr) return ret;
stack<TreeNode*> stk;
stk.push(root);
TreeNode* head=root;
while(stk.size()){
head=stk.top();
ret.push_back(head->val);
stk.pop();
if(head->right){
stk.push(head->right);
}
if(head->left){
stk.push(head->left);
}
}
return ret;
}
};
二、二叉树的中序遍历
给你二叉树的根节点
root
,返回它节点值的 中序 遍历。
思路:
结合前序遍历的性质(左头右)可知,需要不断找到子树的最左后回到父节点找到右子树的最左节点,需要容器存储已经遍历过的节点以便于找到后面的节点,而栈的性质(后进先出)正好满足这一特点
利用栈实现:
- 初始:stk为空,
- cycle直到stk为空并且cur为空指针:不断cur的左边界压入stk中直到遇到空,将top的值插入到vec中后pop,走向右子树
代码:
class Solution {
public:
vector<int> inorderTraversal(TreeNode* root) {
vector<int> vec;
if (!root)
return vec;
stack<TreeNode*> stk;
TreeNode* cur = root;
while (cur||stk.size()) {
while (cur) {
stk.push(cur);
cur = cur->left;
}
cur = stk.top();
stk.pop();
vec.push_back(cur->val);
cur = cur->right;
}
return vec;
}
};
三、二叉树的后序遍历
给你二叉树的根节点
root
,返回它节点值的 后序遍历。
思路:
结合前序遍历的顺序(头左右),将其改为头右左后将vec反转
代码:
class Solution {
public:
vector<int> postorderTraversal(TreeNode* root) {
vector<int> vec;
if(!root)return vec;
stack<TreeNode*> stk;
stk.push(root);
TreeNode* cur;
while(stk.size()){
cur=stk.top();
vec.push_back(cur->val);
stk.pop();
if(cur->left){
stk.push(cur->left);
}
if(cur->right){
stk.push(cur->right);
}
}
reverse(vec.begin(),vec.end());
return vec;
}
};
优化思路:
后序遍历顺序:左右头;
分析前序遍历的方式,走完头再遍历左右(头弹出再进右左);那么后序遍历是否可以模仿前序遍历,走完左右回到头?
确认遍历完左:
- 从头不断向左走直到遇到空
从top向右走,确认遍历完右:
- 若右为空,说明右已经遍历完右需要回到头;
- 若右非空说明需要从左右头的顺序遍历完右。但如何确定右已经遍历完,而不导致循环地将右子树按左右头的顺序遍历?记录上次走过的节点pre。
- 若pre==top->right,说明右已经遍历完右需要回到头;
确认回到头:
- 遍历完左右后通过top回到头并在记录后弹出
优化代码:
class Solution {
public:
vector<int> postorderTraversal(TreeNode* root) {
vector<int> vec;
if (!root)
return vec;
stack<TreeNode*> stk;
TreeNode* cur = root,*pre;
while (cur||stk.size()) {
//走左
while (cur) {
stk.push(cur);
pre=cur;
cur = cur->left;
}
//走右
while (stk.size()) {
cur = stk.top()->right;
//走完了右
if (!cur||cur==pre) {
pre=stk.top();
vec.push_back(stk.top()->val);
stk.pop();
//节点走完了
if(stk.size()==0)cur=nullptr;
}else break;
}
}
return vec;
}
};