基础知识
一. 二叉树的种类
二叉树主要分为满二叉树、完全二叉树
满二叉树:如果一棵二叉树只有度为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底层实现是哈希表。
二. 二叉树的存储方式
二叉树可以链式存储,也可以顺序存储。那么链式存储方式就用指针, 顺序存储的方式就是用数组。
三. 二叉树的遍历方式
二叉树主要有两种遍历方式:
- 深度优先遍历:先往深走,遇到叶子节点再往回走。
- 广度优先遍历:一层一层的去遍历。
- 深度优先遍历(这里前中后,其实指的就是中间节点的遍历顺序,)
- 前序遍历(递归法,迭代法)
- 中序遍历(递归法,迭代法)
- 后序遍历(递归法,迭代法)
- 广度优先遍历
- 层次遍历(迭代法)
前中后序遍历的逻辑其实都是可以借助栈使用非递归的方式来实现的。
而广度优先遍历的实现一般使用队列来实现,这也是队列先进先出的特点所决定的,因为需要先进先出的结构,才能一层一层的来遍历二叉树。
四. 二叉树的定义
链式存储
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;
}
例题
递归写法
/**
* 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;
}
};
递归写法
/**
* 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;
}
};
递归写法
/**
* 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;
}
};
解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;
}
};
和上一个区别不就是个翻转吗
/**
* 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;
}
};
直接输出每一层的最后一个就好了
/**
* 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;
}
};
一层一层算
/**
* 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;
}
};
这次的子结点不是两个了
/*
// 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;
}
};
就多了一个统计最大值
/**
* 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;
}
};
/*
// 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填null
node->next=NULL;
}
else{
node->next=q.front();//结点next指向右边的结点
}
}
}
return root;
}
};
解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 递归三步走
- 终止条件:root为空,返回0
- 确定参数以及返回值:参数只需要root就可以了,需要返回当前数的高度
- 本层递归操作:当前数的高度等于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;
}
};
解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 long
queue<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;
}
};
总结
- 二叉树的深度优先遍历非递归实现也可以统一格式,就是调整栈中的顺序以及添加标记。
- 二叉树的广度优先遍历非递归用队列实现,可以通过添加标记来标记每一层的结束,也可以用一个变量保存每一层的个数。
- 树的深度和树的层数是一致的。