vector<int> res;
vector<TreeNode*> tree;
if (root == NULL) return res;
TreeNode* p = root;//建立临时指针指向根节点
while (p||!tree.empty())
{
if (p)
{
tree.push_back(p);
res.push_back(p->val);
p = p->left;
}
else
{
TreeNode* x = tree.back();
tree.pop_back();
p = x->right;//当左子树没有的时候,我们就把栈顶元素弹出,并且读它的右子树
}
}
while (!tree.empty())
{
TreeNode* x = tree.back();
tree.pop_back();
res.push_back(x->val);
}
return res;
}
}
前序遍历
从根节点开始向左遍历,每一个都又输出又入栈,直到最后一个元素没有左节点。然后开始弹出栈内元素,如果栈内元素有右节点的话,就让临时指针p指向右节点,走那个往左节点遍历的循环。如果栈内元素没有右节点的话,就继续往下弹出栈内元素。
思考:为什么前序遍历会一边入栈一边输出呢?其实这就实现了根节点的先输出。为什么要先从左边这条路往下走呢?其实这就实现了左结点的先输出。为什么我们要一直遍历到左节点没有左节点为止呢,每次输出的时候有右子树右子树又要进入到这个遍历左节点到没有左节点的循环呢,其实这就是实现了递归。
#include<iostream>
#include<vector>
using namespace std;
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) {}
};
class Solution {
public:
vector<int> inorderTraversal(TreeNode* root) {//中序遍历
vector<int> res;
if (root == NULL) return res;
vector<TreeNode*> tree;
TreeNode* p = root;
while (p || !tree.empty())
{
if (p)
{
tree.push_back(p);
p = p->left;
}
else
{
TreeNode* x = tree.back();
res.push_back(x->val);
tree.pop_back();
p = x->right;
}
}
}
};
中序遍历
每次入栈的时候不输出,一直往左节点遍历直到没有左节点为止,开始弹出栈,在边弹出的时候边输出。同样也要访问右节点。
#include<iostream>
#include<vector>
using namespace std;
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) {}
};
class Solution {
public:
vector<int> inorderTraversal(TreeNode* root) {//后续遍历
vector<int> res;
if (root == NULL) return res;
vector<TreeNode*> tree;
TreeNode* p = root;
TreeNode* pre = NULL;
while (p || !tree.empty())
{
if (p)
{
tree.push_back(p);
p = p->left;
}
else
{
p = tree.back();
if (p->right == NULL || p->right == pre)//如果这个根节点没有右孩子,又或者右孩子全部遍历过了,才能输出根节点
{
res.push_back(p->val);
tree.pop_back();
pre = p;
p = NULL;
}
else
{
p = p->right;
}
}
}
return res;
}
};
后序遍历
肯定不能边入栈边输出。但是而不能直接在出栈的时候输出,那样就变成中序遍历了。这里注意我们其实是在玩当前栈的右孩子,如果没有孩子或者右孩子已经输出过了,这个时候我们才能输出,并且让p指向空继续弹出栈内元素。如果有右孩子的话,我们要送右孩子进循环。
其实都很相似(就是每次的循环的模板是一样的)。关键是要知道什么时候我们要压入栈,什么时候我们又要输出(也就是这里的res数组)。还有循环的设置问题。