2024.3.25-26记:二叉树的遍历

二叉树的遍历

二叉树遍历大体上分为深度优先遍历(DFS)和宽度优先遍历(BFS):

深度优先遍历(DFS)

对于深度优先遍历,又可以分为前序、中序和后序遍历,对于一个二叉树,无非包括三个部分根节点、左子树和右子树,其子树也是相同组成方式。顾名思义,二叉树的前中后序遍历就是表示什么时候遍历该二叉树的根节点(包括其子树),例如对于前序遍历而言,我们先遍历根节点然后在遍历左子树,最后再遍历右子树。各个遍历方式如下所示:

前序遍历次序:–>左子树–>右子树
中序遍历次序:左子树–>–>右子树
后续遍历次序:左子树–>右子树–>

对于如下所示的树:
在这里插入图片描述

前序遍历:1,2,4,5,3,6
中序遍历:4,2,5,1,3,6
后续遍历:4,5,2,6,3,1

可以验证上述理论,对于子树也相同适用。

递归遍历

如何实现上述遍历呢,我们很容易想到递归方式,例如对于前序遍历,我们先遍历根节点,然后分别递归遍历左子树右子树。代码实现也很简单:

// 前序遍历就是在递归前处理根节点数据,这里打印数据
std::cout << root->val << std::endl;
preorderTraversal(root->left);
preorderTraversal(root->right);

同样的对于中序和后序:

inorderTraversal(root->left);
// 中序遍历就是在递归中间处理根节点数据,这里打印数据
std::cout << root->val << std::endl;
inorderTraversal(root->right);
postorderTraversal(root->left);
postorderTraversal(root->right);
// 后序遍历就是在递归后处理根节点数据,这里打印数据
std::cout << root->val << std::endl;

具体代码如下:

前序递归遍历:
class Solution {
  vector<int> preorderTraversal(TreeNode *root) {
    vector<int> res;
    preorderTraversal(root, res);
    return res;
  }
  void preorderTraversal(TreeNode *root, vector<int> &res) {
    if (!root) {
      return;
    }
    res.push_back(root->val);
    preorderTraversal(root->left, res);
    preorderTraversal(root->right, res);
  }
};
中序递归遍历
class Solution {
 public:
  vector<int> inorderTraversal(TreeNode *root) {
    vector<int> res;
    inorderTraversal(root, res);
    return res;
  }
  void inorderTraversal(TreeNode *root, vector<int> &res) {
    if (!root) {
      return;
    }
    inorderTraversal(root->left, res);
    res.push_back(root->val);
    inorderTraversal(root->right, res);
  }
};
后续递归遍历
class Solution {
 public:
  vector<int> postorderTraversal(TreeNode *root) {
    vector<int> res;
    postorderTraversal(root, res);
    return res;
  }
  void postorderTraversal(TreeNode *root, vector<int> &res) {
    if (!root) {
      return;
    }
    postorderTraversal(root->left, res);
    postorderTraversal(root->right, res);
    res.push_back(root->val);
  }
};

非递归遍历

对于非递归遍历,我们可以从递归展开中获得灵感,对于递归,如果没有到底部,之前的所有数据会一直执行压栈,只是在压栈过程中何时遍历根节点的问题。直接看代码:

前序非递归遍历
class Solution {
 public:
  vector<int> preorderTraversal(TreeNode *root) {
    vector<int> res;
    stack<TreeNode *> q;
    while (!q.empty() || root) {
      if (root) {
      	// 在压栈前遍历根节点
        res.push_back(root->val);
        q.push(root);
        root = root->left;
      } else {
        root = q.top();
        q.pop();
        root = root->right;
      }
    }
    return res;
  }
};
中序非递归遍历
class Solution {
 public:
  vector<int> inorderTraversal(TreeNode *root) {
    vector<int> res;
    stack<TreeNode *> q;
    while (!q.empty() || root) {
      if (root) {
        q.push(root);
        root = root->left;
      } else {
        root = q.top();
        q.pop();
        // 在处理右子树之前遍历
        res.push_back(root->val);
        root = root->right;
      }
    }
    return res;
  }
};
后续非递归遍历

后续遍历稍微复杂一点,这里采用先遍历:根–>右子树–>左子树的方式,然后将其结果逆序就变成了:左子树–>右子树–>根 的方式,不过逆序也可以用栈来实现

class Solution {
 public:
  vector<int> postorderTraversal(TreeNode *root) {
    vector<int> res;
    stack<TreeNode *> s1;
    while (!s1.empty() || root) {
      if (root) {
        res.push_back(root->val);
        s1.push(root);
        // 先遍历右子树
        root = root->right; 
      } else {
        root = s1.top();
        s1.pop();
        root = root->left;
      }
    }
    reverse(res.begin(), res.end());
    return res;
};

宽度优先遍历(BFS):

宽度优先遍历根据队列的方式遍历,vector中的vector为每层中遍历结果。

class Solution {
public:
    vector<vector<int>> levelOrder(TreeNode* root) {
        queue<TreeNode*> q;
        vector<vector<int>> res;
        if (!root) {
            return res;
        }
        q.push(root);
        while(!q.empty()) {
            vector<int> tmp;
            int size = q.size();
            while(size > 0) {
                TreeNode* node = q.front();
                q.pop();
                tmp.push_back(node->val);
                if (node->left){
                    q.push(node->left);
                }
                if (node->right) {
                    q.push(node->right);
                }
                size--;
            }
            res.push_back(tmp);
        }
        return res;
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值