二叉树遍历(6 道 LeetCode 题目)
Posted 超越技术
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了二叉树遍历(6 道 LeetCode 题目)相关的知识,希望对你有一定的参考价值。
Hi,大家好,我是 Lefe,目前在做图解数据结构与算法,希望用图的方式让数据结构和算法变得通俗易懂,欢迎加入一起学习。
今天通过 6 道 LeetCode 题目学习「二叉树」这种数据结构的遍历。先看一下,什么是二叉树:
每个节点最多有 2 个子节点的树。
下图是一个二叉树:
叶子节点:没子节点的节点。
数据结构定义:
struct TreeNode {
// 值
int val;
// 左子树
TreeNode *left;
// 右子树
TreeNode *right;
TreeNode(int x) : val(x), left(NULL), right(NULL) {}
};
LeetCode 上关于遍历的题目
94. Binary Tree Inorder Traversal 中序遍历
依次执行遍历左子树、访问值、遍历右子树。使用递归的方式实现,把结果保存到 vector 中:
class LEFTreeSubject {
public:
vector<int> result;
vector<int> inorderTraversal(TreeNode* root) {
// 递归出口
if (root == NULL) {
return result;
}
// 递归遍历左子树
inorderTraversal(root->left);
// 把遍历到的值保存到 result 中
result.push_back(root->val);
// 递归遍历右子树
inorderTraversal(root->right);
return result;
}
};
144. Binary Tree Preorder Traversal 前序遍历
依次执行访问值、遍历左子树、遍历右子树。使用递归的方式实现,把结果保存到 vector 中:
vector<int> preorderTraversal(TreeNode* root) {
if (root == NULL) {
return result;
}
result.push_back(root->val);
// 递归遍历左子树
preorderTraversal(root->left);
// 递归遍历右子树
preorderTraversal(root->right);
return result;
}
145. Binary Tree Postorder Traversal 后续遍历
依次执行遍历左子树、遍历右子树、访问值。使用递归的方式实现,把结果保存到 vector 中:
vector<int> postorderTraversal(TreeNode* root) {
if (root == NULL) {
return result;
}
// 递归遍历左子树
postorderTraversal(root->left);
// 递归遍历右子树
postorderTraversal(root->right);
result.push_back(root->val);
return result;
}
102. Binary Tree Level Order Traversal 层序遍历
层序遍历是一种广度优先遍历算法,一层一层进行遍历,需要借助队列。每层结束位置用 NULL 分割。
vector<vector<int>> levelOrder(TreeNode* root) {
vector<vector<int>> levelResult;
// 用来暂存数据
queue<TreeNode *> q;
if (root == NULL) {
return levelResult;
}
// 先存储根节点,每一层的结束用 NULL 分割
q.push(root);
q.push(NULL);
// 当前层的节点
vector<int> cur_vec;
while (!q.empty()) {
TreeNode *cur = q.front();
q.pop();
if (cur == NULL) {
// 一层遍历结束了
levelResult.push_back(cur_vec);
// 重置 cur_vec
cur_vec.resize(0);
if (q.size() > 0) {
// 插入层的分割
q.push(NULL);
}
} else {
cur_vec.push_back(cur->val);
// 当前节点的左右节点入队
if (cur->left) {
q.push(cur->left);
}
if (cur->right) {
q.push(cur->right);
}
}
}
return levelResult;
}
107. Binary Tree Level Order Traversal II 层序遍历,从低向上遍历
题目要求从层序遍历相反的方向遍历,也就是从底向上遍历。这道题直接把 102 道题中的第 19 行代码(投机取巧):
levelResult.push_back(cur_vec);
改为:
levelResult.insert(levelResult.begin(), cur_vec);
103. Binary Tree Zigzag Level Order Traversal 之字形层序遍历
这道题是层序遍历的扩展,它要求先向左遍历,再向右遍历,再向左遍历,再向右遍历...... 依次遍历。其实稍微对层序遍历(102)改一下就可以,增加一个标记位 isLeft 记录当前遍历的方向即可。
// 之字形遍历
vector<vector<int>> zigzagLevelOrder(TreeNode* root) {
vector<vector<int>> levelResult;
// 用来暂存数据
queue<TreeNode *> q;
if (root == NULL) {
return levelResult;
}
// 先存储根节点,每一层的结束用 NULL 分割
q.push(root);
q.push(NULL);
// 当前层的节点
vector<int> cur_vec;
bool isLeft = true;
while (!q.empty()) {
TreeNode *cur = q.front();
q.pop();
if (cur == NULL) {
// 一层遍历结束了
levelResult.push_back(cur_vec);
// 重置 cur_vec
cur_vec.resize(0);
if (q.size() > 0) {
// 插入层的分割
q.push(NULL);
isLeft = !isLeft;
}
} else {
if (isLeft) {
cur_vec.push_back(cur->val);
} else {
cur_vec.insert(cur_vec.begin(), cur->val);
}
// 当前节点的左右节点入队
if (cur->left) {
q.push(cur->left);
}
if (cur->right) {
q.push(cur->right);
}
}
}
return levelResult;
}
二叉树的遍历有前、中、后序遍历,层序遍历。其中前 3 中使用递归的方式实现比较简单,当然也可以使用非递归的方式,可以借助「栈」来实现。层序遍历使用了非递归实现,借助于队列,其实它是一种广度优先算法。
如果你对下面这种递归实现,脑补不到代码的执行顺序,比如第 6、8、9 行代码的执行顺序是什么?是执行完第 6 行,然后紧接着执行第 8行?如果你心中有疑惑,对代码执行顺序模棱两可,下一篇文章,我保证把这些问题将明白了。「图解递归」
vector<int> postorderTraversal(TreeNode* root) {
if (root == NULL) {
return result;
}
// 递归遍历左子树
postorderTraversal(root->left);
// 递归遍历右子树
postorderTraversal(root->right);
result.push_back(root->val);
return result;
}
推荐阅读:
图解数据结构和算法
以上是关于二叉树遍历(6 道 LeetCode 题目)的主要内容,如果未能解决你的问题,请参考以下文章
11道精选经典LeetCode例题让你彻底搞懂二叉树的广度优先遍历
二叉树构建与遍历-LeetCode 103108109(二叉树的构建,层次遍历)
LeetCode-面试算法经典-Java实现106-Construct Binary Tree from Inorder and Postorder Traversal(构造二叉树II)(示例(代码片