二叉树
理论基础
- 次序关系 前中后序 ( VLR, LVR, LRV )
VLR: 前表示根节点在前面,遍历顺序即中左右
LVR: 中表示根节点在中间,遍历顺序即左中右
LRV: 后表示根节点在后面,遍历顺序即左右中
- 遍历方式
DFS (深度优先遍历)- 先往深处走,遇到叶子节点再往回走 :前中后序遍历
BFS(广度优先遍历)- 一层一层遍历:层次遍历
- 二叉树节点构造
struct TreeNode{
int val;
TreeNode left;
TreeNode right;
TreeNode (int x): val(x), left(NULL), right(NULL);
}
一、递归遍历
1. 前序遍历
给你二叉树的根节点 root
,返回它节点值的 前序 遍历。
题解
class Solution {
public:
void traverse(TreeNode * cur, vector<int> &result){
if(cur == nullptr) return;
result.push_back(cur->val);
traverse(cur->left, result);
traverse(cur->right, result);
}
vector<int> preorderTraversal(TreeNode* root) {
vector<int> result;
traverse(root, result);
return result;
}
};
2. 后序遍历
给你二叉树的根节点 root
,返回它节点值的 后序 遍历。
题解
class Solution {
public:
void traverse(TreeNode * cur, vector<int> &result){
if(cur == nullptr) return;
traverse(cur->left, result);
traverse(cur->right, result);
result.push_back(cur->val);
}
vector<int> postorderTraversal(TreeNode* root) {
vector<int> result;
traverse(root, result);
return result;
}
};
3. 中序遍历
给你二叉树的根节点 root
,返回它节点值的 中序 遍历。
题解
class Solution {
public:
void traverse(TreeNode * cur, vector<int> &result){
if(cur == nullptr){
return ;
}
traverse(cur->left, result);
result.push_back(cur->val);
traverse(cur->right, result);
}
vector<int> inorderTraversal(TreeNode* root) {
vector<int> result;
traverse(root, result);
return result;
}
};
二、非递归遍历
知识点
- 非递归使用栈,先进后出
1. 前序遍历
给你二叉树的根节点 root
,返回它节点值的 前序 遍历。
题解
class Solution {
public:
vector<int> preorderTraversal(TreeNode* root) {
stack<TreeNode*> stk;
vector<int> result;
if (root == nullptr) return result;
stk.push(root);
while(!stk.empty()){
TreeNode *tmp = stk.top();
stk.pop();
if(tmp != nullptr) result.push_back(tmp->val); // 中
else continue;
stk.push(tmp->right); // 右
stk.push(tmp->left); // 左
}
return result;
}
};
2. 后序遍历
给你二叉树的根节点 root
,返回它节点值的 后序 遍历。
与前序遍历相似,前序遍历非递归是中右左
修改右左位置为左右,那么就是中左右,再反转成为右左中
题解
class Solution {
public:
vector<int> postorderTraversal(TreeNode* root) {
stack<TreeNode*> stk;
vector<int> result;
if(root == nullptr) return result;
stk.push(root);
while(!stk.empty()){
TreeNode *tmp = stk.top();
stk.pop();
if(tmp != nullptr) result.push_back(tmp->val);
else continue;
stk.push(tmp->left);
stk.push(tmp->right);
}
reverse(result.begin(), result.end());// 没有返回值,直接修改原容器
return result;
}
};
3. 中序遍历
给你二叉树的根节点 root
,返回它节点值的 中序 遍历。
题解
class Solution {
public:
vector<int> inorderTraversal(TreeNode* root) {
stack<TreeNode*> stk;
vector<int> result;
TreeNode *cur = root;
while(cur != nullptr || !stk.empty()){
if(cur != nullptr){
stk.push(cur);
cur = cur->left;
}else{
cur = stk.top();
stk.pop();
result.push_back(cur->val);
cur = cur->right;
}
}
return result;
}
};
三、二叉树层序遍历
知识点
- 使用一个队列来存储每一次遍历的元素,size的设置则是记录当前层有多少个元素
- 使用一维数组记录每一层的元素,使用二维数组来记录整棵树
1. 二叉树层次遍历
class Solution {
public:
vector<vector<int>> levelOrder(TreeNode* root) {
queue<TreeNode*> q;
vector<vector<int>> result;
if(root == nullptr) return result;
q.push(root);
while(!q.empty()){
int size = q.size();
vector<int> vec;
while(size--){
TreeNode *node = q.front();
q.pop();
vec.push_back(node->val);
if(node->left) q.push(node->left);
if(node->right) q.push(node->right);
}
result.push_back(vec);
}
return result;
}
};
2. 二叉树层次遍历II
107. 二叉树的层序遍历 II - 力扣(LeetCode)
class Solution {
public:
vector<vector<int>> levelOrderBottom(TreeNode* root) {
vector<vector<int>> result;
queue<TreeNode*> q;
if(root == nullptr) return result;
q.push(root);
while(!q.empty()){
vector<int> vec;
int size = q.size();
while(size--){
TreeNode * node = q.front();
q.pop();
vec.push_back(node->val);
if(node->left) q.push(node->left);
if(node->right) q.push(node->right);
}
result.push_back(vec);
}
reverse(result.begin(), result.end());
return result;
}
};
3. 二叉树的右视图
给定一个二叉树的 根节点 root
,想象自己站在它的右侧,按照从顶部到底部的顺序,返回从右侧所能看到的节点值。
class Solution {
public:
vector<int> rightSideView(TreeNode* root) {
queue<TreeNode*> q;
vector<int>result;
if(root == nullptr) return result;
q.push(root);
while(!q.empty()){
int size = q.size();
vector<int> vec;
while(size--){
TreeNode *node = q.front();
q.pop();
vec.push_back(node->val);
if(node->left) q.push(node->left);
if(node->right) q.push(node->right);
}
result.push_back(vec.back());
}
return result;
}
};
四、翻转二叉树
题目
给你一棵二叉树的根节点 root
,翻转这棵二叉树,并返回其根节点。
递归三步走:
- 确定递归函数的参数和返回值
参数就是传入的指针,返回根据题目要求是root节点
- 确定终止条件
节点为空则返回
- 单层递归逻辑
前序遍历和后序遍历都可以
题解
class Solution {
public:
TreeNode* invertTree(TreeNode* root) {
// 根节点为空
if(root == nullptr) return root;
// 迭代
swap(root->right, root->left);
invertTree(root->left);
invertTree(root->right);
return root;
}
};