今日任务
- 二叉树理论基础
- 递归遍历
- 迭代遍历
- 统一迭代
二叉树理论基础
具体理论参考一刷时的记录或者课本上关于二叉树的讲解。
递归遍历
144. 二叉树的前序遍历
题目链接:
https://leetcode.cn/problems/binary-tree-preorder-traversal/description/
题目描述:
给你二叉树的根节点 root
,返回它节点值的 前序 **遍历。
示例 1:
输入:root = [1,null,2,3]
输出:[1,2,3]
示例 2:
输入:root = []
输出:[]
示例 3:
输入:root = [1]
输出:[1]
示例 4:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jdMLoV40-1673345046378)(null)]
输入:root = [1,2]
输出:[1,2]
示例 5:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-c3SKsIok-1673345046838)(null)]
输入:root = [1,null,2]
输出:[1,2]
提示:
- 树中节点数目在范围
[0, 100]
内 100 <= Node.val <= 100
题解代码:
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> res;
traversal(root,res);
return res;
}
};
/**
* 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) {}
* };
*/
class Solution {
public:
//一刷
void traversal(TreeNode* node, vector<int>& v){
if(node==NULL){
return;
}
v.push_back(node->val);
traversal(node->left, v);
traversal(node->right,v);
}
vector<int> preorderTraversal(TreeNode* root) {
//前序:根左右
//创建结果数组
vector<int> res;
//调用前序遍历函数
traversal(root,res);
return res;
}
};
145. 二叉树的后序遍历
题目链接:
https://leetcode.cn/problems/binary-tree-postorder-traversal/description/
题目描述:
给你一棵二叉树的根节点 root
,返回其节点值的 后序遍历 。
示例 1:
输入:root = [1,null,2,3]
输出:[3,2,1]
示例 2:
输入:root = []
输出:[]
示例 3:
输入:root = [1]
输出:[1]
提示:
- 树中节点的数目在范围
[0, 100]
内 100 <= Node.val <= 100
题解代码:
/**
* 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) {}
* };
*/
class Solution {
public:
//二刷
void postOrder(TreeNode* cur, vector<int>& vec){
//处理终止条件
if(cur == NULL){
return;
}
//处理单层递归逻辑
//后序遍历
//左右根
postOrder(cur->left,vec);
postOrder(cur->right,vec);
vec.push_back(cur->val);
}
vector<int> postorderTraversal(TreeNode* root){
vector<int> res;
postOrder(root,res);
return res;
}
//一刷
/*
void postOrder(TreeNode* node, vector<int>& v){
if(node==NULL){
return;
}
//后序遍历:左右根
postOrder(node->left,v);
postOrder(node->right,v);
v.push_back(node->val);
}
vector<int> postorderTraversal(TreeNode* root) {
vector<int> res;
postOrder(root,res);
return res;
}
*/
};
94. 二叉树的中序遍历
题目链接:
https://leetcode.cn/problems/binary-tree-inorder-traversal/description/
题目描述:
给定一个二叉树的根节点 root
,返回 它的 中序 遍历 。
示例 1:
输入:root = [1,null,2,3]
输出:[1,3,2]
示例 2:
输入:root = []
输出:[]
示例 3:
输入:root = [1]
输出:[1]
提示:
- 树中节点数目在范围
[0, 100]
内 100 <= Node.val <= 100
题解代码:
/**
* 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) {}
* };
*/
class Solution {
public:
//二刷
void inOrder(TreeNode* cur, vector<int>& vec){
//处理终止条件
if(cur == NULL){
return;
}
//处理单层递归逻辑
//中序遍历
//左根右
inOrder(cur->left,vec);
vec.push_back(cur->val);
inOrder(cur->right,vec);
}
vector<int> inorderTraversal(TreeNode* root){
vector<int> res;
inOrder(root,res);
return res;
}
//一刷
/*
void inOrder(TreeNode* node, vector<int>& v){
if(node==NULL){
return;
}
//中序:左根右
inOrder(node->left,v);
v.push_back(node->val);
inOrder(node->right,v);
}
vector<int> inorderTraversal(TreeNode* root) {
vector<int> res;
inOrder(root,res);
return res;
}
*/
};
迭代遍历
迭代法(非递归的方式)来实现二叉树的前后中序遍历。
递归的实现就是:每一次递归调用都会把函数的局部变量、参数值和返回地址等压入调用栈中,然后递归返回的时候,从栈顶弹出上一次递归的各项参数,所以这就是递归为什么可以返回上一层位置的原因。
既然我们可以用递归的方式实现二叉树的前后中序遍历。
而栈又可以来模拟递归的过程,
那么:
我们用栈也可以是实现二叉树的前后中序遍历了。
这也就是所谓的迭代遍历。
144. 二叉树的前序遍历
所谓使用迭代法实现前序遍历:
前序遍历是中左右,每次先处理的是中间节点。
那么先将根节点放入栈中,对根结点处理完后。
再将右孩子加入栈。
最后将左孩子入栈(此时栈中由左向右分别是:右孩子、左孩子)。
为什么要先加入 右孩子,再加入左孩子呢?
因为这样出栈的时候才是中左右的顺序。
题目链接:
https://leetcode.cn/problems/binary-tree-preorder-traversal/description/
题目描述:
给你二叉树的根节点 root
,返回它节点值的 前序 **遍历。
示例 1:
输入:root = [1,null,2,3]
输出:[1,2,3]
示例 2:
输入:root = []
输出:[]
示例 3:
输入:root = [1]
输出:[1]
示例 4:
输入:root = [1,2]
输出:[1,2]
示例 5:
输入:root = [1,null,2]
输出:[1,2]
提示:
- 树中节点数目在范围
[0, 100]
内 100 <= Node.val <= 100
题解代码:
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(); // 中
st.pop();
result.push_back(node->val);
if (node->right) st.push(node->right); // 右(空节点不入栈)
if (node->left) st.push(node->left); // 左(空节点不入栈)
}
return result;
}
};
145. 二叉树的后序遍历
题目链接:
https://leetcode.cn/problems/binary-tree-postorder-traversal/submissions/
题目描述:
给你一棵二叉树的根节点 root
,返回其节点值的 后序遍历 。
示例 1:
输入:root = [1,null,2,3]
输出:[3,2,1]
示例 2:
输入:root = []
输出:[]
示例 3:
输入:root = [1]
输出:[1]
提示:
- 树中节点的数目在范围
[0, 100]
内 100 <= Node.val <= 100
题解代码:
/**
* 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) {}
* };
*/
class Solution {
public:
//迭代法
vector<int> postorderTraversal(TreeNode* root){
vector<int> res;
if(root == NULL){
return res;
}
stack<TreeNode*> st;
st.push(root);
while(!st.empty()){
TreeNode* node = st.top();
st.pop();
res.push_back(node->val);
if(node->left){
st.push(node->left);
}
if(node->right){
st.push(node->right);
}
//这样出来就是中右左的顺序
//左先入栈,所以会后出栈
}
reverse(res.begin(),res.end());
return res;
}
};
94. 二叉树的中序遍历
在使用迭代法写中序遍历,就需要借用指针的遍历来帮助访问节点,栈则用来处理节点上的元素。
动画如下:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jMZCuDH2-1673345042436)(https://programmercarl.com/%E4%BA%8C%E5%8F%89%E6%A0%91%E7%9A%84%E8%BF%AD%E4%BB%A3%E9%81%8D%E5%8E%86.html#%E4%B8%AD%E5%BA%8F%E9%81%8D%E5%8E%86-%E8%BF%AD%E4%BB%A3%E6%B3%95)]](https://code-thinking.cdn.bcebos.com/gifs/%E4%BA%8C%E5%8F%89%E6%A0%91%E4%B8%AD%E5%BA%8F%E9%81%8D%E5%8E%86%EF%BC%88%E8%BF%AD%E4%BB%A3%E6%B3%95%EF%BC%89.gif)
https://programmercarl.com/二叉树的迭代遍历.html#中序遍历-迭代法
题目链接:
https://leetcode.cn/problems/binary-tree-inorder-traversal/description/
题目描述:
给定一个二叉树的根节点 root
,返回 它的 中序 遍历 。
示例 1:
输入:root = [1,null,2,3]
输出:[1,3,2]
示例 2:
输入:root = []
输出:[]
示例 3:
输入:root = [1]
输出:[1]
提示:
- 树中节点数目在范围
[0, 100]
内 100 <= Node.val <= 100
题解代码:
/**
* 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) {}
* };
*/
class Solution {
public:
//迭代法
vector<int> inorderTraversal(TreeNode* root){
vector<int> res;
stack<TreeNode*> st;
TreeNode* cur = root;
while(cur != NULL || !st.empty()){
if(cur != NULL){
st.push(cur);
cur = cur->left; //左
}
else{
cur = st.top();
st.pop();
res.push_back(cur->val);//中
cur = cur->right; //右
}
}
return res;
}
};
统一迭代
所谓统一迭代:
即用像模板一样的方式写出具有统一风格的代码,
由这些代码来完成二叉树的前中后序遍历。
emmm,二刷就先学懂递归法和简单迭代吧,统一迭代代码的写法,之后有机会三刷再看吧。
总结
递归三部曲 .🎆
- 确定递归函数的参数和返回值【确定哪些参数是递归的过程中需要处理的,那么就在递归函数里加上这个参数, 并且还要明确每次递归的返回值是什么进而确定递归函数的返回类型。】
- 确定递归的终止条件
- 确定单层递归的逻辑【 确定每一层递归需要处理的信息。在这里也就会重复调用自己来实现递归的过程。】
递归遍历. 💫
- 前序遍历:根左右
- 后序遍历:左右根
- 中序遍历:左根右
C++ reverse函数的用法. 💝
逆序(反转)无论是在C或是C++中用的都特别多,常用于数组,字符串,容器等,其本身的函数参数也不复杂。
标准C中是没有recerse()函数的,这是C++的一个新增函数,使用需要包含头文件
#include <algorithm>
reverse函数用于反转在[first,last)范围内的顺序(包括first指向的元素,不包括last指向的元素),reverse函数没有返回值
template <class BidirectionalIterator>
void reverse (BidirectionalIterator first,BidirectionalIterator last);
例如,交换vector容器中元素的顺序
vector<int> v = {5,4,3,2,1};
reverse(v.begin(),v.end());//v的值为1,2,3,4,5