目录
深度遍历DFS
题目链接:144. 二叉树的前序遍历 - 力扣(LeetCode)
题目链接:94. 二叉树的中序遍历 - 力扣(LeetCode)
题目链接:145. 二叉树的后序遍历 - 力扣(LeetCode)
题目链接:589. N 叉树的前序遍历 - 力扣(LeetCode)
题目链接:590. N 叉树的后序遍历 - 力扣(LeetCode)
广度遍历BFS
题目链接:102. 二叉树的层序遍历 - 力扣(LeetCode)
题目链接:107. 二叉树的层序遍历 II - 力扣(LeetCode)
题目链接:199. 二叉树的右视图 - 力扣(LeetCode)
题目链接:637. 二叉树的层平均值 题解 - 力扣(LeetCode)
题目链接:429. N 叉树的层序遍历 - 力扣(LeetCode)
题目链接:515. 在每个树行中找最大值 - 力扣(LeetCode)
题目链接:116. 填充每个节点的下一个右侧节点指针 - 力扣(LeetCode)
题目链接:117. 填充每个节点的下一个右侧节点指针 II - 力扣(LeetCode)
题目链接:104. 二叉树的最大深度 - 力扣(LeetCode)
题目链接:111. 二叉树的最小深度 - 力扣(LeetCode)
二叉树的遍历方式
1.深度优先遍历
- 前序遍历:根左右
- 中序遍历:左根右
- 后序遍历:左右根
2.广度优先遍历
- 层次遍历
题目链接:144. 二叉树的前序遍历 - 力扣(LeetCode)
class Solution{//前序遍历递归
public:
vector<int> preorderTraversal(TreeNode *root){
vector<int> res;
travel(root,res);
return res;
}
private:
void travel(TreeNode *cur, vector<int> &res){
if(cur==NULL) return;
res.push_back(cur->val);//根
travel(cur->left,res);//左
travel(cur->right,res);//右
}
};
class Solution {//前序遍历迭代
public:
vector<int> preorderTraversal(TreeNode* root) {
vector<int> res;
stack<TreeNode*> st;
if(root==NULL) return res;
TreeNode *cur=root;
st.push(root);//将根结点压入栈中
while(!st.empty()){//当栈不为空时,表明其中还有结点未遍历
//首先将每棵子树的根节点pop并压入res数组
TreeNode *node=st.top();
st.pop();
res.push_back(node->val); //根
//先右后左,这样pop出来就是先左后右
//如果右子树不为空,将右子树根节点压入栈中
if(node->right) st.push(node->right); //右
//如果左子树不为空,将左子树根节点压入栈中
if(node->left) st.push(node->left); //左
}
return res;
}
};
class Solution {//前序遍历统一迭代
public:
vector<int> preorderTraversal(TreeNode* root) {
vector<int> res;
if(root==NULL) return res;
stack<TreeNode*> st;
st.push(root);
while(!st.empty()){
//将栈顶结点取出
TreeNode *cur=st.top();st.pop();
if(cur!=NULL){//如果栈顶结点不为空
//重新按照倒序向栈中压入该结点及其孩子
if(cur->right) st.push(cur->right);//右
if(cur->left) st.push(cur->left); //左
st.push(cur); //根
st.push(NULL);//NULL用来标记根结点所在位置
}
else{//如果栈顶结点为空,则要处理根节点,即其上一个结点
cur=st.top();st.pop();
res.push_back(cur->val);
}
}
return res;
}
};
题目链接:94. 二叉树的中序遍历 - 力扣(LeetCode)
class Solution {//中序遍历递归
public:
vector<int> inorderTraversal(TreeNode* root) {
vector<int> res;
if(root==NULL) return res;
traversal(root,res);
return res;
}
private:
void traversal(TreeNode *cur,vector<int> &res){
if(cur==NULL) return ;
traversal(cur->left,res); //左
res.push_back(cur->val); //根
traversal(cur->right,res); //右
}
};
class Solution {//中序遍历迭代
public:
vector<int> inorderTraversal(TreeNode* root) {
vector<int> res;
if(root==NULL) return 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;
}
};
class Solution {//统一迭代
public:
vector<int> inorderTraversal(TreeNode* root) {
vector<int> res;
stack<TreeNode*> st;
if(root!=NULL) st.push(root);
TreeNode *cur=root;
while(!st.empty()){
TreeNode *cur=st.top();
if(cur!=NULL){
st.pop();//虽然之前将根节点push进栈,但处理结点顺序时将根节点pop出来,再按照前序/中序/后序将结点push进栈
if(cur->right) st.push(cur->right);//右
st.push(cur);//根
st.push(NULL);//根节点访问过但还没处理,加入空结点作为标记
if(cur->left) st.push(cur->left);//左
}else{
st.pop();//先把NULLpop出来
cur=st.top();
st.pop();
res.push_back(cur->val);//按照push顺序处理结点
}
}
return res;
}
};
题目链接:145. 二叉树的后序遍历 - 力扣(LeetCode)
class Solution {//后序遍历递归
public:
vector<int> postorderTraversal(TreeNode* root) {
vector<int> res;
if(root==NULL) return res;
traversal(root,res);
return res;
}
private:
void traversal(TreeNode *cur,vector<int> &res){
if(cur==NULL) return ;
traversal(cur->left,res);
traversal(cur->right,res);
res.push_back(cur->val);
}
};
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;
}
};
class Solution {//后序遍历统一迭代
public:
vector<int> postorderTraversal(TreeNode* root) {
vector<int> res;
stack<TreeNode*> st;
if(root!=NULL) st.push(root);
while(!st.empty()){
TreeNode *cur=st.top();
if(cur!=NULL){
st.pop();
st.push(cur);//根
st.push(NULL);//虽然根已经刚问过但还没有处理,push空结点作为标记
if(cur->right) st.push(cur->right);//右
if(cur->left) st.push(cur->left);//左
}
else{
st.pop();//pop出NULL
cur=st.top();
st.pop();
res.push_back(cur->val);
}
}
return res;
}
};
题目链接:589. N 叉树的前序遍历 - 力扣(LeetCode)
class Solution {//递归
public:
vector<int> preorder(Node* root) {
vector<int> res;
if(root==NULL) return res;
travel(root,res);
return res;
}
private:
void travel(Node* root,vector<int> &res){
res.push_back(root->val);
//由上面Node的定义可知,children是一个vector<Node*>数组
for(int i=0;i<root->children.size();i++)
{
travel(root->children[i],res);
}
}
};
class Solution {//迭代
public:
vector<int> preorder(Node* root) {
vector<int> res;
if(root==NULL) return res;
stack<Node*> st;
st.push(root);
while(!st.empty()){
Node *node=st.top();
st.pop();
res.push_back(node->val);
for(int i=node->children.size()-1;i>=0;i--)
{
st.push(node->children[i]);
}
}
return res;
}
};
题目链接:590. N 叉树的后序遍历 - 力扣(LeetCode)
class Solution {//递归
public:
vector<int> postorder(Node* root) {
vector<int> res;
if(root==NULL) return res;
order(root,res);
return res;
}
private:
void order(Node *cur,vector<int> &res){
if(cur==NULL) return ;
for(int i=0;i<cur->children.size();i++){
order(cur->children[i],res);
}
res.push_back(cur->val);
}
};
class Solution {//迭代
public:
vector<int> postorder(Node* root) {
vector<int> res;
if(root==NULL) return res;
stack<Node*> st;
st.push(root);
while(!st.empty()){
Node *cur=st.top();
st.pop();
//在N叉树的前序遍历中,children是倒序push的
for(int i=0;i<cur->children.size();i++){
st.push(cur->children[i]);
}
res.push_back(cur->val);
}
//N叉树的后序遍历要反转
reverse(res.begin(),res.end());
return res;
}
};
题目链接:102. 二叉树的层序遍历 - 力扣(LeetCode)
class Solution {//迭代
public:
vector<vector<int>> levelOrder(TreeNode* root) {
//辅助队列
queue<TreeNode*> q;
//每一层形成一个数组
vector<vector<int>> res;
if(root!=NULL) q.push(root);
while(!q.empty())
{
//记录每一层的结点数
int size=q.size();
vector<int> r;
for(int i=0;i<size;i++)
{
TreeNode *cur=q.front();
//如果该结点有左右孩子就压入队列
if(cur->left) q.push(cur->left);
if(cur->right) q.push(cur->right);
r.push_back(cur->val);
q.pop();
}
res.push_back(r);
}
return res;
}
};
class Solution {//递归
public:
vector<vector<int>> levelOrder(TreeNode* root) {
vector<vector<int>> res;
int depth=0;
order(root,res,depth);
return res;
}
private:
void order(TreeNode *cur,vector<vector<int>> &res,int depth){
if(cur==NULL) return;
//如果res目前的数组数==depth,则需要新建一层数组
if(res.size()==depth) res.push_back(vector<int>());
res[depth].push_back(cur->val);
order(cur->left,res,depth+1);
order(cur->right,res,depth+1);
}
};
题目链接:107. 二叉树的层序遍历 II - 力扣(LeetCode)
class Solution {
public:
vector<vector<int>> levelOrderBottom(TreeNode* root) {
queue<TreeNode*> q;
vector<vector<int>> res;
if(root!=NULL) q.push(root);
while(!q.empty()){
int size=q.size();
vector<int> r;
for(int i=0;i<size;i++){
TreeNode *cur=q.front();
r.push_back(cur->val);
if(cur->left) q.push(cur->left);
if(cur->right) q.push(cur->right);
q.pop();
}
res.push_back(r);
}
//反转层次遍历数组
reverse(res.begin(),res.end());
return res;
}
};
题目链接:199. 二叉树的右视图 - 力扣(LeetCode)
class Solution {
public:
vector<int> rightSideView(TreeNode* root) {
queue<TreeNode*> q;
vector<int> res;
if(root!=NULL) q.push(root);
while(!q.empty())
{
int size=q.size();
for(int i=0;i<size;i++){
TreeNode *cur=q.front();
if(cur->left) q.push(cur->left);
if(cur->right) q.push(cur->right);
q.pop();
//取每层最后一个结点
if(i==size-1) res.push_back(cur->val);
}
}
return res;
}
};
题目链接:637. 二叉树的层平均值 题解 - 力扣(LeetCode)
class Solution {
public:
vector<double> averageOfLevels(TreeNode* root) {
//层次遍历并计算每层平均值
vector<double> res;
queue<TreeNode*> q;
if(root!=NULL) q.push(root);
while(!q.empty()){
int size=q.size();
double sum=0;
for(int i=0;i<size;i++){
TreeNode *cur=q.front();
q.pop();
sum+=cur->val;
if(cur->left) q.push(cur->left);
if(cur->right) q.push(cur->right);
}
res.push_back(sum/size);
}
return res;
}
};
题目链接:429. N 叉树的层序遍历 - 力扣(LeetCode)
class Solution {//迭代
public:
vector<vector<int>> levelOrder(Node* root) {
vector<vector<int>> res;
queue<Node*> q;
if(root!=NULL) q.push(root);
while(!q.empty()){
int size=q.size();
vector<int> r;
for(int i=0;i<size;i++)
{
Node *cur=q.front();
q.pop();
r.push_back(cur->val);
for(int j=0;j<cur->children.size();j++){
q.push(cur->children[j]);
}
}
res.push_back(r);
}
return res;
}
};
题目链接:515. 在每个树行中找最大值 - 力扣(LeetCode)
class Solution {
public:
vector<int> largestValues(TreeNode* root) {
vector<int> res;
queue<TreeNode*> q;
if(root!=NULL) q.push(root);
while(!q.empty()){
int size=q.size();
int max=INT_MIN;
for(int i=0;i<size;i++){
TreeNode *cur=q.front();
q.pop();
if(cur->val>max) max=cur->val;
if(cur->left) q.push(cur->left);
if(cur->right) q.push(cur->right);
}
res.push_back(max);
}
return res;
}
};
题目链接:116. 填充每个节点的下一个右侧节点指针 - 力扣(LeetCode)
class Solution {
public:
Node* connect(Node* root) {
queue<Node*> q;
if(root!=NULL) q.push(root);
while(!q.empty()){
int size=q.size();
for(int i=0;i<size;i++){
Node *cur=q.front();
q.pop();
//当cur指向每层最后一个结点时,令其next指向NULL,否则指向该层下一个结点
if(i==size-1) cur->next=NULL;
else cur->next=q.front();
if(cur->left) q.push(cur->left);
if(cur->right) q.push(cur->right);
}
}
return root;
}
};
题目链接:117. 填充每个节点的下一个右侧节点指针 II - 力扣(LeetCode)
//当父结点不为空时
//如果父结点cur有左孩子
//如果temp为空,则说明当前结点cur->left是该层第一个结点,记录下来,下一层的父结点从temp开始;如果temp不为空,则当前结点不是该层第一个结点
//如果last不为空,则令last->next=当前结点;如果last为空,说明当前结点是该层第一个结点。不管last空不空都要给last赋值当前结点
//当前结点的next=当前父结点的right
//如果父结点cur有右孩子
//如果temp为空,同左孩子的temp情况
//如果last为空,同左孩子的last情况
//如果父结点的next不为空,则cur=cur->next,继续该层下一个父结点的孩子遍历;如果父结点的next为空,则cur=temp,进行下一层遍历
class Solution {
public:
Node* connect(Node* root) {
//cur表示当前遍历到的结点的父结点
//temp表示同一层第一个访问的结点
//last表示同一层上一个不为空的结点
Node *cur=root,*temp=NULL,*last=NULL;
while(cur){
if(cur->left){
if(!temp) temp=cur->left;
if(last) last->next=cur->left;
cur->left->next=cur->right,last=cur->left;
}
if(cur->right){
if(!temp) temp=cur->right;
if(last) last->next=cur->right;
if(cur->next) cur->right->next=cur->next->left,last=cur->right;
}
if(cur->next) cur=cur->next;
else cur=temp,temp=NULL,last=NULL;
}
return root;
}
};
题目链接:104. 二叉树的最大深度 - 力扣(LeetCode)
class Solution {//深度优先遍历
public:
int maxDepth(TreeNode* root) {
if(root==NULL) return 0;
return max(maxDepth(root->left),maxDepth(root->right))+1;
}
};
class Solution {//广度优先遍历
public:
int maxDepth(TreeNode* root) {
if(root==NULL) return 0;
queue<TreeNode*> q;
int depth=0;
q.push(root);
while(!q.empty()){
int size=q.size();
depth++;
for(int i=0;i<size;i++){
TreeNode *cur=q.front();
q.pop();
if(cur->left) q.push(cur->left);
if(cur->right) q.push(cur->right);
}
}
return depth;
}
};
题目链接:111. 二叉树的最小深度 - 力扣(LeetCode)
class Solution {
public:
int minDepth(TreeNode* root) {
int depth=0;
queue<TreeNode*> q;
if(root==NULL) return 0;
q.push(root);
while(!q.empty()){
int size=q.size();
depth++;
for(int i=0;i<size;i++){
TreeNode *cur=q.front();
q.pop();
if(cur->left) q.push(cur->left);
if(cur->right) q.push(cur->right);
//不必比较depth的大小,因为这是层次遍历,只要该结点为叶子节点就一定是最小的深度
if(cur->left==NULL&&cur->right==NULL) return depth;
}
}
return depth;
}
};