- 先序遍历:根-左-右
//入站要先右节点在左节点
class Solution {
public:
void preorderTraversal(TreeNode* root) {
if (!root) return;
stack<TreeNode*> st; st.push(root);
while (!st.empty())
{//直接弹出,所以根节点和当前左右孩子不会同时在栈中,因此“根”总是在前面。
TreeNode* p = st.top(); st.pop();
cout << p->val << endl;
if (p->right) st.push(p->right);
if (p->left) st.push(p->left);
}
}
};
- 后序遍历:左右根;使用两个栈,第一个栈元素出栈到第二个栈。因此第二个栈:根-右-左即可,第一个栈:根-左-右,由于栈先入后出所以要先左子树后右子树。
class Solution {
public:
void postorderTraversal(TreeNode* root) {
if (!root) return;
stack<TreeNode*> st1, st2;
st.push(root);
while(!st1.empty())
{
TreeNode* top = st1.top();
st2.push(top); st1.pop();
if(top->left) st1.push(top->left);
if(top->right) st1.push(top->right);
}
//第二个栈中,根节点和当前左右孩子会同时在栈中,所以一起遵循逆序。
while(!st2.empty())
{
cout << st2.top()->val << endl;
st2.pop();
}
};
//方法二:使用一个栈.使用两个额外的节点分别记录当前节点(根节点)和上次访问的节点,对任意子树,
//左节点未访问,先访问左节点;如果上次访问左节点而没访问右节点:访问右节点;否则才访问当前节点。
class Solution {
public:
void postorderTraversal(TreeNode* root) {
if(!root) return;
TreeNode* last = NULL;
stack<TreeNode*> st; st.push(root);
while(!st.empty())
{
TreeNode* cur = st.top();
if(cur->left && cur->left != last && cur->right != last)
st.push(cur->left);
else if(cur->right && cur->right != last)
st.push(cur->right);
else{
cout << cur->val;
st.pop();
}
last = cur;
}
}
}
中序借助一个辅助节点
//先顺着左子树下去并把根节点加入栈中,直到左节点为空,从栈中拿出一个节点访问值,并沿右子树循环。
class Solution {
public:
void Traversal(TreeNode* root) {
if (!root) return;
stack<TreeNode*> st;
TreeNode* p = root;
while (!st.empty() || p)
{
if (p)
{//push_back写在这里就是先序。
st.push(p);
p = p->left;
}
else {
p = st.top(); st.pop();
cout << p->val <<endl;
p = p->right;
}
}
}
};
- 深度优先搜索(递归或非递归形式的先序、中序、后续)空间复杂度都是树的高度,即栈空间大小;时间复杂度是 O ( n ) O(n) O(n),其中n是节点数。
- 官渡优先搜索(层次遍历)空间复杂度是每层节点数的最大值,即队列大小;时间复杂度是 O ( n ) O(n) O(n)。