代码随想录第十四天 144 二叉树的前序遍历 94 二叉树的中序遍历 145 二叉树的后序遍历 二叉树的统一迭代

文章详细介绍了二叉树的前序、中序和后序遍历的递归实现以及迭代方法,强调了迭代中使用栈的技巧和不同遍历方式的处理逻辑,特别提到了统一迭代法中利用空节点标记的技巧。
摘要由CSDN通过智能技术生成

一 144 二叉树的前序遍历

递归遍历二叉树就是用系统栈来保存上一层递归需要用到的参数,采用迭代法就是用我们自定义的栈模拟这个过程,需要注意的是入栈时先将右孩子入栈,再将左孩子入栈,这是为了保证出栈的顺序。

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;
    }
};

二 94 二叉树的中序遍历

栈里使我们访问过的元素,先一路向左加入栈中,直至空节点,弹出栈中元素,将其右结点加

将左孩子加入栈中,若左孩子为空,弹出栈中元素,访问该元素的左孩子,访问该元素,再将其右孩子加入栈中

class Solution {
public:
    vector<int> inorderTraversal(TreeNode* root) {
        vector<int> result;
        //指针用于遍历各个结点,以便输出值
        TreeNode* cur = root;
        //栈用于保存访问过的结点,以便指针返回
        stack<TreeNode*> st;
        //cur为空且栈为空时整个遍历才结束
        while(cur != nullptr|| !st.empty()){
            if(cur != nullptr){
                st.push(cur);
                cur = cur->left;
            }
            else{
                cur = st.top(); //这是从栈里弹出的数据,也是要处理的数据
                st.pop();
                result.push_back(cur->val);
                cur = cur->right; 
            }
        }

        return result;


    }
};

三 145 二叉树的后序遍历

将前序遍历的中左右,改变下左右入栈的顺序,变成中右左,再将其反转就变成后序遍历的左右中了。

class Solution {
public:
    vector<int> postorderTraversal(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->left) st.push(node->left); // 相对于前序遍历,这更改一下入栈顺序 (空节点不入栈)
            if (node->right) st.push(node->right); // 空节点不入栈
        }
        reverse(result.begin(), result.end()); // 将结果反转之后就是左右中的顺序了
        return result;
    }
};

四 二叉树的统一迭代

统一迭代的核心思想是,将访问的节点放入栈中,把要处理的节点也放入栈中但是要做标记,标记的方法就是就是要处理的节点放入栈之后,紧接着放入一个空指针作为标记。 三种遍历方式只是相差了几行代码的顺序。

//中序遍历
class Solution {
public:
    vector<int> inorderTraversal(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);  // 添加右节点(空节点不入栈)

                st.push(node);                          // 添加中节点
                st.push(NULL); // 中节点访问过,但是还没有处理,加入空节点做为标记。

                if (node->left) st.push(node->left);    // 添加左节点(空节点不入栈)
            } else { // 栈顶是空节点,此时将下一个节点放进结果集
                st.pop();           // 空节点弹出
                node = st.top();    // 重新取出栈中元素
                st.pop();
                result.push_back(node->val); // 加入到结果集
            }
        }
        return result;
    }
};
//前序遍历
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;
    }
};
//后序遍历
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;
    }
};

五 总结

  1. 二叉树递归需要注意三点:返回值和参数、终止条件、单层递归的处理逻辑
  2. 先序遍历的迭代法由于访问顺序和遍历输出的顺序相同,所以简单;中序由于两个顺序不同,因此需要指针进行遍历输出,栈用于存储访问过的节点。而统一迭代法采用空节点进行标记,处理逻辑类似,只是相差代码的顺序。
  • 7
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值