代码随想录算法训练营第14天

递归遍历

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在左的后面

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值