代码随想录 | day 13 | 第六章 二叉树part01

二叉树的遍历

用栈的步骤模拟一遍前中后序遍历,关键是在cur==NULL的时候return,接着返回栈的之前保存的地址接着往下执行,详情请参考王道

  1. 首先是二叉树节点的定义
/**
 * Definition for a binary tree node.
 * 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) {}
 * };
 */
  1. 前序遍历
    前表示的是中节点在前面,一进入traversal递归就先把中节点压入vec,然后再遍历左节点,遍历到最后一个即最左下的子节点traversal(cur->left, vec);后就会cur==NULL然后return出来,此时的栈顶是traversal(cur->left, vec);接着往下执行遍历当前节点的右节点traversal(cur->right, vec),接着又会进来继续中左右的顺序,就是右子树节点的中左右顺序遍历。
class Solution {
public:
    void traversal(TreeNode* cur, vector<int>& vec)
    {
        if(cur==NULL)
        {
            return;
        }

        vec.push_back(cur->val);  //中
        traversal(cur->left, vec);  //左
        traversal(cur->right, vec);  //右
    }

    vector<int> preorderTraversal(TreeNode* root) {
        vector<int>vec;
        traversal(root,vec);
        return vec;
    }
};
  1. 中序遍历
    左中右,在一开始一直进入traversal(cur->left, vec);递归循环,直到找到了最左下的子节点,然后cur==NULL后return出来返回到cur节点(本质上为最左下的子节点,然后cur->val压入vec)
class Solution {
public:
    void traversal(TreeNode* cur, vector<int>& vec)
    {
        if(cur==NULL)
        {
            return;
        }
        traversal(cur->left, vec);
        vec.push_back(cur->val);
        traversal(cur->right, vec);
    }

    vector<int> inorderTraversal(TreeNode* root) {
        vector<int> vec;
        traversal(root, vec);
        return vec;
    }
};
  1. 后序遍历
    左右中,后代表的是中节点在第三个,递归过程和上面一致
class Solution {
public:
    void traversal(TreeNode* cur, vector<int>& vec)
    {
        if(cur==NULL)
        {
            return;
        }

        traversal(cur->left, vec);
        traversal(cur->right, vec);
        vec.push_back(cur->val);
    }

    vector<int> postorderTraversal(TreeNode* root) {
        vector<int> vec;
        traversal(root, vec);
        return vec;
    }
};

迭代遍历

前序遍历(中左右)

迭代遍历的前序遍历,卡哥后面说了,因为要访问的元素和要处理的元素顺序是一致的,都是中间节点。所以写起来比较容易,但是前序和后序就不一样了。
请添加图片描述
看动图是最直观的,就是中间节点先入栈接着出栈(顺便压入vector),出栈后判断中节点是否有左右孩子,并且先压入右孩子再压入左孩子(因为栈是后进先出的),最后加上安全判断,比如如果根节点是空的,还有用while来循环。

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();
            result.push_back(node->val);
            st.pop();
            if(node->right)
            {
                st.push(node->right);
            }
            if(node->left)
            {
                st.push(node->left);
            }
        }
        return result;
    }
};

后序遍历

再来看后序遍历,先序遍历是中左右,后序遍历是左右中,那么我们只需要调整一下先序遍历的代码顺序,就变成中右左的遍历顺序,然后在反转result数组,输出的结果顺序就是左右中了,如下图请添加图片描述

class Solution {
public:
    vector<int> postorderTraversal(TreeNode* root) {
        stack<TreeNode*>st;
        vector<int>result;
        st.push(root);

        if(root==NULL)
        {
            return result;
        }

        while(!st.empty())
        {
            TreeNode* node = st.top();
            result.push_back(node->val);
            st.pop();

            if(node->left)
            {
                st.push(node->left);
            }
            if(node->right)
            {
                st.push(node->right);
            }
        }
        reverse(result.begin(), result.end());
        return result;
    }
};

中序遍历

需要借用指针的遍历来帮助访问节点,栈则用来处理节点上的元素。
请添加图片描述
流程:

  1. cur指针一直变left孩子压入栈,压到叶子节点为止;
  2. 当栈顶出栈的时候,把cur指针变为right孩子
class Solution {
public:
    vector<int> inorderTraversal(TreeNode* root) {
        stack<TreeNode*>st;
        vector<int>result;
        TreeNode* cur = root;
        while(cur!=NULL || !st.empty())
        {
            if(cur!=NULL)
            {
                st.push(cur);
                cur = cur->left;
            }else
            {
                cur = st.top();
                st.pop();
                result.push_back(cur->val);
                cur = cur->right;
            }
        }
        return result;
    }
};

层序遍历

广度优先搜索的模板

  1. 用队列来模拟广度优先搜索的节点
  2. 先把root节点压入队列
  3. 用size变量来记录本层有多少个节点
  4. 每弹出一个节点,就往队列后面压入该节点左右孩子
    请添加图片描述
class Solution {
public:
    vector<vector<int>> levelOrder(TreeNode* root) {
        queue<TreeNode*>que;
        vector<vector<int>>result;
        if(root!=NULL)
        {
            que.push(root);
        }

        while(que.size()!=0)
        {
            int size = que.size();
            vector<int>vec;
            while(size--)
            {
                TreeNode* node = que.front();
                que.pop();
                vec.push_back(node->val);
                if(node->left)
                {
                    que.push(node->left);
                }
                if(node->right)
                {
                    que.push(node->right);
                }
            }
            result.push_back(vec);
        }
        return result;
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值