基础知识

一. 二叉树的种类

二叉树主要分为满二叉树、完全二叉树
满二叉树:如果一棵二叉树只有度为0的结点和度为2的结点,并且度为0的结点在同一层上,则这棵二叉树为满二叉树。深度为k的满二叉树,有2k-1个节点。
完全二叉树:在完全二叉树中,除了最底层节点可能没填满外,其余每层节点数都达到最大值,并且最下面一层的节点都集中在该层最左边的若干位置。若最底层为第 h 层,则该层包含 1~ 2h -1 个节点。

二叉搜索树

  • 树上加上数值就是二叉搜索树,二叉搜索树是一个有序树。
  • 若它的左子树不空,则左子树上所有结点的值均小于它的根结点的值;
  • 若它的右子树不空,则右子树上所有结点的值均大于它的根结点的值;
  • 它的左、右子树也分别为二叉排序树

平衡二叉搜索树
平衡二叉搜索树:又被称为AVL(Adelson-Velsky and Landis)树,且具有以下性质:它是一棵空树或它的左右两个子树的高度差的绝对值不超过1,并且左右两个子树都是一棵平衡二叉树。
C++中map、set、multimap,multiset的底层实现都是平衡二叉搜索树,所以map、set的增删操作时间时间复杂度是logn,注意unordered_map、unordered_map底层实现是哈希表。

二. 二叉树的存储方式

二叉树可以链式存储,也可以顺序存储。那么链式存储方式就用指针, 顺序存储的方式就是用数组。

三. 二叉树的遍历方式

二叉树主要有两种遍历方式:

  1. 深度优先遍历:先往深走,遇到叶子节点再往回走。
  2. 广度优先遍历:一层一层的去遍历。
  • 深度优先遍历(这里前中后,其实指的就是中间节点的遍历顺序,)

    • 前序遍历(递归法,迭代法)
    • 中序遍历(递归法,迭代法)
    • 后序遍历(递归法,迭代法)
  • 广度优先遍历
    • 层次遍历(迭代法)

前中后序遍历的逻辑其实都是可以借助栈使用非递归的方式来实现的。
而广度优先遍历的实现一般使用队列来实现,这也是队列先进先出的特点所决定的,因为需要先进先出的结构,才能一层一层的来遍历二叉树。

四. 二叉树的定义

链式存储

struct TreeNode {int val;TreeNode *left;TreeNode *right;TreeNode(int x) : val(x), left(NULL), right(NULL) {}
};

五 补充

X的先序遍历之前的结点并上X的后序遍历之前的结点就是X的所有祖先结点。
证明:由先序遍历左根右,X的祖先必出现在X的先序遍历之前。
由后序遍历的,X的祖先必出现在X的后序遍历之后。即X的祖先一定全部出现在交集里。
接下来证交集只有X的祖先。采用排除法
首先证X的左右子树结点不会出现在交集里,显然成立,因为X的先序遍历之前的结点不会是X的孩子结点
再证X的右兄弟不会出现在交集里。显然右兄也不会出现在X的先序遍历之前

最后证X的左兄不会出现在交集里。显然X的左兄不会出现在X后序遍历之后。

综上,交集只有X的祖先

二叉树的序列化与反序列化

二叉树的序列化是指:把一棵二叉树按照某种遍历方式的结果以某种格式保存为字符串,从而使得内存中建立起来的二叉树可以持久保存。序列化可以基于先序、后序、层序(没有中序,有歧义)的二叉树遍历方式来进行修改,序列化的结果是一个字符串,序列化时通过 某种符号表示空节点(#)。
例如:

先序序列化的结果为:“a,b,d,#,#,e,#,#,c,#,#”。(以逗号划分,#表示空)

先序的序列化

void pre(Node* root, queue<string>& ans) {if (root == NULL) {ans.push("#");return;}ans.push(to_string(root->val));pre(root->left, ans);pre(root->right, ans);}
queue<string>serialize(Node* root) {//先序序列化,序列化的结果放在队列里,因为要频繁删除第一个元素,用队列比较方便queue<string>ans;if (root == NULL) {return ans;}pre(root, ans);return ans;
}

先序的反序列化

Node* reversePre(queue<string>& ans) {if (ans.front() == "#") {ans.pop();return NULL;}Node* p = new Node(stoi(ans.front()));ans.pop();p->left = reversePre(ans);p->right = reversePre(ans);return p;}
Node* reverseSerialize(queue<string>& ans) {if (ans.empty()) {return NULL;}Node* root=reversePre(ans);return root;
}

后序的序列化与反序列化与先序的类似

层序的序列化

void level(Node* root, queue<string>& ans) {queue<Node*>q;q.push(root);ans.push(to_string(root->val));while (!q.empty()) {Node* node = q.front();q.pop();if (node->left != NULL) {//不空才进q队列q.push(node->left);ans.push(to_string(node->left->val));}else {ans.push("#");}if (node->right != NULL) {q.push(node->right);ans.push(to_string(node->right->val));}else {ans.push("#");}}
}
queue<string>xvliehua(Node* root) {queue<string>ans;if (root == NULL) {return ans;}level(root, ans);return ans;
}

层序的反序列化

Node* fanlevel(queue<string>& ans) {if (ans.front() == "#") {return NULL;}Node* root = new Node(stoi(ans.front()));//根结点ans.pop();queue<Node*>q;q.push(root);while (!q.empty()) {Node* node = q.front();q.pop();string left = ans.front();ans.pop();string right = ans.front();ans.pop();if (left == "#") {node->left = NULL;}else {//非#的才入q队列Node* leftNode = new Node(stoi(left));node->left = leftNode;q.push(leftNode);}if (right == "#") {node->right = NULL;}else {Node* rightNode = new Node(stoi(right));node->right = rightNode;q.push(rightNode);}}return root;
}
Node* fanxvliehau1(queue<string>& ans) {if (ans.empty()) {return NULL;}return fanlevel(ans);
}

设计一个算法,可以将 N 叉树编码为二叉树,并能将该二叉树解码为原 N 叉树。 一个 N 叉树是指每个节点都有不超过 N 个孩子节点的有根树。 类似地,一个二叉树是指每个节点都有不超过 2 个孩子节点的有根树。 你的编码 / 解码的算法的实现没有限制,你只需要保证一个 N 叉树可以编码为二叉树且该二叉树可以解码回原始 N 叉树即可。
例如,你可以将下面的 3-叉 树以该种方式编码:

分析:多叉转二叉树:结点的第一个孩子作为左孩子,结点的第一个右兄弟作为右孩子
二叉转多叉树:结点的左孩子就是孩子结点,结点的右孩子是自己的兄弟

#include<iostream>
#include<algorithm>
#include<list>
#include <queue>
using namespace std;
class NNode {//多叉树结点
public:int val;list<NNode*>child;NNode(int val) :val(val){}NNode(int val, list<NNode*>child) :val(val), child(child) {}
};class BinNode {//二叉树结点
public:int val;BinNode* left;BinNode* right;BinNode(int val) :val(val) {left = NULL;right = NULL;}
};class NNodeToBinNOde {public:BinNode* process1(list<NNode*>child) {//返回根结点if (child.empty()) {return NULL;}BinNode* head = NULL;BinNode* cur = NULL;for (NNode* node : child) {if (head == NULL) {//node是第一个孩子结点,应该作为根结点head = new BinNode(node->val);head->left=process1(node->child);cur = head;}else {cur->right = new BinNode(node->val);//第一个右兄弟作为右孩子cur = cur->right;//cur下移cur->left = process1(node->child);}}return head;}list<NNode*>process2(BinNode* root) {//返回孩子结点list<NNode*>child;while (root != NULL) {NNode* node = new NNode(root->val, process2(root->left));//构造root对应的多叉树child.push_back(node);root = root->right;}return child;}BinNode* nTob(NNode* root) {//多叉—>二叉if (root == NULL) {return NULL;}BinNode* head = new BinNode(root->val);head->left = process1(root->child);return head;}NNode* bTon(BinNode* root) {//二叉->多叉if (root == NULL) {return NULL;}return new NNode(root->val, process2(root->left));}
};NNode* geneN(int n) {//随机生成多叉树srand(unsigned(time(0)));NNode* root = new NNode(0);list<NNode*>already;int sum = 1;already.push_back(root);while (!already.empty()) {if (sum >= n) {break;}NNode* node = already.front();already.pop_front();list<NNode*>list;int m = rand() % 4;for (int j = 0; j < m; ++j) {int num = rand() % 50 + 1;NNode* ch = new NNode(num);list.push_back(ch);already.push_back(ch);++sum;}node->child = list;}return root;
}void showNNode(NNode* root) {if (root == NULL) {return;}queue<NNode*>q;q.push(root);while (!q.empty()) {NNode* node = q.front();q.pop();cout << node->val << " ";for (NNode* ch : node->child) {q.push(ch);}}cout << endl;
}void showBinNode(BinNode* root) {if (root == NULL) {return;}queue<BinNode*>q;q.push(root);while (!q.empty()) {BinNode* node = q.front();q.pop();cout << node->val << " ";if (node->left != NULL) {q.push(node->left);}if (node->right != NULL) {q.push(node->right);}}cout << endl;
}
int main() {NNode* root = geneN(10);showNNode(root);NNodeToBinNOde n;BinNode* root2=n.nTob(root);//多叉树转二叉树showBinNode(root2);NNode* r2 = n.bTon(root2);//二叉树转多叉树showNNode(r2);return 0;
}

例题

144. 二叉树的前序遍历

递归写法

/*** 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* root,vector<int>& re){if(root==nullptr){return ;}re.push_back(root->val);//中traversal(root->left,re);//左traversal(root->right,re);//右}vector<int> preorderTraversal(TreeNode* root) {vector<int> result;traversal(root,result);return result;}
};

迭代写法

/*** 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> preorderTraversal(TreeNode* root) {stack<TreeNode*>st;vector<int> result;if(root==nullptr){return result;}st.push(root);while(!st.empty()){TreeNode* node=st.top();st.pop();result.push_back(node->val);if(node->right!=nullptr){//因为要先左后右,所以右结点先入栈,空节点不入栈st.push(node->right);}if(node->left!=nullptr){st.push(node->left);}}return result;}
};

94. 二叉树的中序遍历

递归写法

/*** 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* root,vector<int>& re){if(root==nullptr){return ;}traversal(root->left,re);//左re.push_back(root->val);//中traversal(root->right,re);//后}vector<int> inorderTraversal(TreeNode* root) {vector<int> result;traversal(root,result);return result;}
};

迭代写法

/*** 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> re;TreeNode* cur=root;stack<TreeNode*> st;while(cur!=nullptr || !st.empty()){if(cur!=nullptr){//直到左结点为空st.push(cur);cur=cur->left;}else{cur=st.top();//弹出就是当前的根结点st.pop();re.push_back(cur->val);cur=cur->right;//再访问右结点}}return re;}
};

145. 二叉树的后序遍历

递归写法

/*** 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* root,vector<int> & re){if(root==nullptr){return ;}traversal(root->left,re);traversal(root->right,re);re.push_back(root->val);}vector<int> postorderTraversal(TreeNode* root) {vector<int> result;traversal(root,result);return result;}
};

迭代写法
后序遍历:左右中,倒过来就是中右左,颠倒一下右左就是前序遍历,所以可以按照前序遍历(先左后右),然后逆序输出。

/*** 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) {stack<TreeNode*>st;vector<int> re;if(root==nullptr){return re;}st.push(root);while(!st.empty()){TreeNode* node=st.top();st.pop();re.push_back(node->val);if(node->left!=nullptr){st.push(node->left);}if(node->right!=nullptr){st.push(node->right);}}reverse(re.begin(),re.end());return re;}
};

前中后序遍历统一写法

前序和中序之所以写法不同就是因为前序访问的结点(放栈)和处理的结点(放result)一致,而中序不一致。如果要统一写法,就要调整栈中的顺序,具体处理是在要处理的结点上面加一个空指针标志,当弹出空指针时,说明下一个结点就是要处理的结点,直接放resul中即可。
注意入栈的顺序:前序:右左中null , 中序:右中null左 , 后序:中null右左

前序

/*** 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> preorderTraversal(TreeNode* root) {stack<TreeNode*> st;vector<int> re;if(root==nullptr){return re;}st.push(root);while(!st.empty()){TreeNode* node=st.top();if(node!=nullptr){st.pop();if(node->right!=nullptr)st.push(node->right);if(node->left!=nullptr)st.push(node->left);st.push(node);st.push(nullptr);}else{st.pop();/弹出空指针node=st.top();st.pop();re.push_back(node->val);}}return re;}
};

中序

/*** 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) {st<TreeNode* >st;vector<int> re;if(root!=nullptr)return re;st.push(root);while(!st.empty()){TreeNode* node=st.top();if(node!=nullptr){st.pop();if(node->right!=nullptr)st.push(node->right);st.push(node);st.push(nullptr);if(node->left!=nullptr) st.push(node->left);}else{st.pop();node=st.top();st.pop();re.push_back(node->val);}}return re;}
};

后序

/*** 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) {stack<TreeNode*>st;vector<int> re;if(root==nullptr)return re;st.push(root);while(!st.empty()){TreeNode* node=st.top();if(node!=nullptr){st.pop();st.push(node);st.push(nullptr);if(node->right!=nullptr)st.push(node->right);//空指针不入栈if(node->left!=nullptr)st.push(node->left);}else{st.pop();node=st.top();st.pop();re.push_back(node->val);}}return re;}
};

102. 二叉树的层序遍历

解1 空指针标记法
层序遍历就是一层一层从左往右遍历,自然要用队列实现,关键是如何区分某一层。这里可以采用空指针标记法,在每一层的末尾加上空指针,这样当遇到空指针就说明这一层遍历结束。

/*** 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<vector<int>> levelOrder(TreeNode* root) {queue<TreeNode*>q;vector<vector<int>> re;vector<int> t;if(root==nullptr)return re;q.push(root);q.push(nullptr);//空指针标记while(!q.empty()){TreeNode* node=q.front();if(node!=nullptr){//如果队头不是空指针,就继续放下一层的结点q.pop();t.push_back(node->val);if(node->left!=nullptr){q.push(node->left);}if(node->right!=nullptr){q.push(node->right);}}else{//此时一层遍历结束,为下一层添加结束标记q.pop();//删掉空指针re.push_back(t);//保存一层遍历的结果t.clear();q.push(nullptr);//为下一层添加结束标记if(q.size()==1){//队列里只有一个空指针时就结束,一定不要忘了这一句,否则就死循环了break;}}}return re;}
};

解2 变量控制法,提前用一个变量保持每一层结点的个数

/*** 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<vector<int>> levelOrder(TreeNode* root) {queue<TreeNode*> q;vector<vector<int>> re;if(root==nullptr)return re;q.push(root);while(!q.empty()){int size=q.size();//由于队列中结点的个数是不断变化的,所以需要提前保存下来vector<int>t;//存放每一层的结点值for(int i=0;i<size;i++){TreeNode*node=q.front();q.pop();t.push_back(node->val);if(node->left!=nullptr)q.push(node->left);if(node->right!=nullptr)q.push(node->right);}re.push_back(t);}return re;}
};

107. 二叉树的层序遍历 II

和上一个区别不就是个翻转吗

/*** 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<vector<int>> levelOrderBottom(TreeNode* root) {queue<TreeNode*>q;vector<vector<int>>re;vector<int>t;if(root==nullptr)return re;q.push(root);q.push(nullptr);while(!q.empty()){TreeNode* node=q.front();if(node!=nullptr){q.pop();t.push_back(node->val);if(node->left!=nullptr)q.push(node->left);if(node->right!=nullptr)q.push(node->right);}else{q.pop();q.push(nullptr);re.push_back(t);t.clear();if(q.size()==1){break;}}}reverse(re.begin(),re.end());return re;}
};

199. 二叉树的右视图

直接输出每一层的最后一个就好了

/*** 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> rightSideView(TreeNode* root) {vector<int> re;queue<TreeNode*>q;if(root==nullptr)return re;q.push(root);q.push(nullptr);while(!q.empty()){TreeNode*node=q.front();if(node!=nullptr){q.pop();if(node->left!=nullptr)q.push(node->left);if(node->right!=nullptr)q.push(node->right);if(q.front()==nullptr){re.push_back(node->val);}}else{q.pop();q.push(nullptr);if(q.size()==1){break;}}}return re;}
};

637. 二叉树的层平均值

一层一层算

/*** 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<double> averageOfLevels(TreeNode* root) {vector<double>re;double t=0;queue<TreeNode*>q;q.push(root);while(!q.empty()){int size=q.size();t=0;for(int i=0;i<size;i++){TreeNode* node=q.front();t+=node->val;q.pop();if(node->left!=nullptr)q.push(node->left);if(node->right!=nullptr)q.push(node->right);}t=t/size;re.push_back(t);}return re;}
};

429. N 叉树的层序遍历

这次的子结点不是两个了

/*
// Definition for a Node.
class Node {
public:int val;vector<Node*> children;Node() {}Node(int _val) {val = _val;}Node(int _val, vector<Node*> _children) {val = _val;children = _children;}
};
*/class Solution {public:vector<vector<int>> levelOrder(Node* root) {vector<vector<int>>re;queue<Node*>q;if(root==NULL){return re;}q.push(root);while(!q.empty()){int size=q.size();//每一层的结点数vector<int> t;for(int i=0;i<size;i++){Node* node=q.front();q.pop();t.push_back(node->val);vector<Node*>n=node->children;for(int j=0;j<n.size();j++){//孩子结点入队q.push(n[j]);}}re.push_back(t);}return re;}
};

515. 在每个树行中找最大值

就多了一个统计最大值

/*** 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> largestValues(TreeNode* root) {queue<TreeNode*> q;vector<int>re;if(root==nullptr)return re;q.push(root);while(!q.empty()){int size=q.size();int max=q.front()->val;for(int i=0;i<size;i++){TreeNode*node=q.front();q.pop();max=max > node->val?max : node->val;//取更大的if(node->left!=nullptr)q.push(node->left);if(node->right!=nullptr)q.push(node->right);}re.push_back(max);}return re;}
};

116. 填充每个节点的下一个右侧节点指针

/*
// Definition for a Node.
class Node {
public:int val;Node* left;Node* right;Node* next;Node() : val(0), left(NULL), right(NULL), next(NULL) {}Node(int _val) : val(_val), left(NULL), right(NULL), next(NULL) {}Node(int _val, Node* _left, Node* _right, Node* _next): val(_val), left(_left), right(_right), next(_next) {}
};
*/class Solution {public:Node* connect(Node* root) {queue<Node*> q;if(root==NULL)return root;q.push(root);while(!q.empty()){int size=q.size();for(int i=0;i<size;i++){Node*node=q.front();q.pop();                  if(node->left!=NULL)q.push(node->left);if(node->right!=NULL)q.push(node->right);if(i==size-1){//一层最右边结点的next填nullnode->next=NULL;}else{node->next=q.front();//结点next指向右边的结点}   }} return root;}
};

104. 二叉树的最大深度

解1 层序遍历法 初始depth等于0,只要队列还有元素,depth++

/*** 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:int maxDepth(TreeNode* root) {int depth=0;queue<TreeNode*>q;if(root==nullptr)return depth;q.push(root);while(!q.empty()){int size=q.size();depth++;for(int i=0;i<size;i++){TreeNode*node=q.front();q.pop();if(node->left!=nullptr)q.push(node->left);if(node->right!=nullptr)q.push(node->right);}}return depth;}
};

解2 递归三步走

  1. 终止条件:root为空,返回0
  2. 确定参数以及返回值:参数只需要root就可以了,需要返回当前数的高度
  3. 本层递归操作:当前数的高度等于max(左子树的高度,右子树的高度)+1,所以需要调用左子树的递归和右子树的递归
/*** 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:int maxDepth(TreeNode* root) {if(root==nullptr)return 0;int left=maxDepth(root->left);int right=maxDepth(root->right);return max(left,right)+1;}
};

解3 求树的最大深度可以通过根结点的高度求,也可以直接按照深度的定义求,这就涉及到回溯了

/*** 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:int maxDep = 0;void travel(TreeNode* root, int depth) {if (root == nullptr)return;maxDep = maxDep > depth ? maxDep : depth;//更新当前最大深度if (root->left != nullptr) {depth++;travel(root->left, depth);depth--;//回溯}if (root->right != nullptr) {depth++;travel(root->right, depth);depth--;}}int maxDepth(TreeNode* root) {travel(root, 1);return maxDep;}
};

111. 二叉树的最小深度

解1 如果左右结点都为空,说明当前结点就是叶子结点,一定是最小深度

/*** 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:int minDepth(TreeNode* root) {int min=0;queue<TreeNode*> q;if(root==nullptr)return min;q.push(root);while(!q.empty()){int size=q.size();min++;for(int i=0;i<size;i++){TreeNode*node=q.front();q.pop();if(node->left!=nullptr)q.push(node->left);if(node->right!=nullptr)q.push(node->right);if(node->left==nullptr && node->right==nullptr){//如果左右结点都为空,说明当前结点就是叶子结点,一定是最小深度return min;}}}return min;}
};

解2 递归 和上一题基本一致,有一点需要注意,如果结点的左子树并且右子树不为空,就返回当前左右子树的最小值;否则即返回当前左右子树的最大值。
如果结点的左子树为空或者右子树为空,那么该结点不是叶子结点。

/*** 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:int minDepth(TreeNode* root) {if(root==nullptr)return 0;int left=minDepth(root->left);int right=minDepth(root->right);if(root->left!=nullptr && root->right!=nullptr){return min(left,right)+1;}else{return max(left,right)+1;}}
};

662. 二叉树最大宽度
分析:本题难点在于如何计算空结点的个数,可以采用编号的方式,一层最后一个结点的编号-一层第一个结点的编号+1就是本层的结点个数。

/*** 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:int widthOfBinaryTree(TreeNode* root) {if(root==nullptr){return 0;}unsigned long long maxWidth=1;//为防止溢出,只能使用unsigned long longqueue<TreeNode*>q;list<unsigned long long>listIndex;//存放结点的索引(按照完全二叉树的结构给每个结点编号)q.push(root);listIndex.push_back(1);while(!q.empty()){int size=q.size();for(int i=0;i<size;++i){//遍历本层的所有结点,并将下一层的结点全部入队列和链表TreeNode* cur=q.front();q.pop();unsigned long long index=listIndex.front();listIndex.pop_front();if(cur->left!=nullptr){q.push(cur->left);listIndex.push_back(index*2);}if(cur->right!=nullptr){q.push(cur->right);listIndex.push_back(index*2+1);}}if(!listIndex.empty()){//此时队列里是下一层的结点,链表里也是下一层结点的索引unsigned long long firstIndex=listIndex.front();unsigned long long lastIndex=listIndex.back();maxWidth=maxWidth>=(lastIndex-firstIndex+1)?maxWidth:(lastIndex-firstIndex+1);}}return maxWidth;}
};

总结

  1. 二叉树的深度优先遍历非递归实现也可以统一格式,就是调整栈中的顺序以及添加标记。
  2. 二叉树的广度优先遍历非递归用队列实现,可以通过添加标记来标记每一层的结束,也可以用一个变量保存每一层的个数。
  3. 树的深度和树的层数是一致的。

【算法笔记】二叉树之基础遍历相关推荐

  1. 数据结构与算法练习-二叉树中序遍历

    python数据结构与算法练习-二叉树中序遍历 二叉树中序遍历 思路 python实现 二叉树中序遍历 链接: link. 给定一个二叉树的根节点 root ,返回它的 中序 遍历. 样例 输入:ro ...

  2. 【每日一算法】二叉树的层次遍历 II

    每日一算法-二叉树的层次遍历 II 题目 给定一个二叉树,返回其节点值自底向上的层次遍历. (即按从叶子节点所在层到根节点所在的层,逐层从左向右遍历) 例如: 给定二叉树 [3,9,20,null,n ...

  3. leetcode算法题--二叉树中序遍历迭代法

    原题链接:https://leetcode-cn.com/problems/binary-tree-inorder-traversal/ 二叉树中序遍历迭代法,栈实现 vector<int> ...

  4. C++数据结构与算法之二叉树中序遍历

    二叉树中序遍历 C++二叉树中序遍历基本思想 C++二叉树中序遍历代码 C++二叉树中序遍历基本思想 申请一个栈stk,再申请一个变量cur,初始值让它等于头节点 先把cur压入栈中对cur节点的整颗 ...

  5. [算法笔记]二叉树基础

    前言:部分资料引自极客大学<数据结构与算法之美>,感谢王争老师! 参考链接: https://visualgo.net/en/bst?slide=1 https://zh.wikipedi ...

  6. 常考数据结构与算法:求二叉树的层序遍历

    题目描述 给定一个二叉树,返回该二叉树层序遍历的结果,(从左到右,一层一层地遍历) 例如: 给定的二叉树是{3,9,20,#,#,15,7}, 该二叉树层序遍历的结果是 [ [3], [9,20], ...

  7. leetcode算法题--二叉树的前序遍历

    题目链接:https://leetcode-cn.com/problems/binary-tree-preorder-traversal/ 二叉树前序遍历,栈实现 vector<int> ...

  8. 数据结构与算法--8.二叉树的基础知识

    文章目录 一. 二叉树基本概念 二. 二叉树的性质 三. 二叉树的代码实现 四. 二叉树的先序.中序.后序遍历 一. 二叉树基本概念 二. 二叉树的性质 三. 二叉树的代码实现 class Node( ...

  9. 算法入门 | 二叉树的递归遍历、递归创建系列(递归)

    目录 1. 二叉树的遍历规则 2. 二叉树的结构体设计 [leftchild  data  rightchild] 3. 二叉树的递归先序.中序.后序遍历 4. 利用已知字符串(二叉树的先序序列)递归 ...

最新文章

  1. Spring testcontext
  2. 机器学习(MACHINE LEARNING)交叉验证(简单交叉验证、k折交叉验证、留一法)
  3. 【Zabbix】CentOS6.9系统下部署Zabbix-server 3.0
  4. yii2 js css,JS、CSS的引用
  5. HDOJ2021 ( 发工资咯:) ) 【水题】
  6. 基于JQuery实现滚动到页面底端时自动加载更多信息
  7. 海量数据库解决方案2011030101
  8. qt连接mysql4.7数据库_QT4.7访问MySQL的驱动编译过程
  9. jquery实现双击事件不触发单击事件
  10. 射线检测(Summary)
  11. 苹果发布新应用Find My Friends,轻松追踪朋友和家人的所在位置
  12. 系统引导过程总体介绍
  13. 【KALI使用】11 搜索引擎 SHODAN
  14. python爬取微信朋友圈
  15. 网站被攻击了,怎么办?
  16. 从 0 开始学支付系统搭建——解析「核算对账核心」
  17. 新闻资讯APP开发成本需要多少钱?
  18. 工作人员必备的计算机知识,工作必备计算机技巧知识
  19. 智能手表的突破和新发展机遇
  20. 开启cdn后导致websocket10秒直接断开连接 报错1006

热门文章

  1. 各大媒体优劣对比_各大自媒体平台优缺点对比
  2. Office2016的安装进度在 90% 时挂起
  3. Java实现能完成 加减乘除幂与阶乘 组合运算的计算器
  4. mapbox 聚合图
  5. 基于FPGA的DDS信号发生器
  6. 如何用python语言解一元二次方程式
  7. HTML 5 em strong dfn code samp kbd var cite 标签
  8. 快速寻找勾股数算法的实现和优化
  9. 关于服务器上安装新版Python报错的问题
  10. HTML5期末大作业:电影网站设计——电影(1页) HTML+CSS+JavaScript 学生DW网页设计作业成品 web课程设计网页规划与设计 计算机毕设网页设计源码