day13 二叉树递归遍历 迭代遍历 层序遍历

day13 | 二叉树递归遍历 迭代遍历 层序遍历

二叉树的遍历方式主要有深度优先和广度优先:

  • 深度优先有前序、中序、后序
  • 广度优先有层序遍历

深度优先就是先遍历到叶子接点再返回,一般通过递归来实现,也可以转为迭代。深度优先的遍历方式主要是以根节点顺序区分,比如前序就是根左右,中序左根右,后续左右根。广度优先一般利用队列来完成。

二叉树结点定义:

struct TreeNode {
    int val;
    TreeNode* left;
    TreeNode* right;
    TreeNode(int _val) : val(_val), left(nullptr), right(nullptr) {}
}

递归遍历

首先递归通常三步写:

  1. 确定返回值和参数
  2. 确定终止条件
  3. 确定单层递归逻辑

递归前序遍历

  1. 确定返回值和参数

    采用一个数组来记录每个结点的val值,返回值为void,参数为二叉树根节点和用来存储结果的vector

    void traverse(TreeNode* root, vector<int>& vec)

  2. 确定终止条件

    遇到空结点则返回,if (root == nulltpr) return

  3. 单层递归逻辑,前序是先处理根节点,然后递归处理左子树,递归处理右子树

vec.push_back(root->val); // 处理根节点
traverse(root->left, vec); // 递归处理左子树
traverse(root->right, vec); // 递归处理右子树

全部代码:

class Solution {
public:
    void traverse(TreeNode* root, vector<int>& vec) {
        if (root == nullptr) return;

        vec.push_back(root->val);
        traverse(root->left, vec);
        traverse(root->right, vec);
    }

    vector<int> preorderTraversal(TreeNode* root) {
        vector<int> result;
        traverse(root, result);
        return result;
    }
};

递归中序遍历

class Solution {
public:
    void traverse(TreeNode* root, vector<int>& vec) {
        if (root == nullptr) return;

        traverse(root->left, vec);
        vec.push_back(root->val);
        traverse(root->right, vec);
        
    }

    vector<int> inorderTraversal(TreeNode* root) {
        vector<int> result;
        traverse(root, result);
        return result;
    }
};

递归后序遍历

class Solution {
public:
    void traverse(TreeNode* root, vector<int>& vec) {
        if (root == nullptr) return;

        traverse(root->left, vec);
        traverse(root->right, vec);
        vec.push_back(root->val);
    }

    vector<int> postorderTraversal(TreeNode* root) {
        vector<int> result;
        traverse(root, result);
        return result;
    }
};

迭代遍历

递归遍历可以转为迭代遍历,通过栈来完成,其中前序遍历和后序遍历方式一样,因为这两种遍历方式遍历到的结点都是要处理的结点,可以直接进行处理;而中序遍历遍历到的结点不一定是要处理的结点,需要通过指针找到处理的结点,遍历过的结点用栈存起来,然后处理完一个结点后找到下一个要处理的结点。

前序遍历

遍历到每一个结点,也就是要处理的结点,将右孩子、左孩子依次入栈就能得到根左右的顺序

class Solution {
public:
    vector<int> preorderTraversal(TreeNode* root) {
        // 利用栈来存储结点的左右孩子 处理了根节点后然后出栈处理孩子
        stack<TreeNode*> st;
        vector<int> result;
        if (root != nullptr) st.push(root);

        while (!st.empty()) {
            TreeNode* cur = st.top();
            result.push_back(cur->val);
            st.pop();
            if (cur->right) st.push(cur->right);
            if (cur->left) st.push(cur->left);
        }
        return result;
    }
};

后序遍历

后序遍历可以通过前序遍历达到,后序是左右根,可以通过逆置根右左来达到,遍历到每一个结点,将左孩子右孩子依次入栈

class Solution {
public:
    vector<int> postorderTraversal(TreeNode* root) {
        // 后序迭代遍历 左右根 可以通过前序迭代遍历 来完成 需要调整一下入栈顺序 编程 根右左 最后逆置一下
        stack<TreeNode*> st;
        vector<int> result;

        if (root != nullptr) st.push(root); 

        while (!st.empty()) {
            TreeNode* cur = st.top();
            result.push_back(cur->val);
            st.pop();
            if (cur->left) st.push(cur->left);
            if (cur->right) st.push(cur->right);
        }
        reverse(result.begin(), result.end());
        return result;
    }
};

中序遍历

需要通过一个指针来找到需要处理的结点,当指针为空的时候说明遍历到了最右边,这时候应该开始处理栈顶的结点并遍历其右孩子。

class Solution {
public:
    vector<int> inorderTraversal(TreeNode* root) {
        // 还是利用栈 但是不同的是由于遍历到的元素并不一定是要处理的元素,需要存到栈中,也就是当遍历到空时还需要结合栈来
        // 进行遍历方向 遍历到空 则说明到了左边结点的孩子,这时候需要访问该结点的父节点然后有兄弟
        stack<TreeNode*> st;
        vector<int> result;

        // 利用指针来找需要处理的结点
        TreeNode* cur = root;
        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;

    }

统一迭代(暂时忽略)

层序遍历

每一次处理二叉树的一层,通过队列达到,每次处理纪录一下队列中有多少元素,把这些元素一次性处理完。处理每个元素的时候将左右孩子入队。

class Solution {
public:
    vector<vector<int>> levelOrder(TreeNode* root) {
        queue<TreeNode*> que;
        vector<vector<int>> result;

        if (root != nullptr) que.push(root);
        while (!que.empty()) {
            int size = que.size();
            vector<int> layer;
            for (int i = 0; i < size; i++) {
                TreeNode* cur = que.front();
                que.pop();
                layer.push_back(cur->val);
                if (cur->left) que.push(cur->left);
                if (cur->right) que.push(cur->right);

            }
            result.push_back(layer);
        }
        return result;
    }
};
  • 4
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值