文章目录
二叉树类型题合集
是否为搜索二叉树
事实上如果一个二叉树中序遍历的结果是升序的,它就是一颗搜索二叉树,所以,我们可以在中序遍历的基础上改
先来定义节点
struct Node {
int value;
Node *left;
Node *right;
Node() : value(0), left(nullptr), right(nullptr) {}
Node(int x, Node *left, Node *right) : value(x), left(left), right(right) {}
};
这个节点的定义方法我参考了leetcode
然后我们看如何利用结点,搭建起一棵二叉树
Node* bT(){
Node * head = new Node(8);
head->left = new Node(6);
head->right = new Node(10);
head->left->left = new Node(4);
head->left->right = new Node(7);
head->left->left->left = new Node(1);
head->left->left->right = new Node(5);
head->right->left = new Node(9);
head->right->right = new Node(11);
return head;
}
上面的代码搭建了如下一颗二叉树,然后返回它的头节点地址
然后是递归版本和非递归版本的中序遍历
//递归版中序遍历
void inOrderRecur(Node *head){
if(!head){
return;
}
inOrderRecur(head->left);
cout<<head->value<<" ";
inOrderRecur(head->right);
}
//非递归版中序遍历
void inOrderUnRecur(Node* head){
cout<<endl;
if(head){
auto *sta = new stack<Node*>() ;
while(!sta->empty()||head){
if(head){
sta->push(head);
head = head->left;
}else{
head = sta->top();
sta->pop();
cout<<head->value<<" ";
head = head->right;
}
}
}
cout<<endl;
}
然后可以写代码测试一下结果
void test(){
inOrderRecur(bT());
inOrderUnRecur(bT());
}
int main(){
test();
return 0;
}
输出结果如下
1 4 5 6 7 8 9 10 11
1 4 5 6 7 8 9 10 11
这样我们可以明显的看出上面的二叉树是一颗搜索二叉树
然后对中序遍历的代码稍作更改
//递归版本
int preValue = -10000;
bool isBST(Node *head){
if(!head){
return true;
}
bool isLeftBst = isBST(head->left);
if(!isLeftBst)//判断左数是不是搜索二叉树,不是的话返回false
return false;
if(head->value<=preValue)//看看当前节点是否比前一个节点小,如果小,返回false
return false;
else
preValue = head->value;//如果大,那当前值设置为preValue;
//右树如果是搜索二叉树,那么整棵树是搜索二叉树,如果不是那么整棵树都不是
return isBST(head->right);
}
//非递归版本
bool isBSTUnRecur(Node* head){
if(head){
int preValue = -10000;
auto *sta = new stack<Node*>() ;
while(!sta->empty()||head){
if(head){
sta->push(head);
head = head->left;
}else{
head = sta->top();
sta->pop();
if(head->value<=preValue)
return false;
else
preValue = head->value;
head = head->right;
}
}
}
return true;
}
2、判断是否完全二叉树
这道题主要用的方法是BFS,即宽度优先遍历
判断条件如下:
(1)任何一个节点,有右孩子而无左孩子,返回false
(2)遇到一个有左无右的节点后,必须保证后面的所有节点都是叶节点,否则不是完全二叉树
bool isCBT(Node*head){
if(head == nullptr){
return true;
}
auto *que = new queue<Node*>();
//是否遇到过左右两个孩子不双全的节点
bool leaf = false;
Node *l = nullptr;
Node *r = nullptr;
que->push(head);
while(!que->empty()){
head = que->front();
que->pop();
l = head->left;
r = head->right;
if( (leaf&&(l||r))//条件二
||(!l&&r)){//条件一
return false;
}
if(l) que->push(l);
if(r) que->push(r);
if(!l||!r) leaf = true;//左右孩子不双全
}
return true;
}
3、判断是否是满二叉树
先求二叉树的最大深度,再求二叉树的节点个数N,二者满足如下关系则说明是满二叉树,代码在下一个问题解决之后再展示
N
=
2
l
−
1
N = 2^l -1
N=2l−1
4、判断是否平衡二叉树(二叉树题目套路)
平衡二叉树是指:对与任何一棵子树,左子树和右子树的高度差都不能超过1
struct ReturnType{
bool isBalanced;
int height;
ReturnType(bool isB, int hei):isBalanced(isB),height(hei){}
};
ReturnType* process(Node* x){
//base case
if(!x) return new ReturnType(true, 0);
ReturnType leftData = *process(x->left);
ReturnType rightData = *process(x->right);
int height = max(leftData.height, rightData.height)+1;
bool isBalanced = leftData.isBalanced&&rightData.isBalanced
&&abs(leftData.height-rightData.height)<2;
ReturnType *ans = new ReturnType(isBalanced, height);
return ans;
}
bool isBalanced(Node * head){
return process(head)->isBalanced;
}
用上面的套路也可以写搜索二叉树的判断
判断条件如下:
(1)左子树是否搜索二叉树
(2)右子树是否搜索二叉树
(3)左边的最大值是否小于右树的最小值
所以我们需要的返回值类型,
如下:(1)是否是搜索二叉树
(2)整棵树的最小值
(3)整棵树的最大值
struct ReturnData{
bool isBST;
int min;
int max;
ReturnData(bool is, int mi, int ma):isBST(is), min(mi), max(ma){}
};
ReturnData * process1(Node *x){
if(!x){
return nullptr;
}
ReturnData* leftData = process1(x->left);
ReturnData* rightData = process1(x->right);
int Min = x->value;
int Max = x->value;
if(leftData){
Min = min(Min, leftData->min);
Max = max(Max, leftData->max);
}
if(rightData){
Min = min(Min, leftData->min);
Max = max(Max, leftData->max);
}
// bool isBST = true;
// if(leftData&&(!leftData->isBST || leftData->max>=x->value))
// isBST = false;
// if(rightData&&(!rightData->isBST || rightData->min<=x->value))
// isBST = false;
bool isBST = false;
if(
(leftData?(leftData->isBST&&leftData->max<x->value): true)
&&(rightData?(leftData->isBST&&leftData->max<x->value):true)
){
isBST = true;
}
return new ReturnData(isBST, Min, Max);
}
bool isBST1(Node * x){
return process1(x)->isBST;
}
上面的这种套路,据左神说,可以解决一切树形DP的问题,
这个套路有两个方面,第一个方面是你怎么想这个问题:第一就是可以从左右两边来获取信息
第二个方面是,怎么写代码,代码结构是什么都一目了然
按照这个套路,我们开始解决满二叉树的问题
struct Info{
int height;
int nodes;
Info(int h, int n){
height = h;
nodes = n;
}
};
Info* processInfo(Node *x){
if(!x) return new Info(0, 0);
Info * leftData = processInfo(x->left);
Info * rightData = processInfo(x->right);
int height = max(leftData->height, rightData->height)+1;
int nodes = leftData->nodes + rightData->nodes + 1;
return new Info(height, nodes);
}
bool isF(Node *head){
if(!head) return true;
Info *data = processInfo(head);
return data->nodes == (1<<data->height-1);//相当于2^l-1
}
下面放一下刚才的所有代码
#include <iostream>
#include<stack>
#include<queue>
#include<cmath>
using namespace std;
struct Node {
int value;
Node *left;
Node *right;
Node() : value(0), left(nullptr), right(nullptr) {}
Node(int x) : value(x), left(nullptr), right(nullptr) {}
Node(int x, Node *left, Node *right) : value(x), left(left), right(right) {}
};
//------------------------是否是搜索二叉树----------------------
//递归版中序遍历
void inOrderRecur(Node *head){
if(!head){
return;
}
inOrderRecur(head->left);
cout<<head->value<<" ";
inOrderRecur(head->right);
}
//递归版本判断搜索二叉树
int preValue = -10000;
bool isBST(Node *head){
if(!head){
return true;
}
bool isLeftBst = isBST(head->left);
if(!isLeftBst)//判断左数是不是搜索二叉树,不是的话返回false
return false;
if(head->value<=preValue)//看看当前节点是否比前一个节点小,如果小,返回false
return false;
else
preValue = head->value;//如果大,那当前值设置为preValue;
//右树如果是搜索二叉树,那么整棵树是搜索二叉树,如果不是那么整棵树都不是
return isBST(head->right);
}
//非递归版中序遍历
void inOrderUnRecur(Node* head){
cout<<endl;
if(head){
auto *sta = new stack<Node*>() ;
while(!sta->empty()||head){
if(head){
sta->push(head);
head = head->left;
}else{
head = sta->top();
sta->pop();
cout<<head->value<<" ";
head = head->right;
}
}
}
cout<<endl;
}
//非递归版本
bool isBSTUnRecur(Node* head){
if(head){
int preValue = -10000;
auto *sta = new stack<Node*>() ;
while(!sta->empty()||head){
if(head){
sta->push(head);
head = head->left;
}else{
head = sta->top();
sta->pop();
if(head->value<=preValue)
return false;
else
preValue = head->value;
head = head->right;
}
}
}
return true;
}
//--------------是否是完全二叉树------------------------
bool isCBT(Node*head){
if(head == nullptr){
return true;
}
auto *que = new queue<Node*>();
//是否遇到过左右两个孩子不双全的节点
bool leaf = false;
Node *l = nullptr;
Node *r = nullptr;
que->push(head);
while(!que->empty()){
head = que->front();
que->pop();
l = head->left;
r = head->right;
if( (leaf&&(l||r))//条件二
||(!l&&r)){//条件一
return false;
}
if(l) que->push(l);
if(r) que->push(r);
if(!l||!r) leaf = true;
}
return true;
}
//--------------------是否是平衡二叉树-----------------------
struct ReturnType{
bool isBalanced;
int height;
ReturnType(bool isB, int hei):isBalanced(isB),height(hei){}
};
ReturnType* process(Node* x){
//base case
if(!x) return new ReturnType(true, 0);
ReturnType leftData = *process(x->left);
ReturnType rightData = *process(x->right);
int height = max(leftData.height, rightData.height)+1;
bool isBalanced = leftData.isBalanced&&rightData.isBalanced
&&abs(leftData.height-rightData.height)<2;
ReturnType *ans = new ReturnType(isBalanced, height);
return ans;
}
bool isBalanced(Node * head){
return process(head)->isBalanced;
}
//---------------------是否搜索二叉树套路版---------------
struct ReturnData{
bool isBST;
int min;
int max;
ReturnData(bool is, int mi, int ma):isBST(is), min(mi), max(ma){}
};
ReturnData * process1(Node *x){
if(!x){
return nullptr;
}
ReturnData* leftData = process1(x->left);
ReturnData* rightData = process1(x->right);
int Min = x->value;
int Max = x->value;
if(leftData){
Min = min(Min, leftData->min);
Max = max(Max, leftData->max);
}
if(rightData){
Min = min(Min, leftData->min);
Max = max(Max, leftData->max);
}
// bool isBST = true;
// if(leftData&&(!leftData->isBST || leftData->max>=x->value))
// isBST = false;
// if(rightData&&(!rightData->isBST || rightData->min<=x->value))
// isBST = false;
bool isBST = false;
if(
(leftData?(leftData->isBST&&leftData->max<x->value): true)
&&(rightData?(leftData->isBST&&leftData->max<x->value):true)
){
isBST = true;
}
return new ReturnData(isBST, Min, Max);
}
bool isBST1(Node * x){
return process1(x)->isBST;
}
//---------------------是否为满二叉树----------------------
struct Info{
int height;
int nodes;
Info(int h, int n){
height = h;
nodes = n;
}
};
Info* processInfo(Node *x){
if(!x) return new Info(0, 0);
Info * leftData = processInfo(x->left);
Info * rightData = processInfo(x->right);
int height = max(leftData->height, rightData->height)+1;
int nodes = leftData->nodes + rightData->nodes + 1;
return new Info(height, nodes);
}
bool isF(Node *head){
if(!head) return true;
Info *data = processInfo(head);
return data->nodes == (1<<data->height-1);//相当于2^l-1
}
Node* bT(){
Node * head = new Node(8);
head->left = new Node(6);
head->right = new Node(10);
head->left->left = new Node(4);
head->left->right = new Node(7);
head->left->left->left = new Node(1);
head->left->left->right = new Node(5);
head->right->left = new Node(9);
head->right->right = new Node(11);
return head;
}
void test(){
// inOrderRecur(bT());// 1
// inOrderUnRecur(bT());// 1
// cout<<isBST(bT())<<endl;// 1
// cout<<isBSTUnRecur(bT())<<endl;// 1
// cout<<isCBT(bT())<<endl;// 1
// cout<<isBalanced(bT())<<endl;// 1
// cout<<isBST1(bT())<<endl;// 1
// cout<<isF(bT())<<endl;// 0
}
int main(){
test();
return 0;
}
最低公共祖先:
#include<iostream>
#include<map>
#include<set>
using namespace std;
using namespace __gnu_cxx;
struct Node {
int value;
Node *left;
Node *right;
Node(int x) : value(x), left(nullptr), right(nullptr) {}
};
void process(Node *head, map<Node *, Node *> *fatherMap) {
if (!head) return;
fatherMap->insert(make_pair(head->left, head));
fatherMap->insert(make_pair(head->right, head));
process(head->left, fatherMap);
process(head->right, fatherMap);
}
Node *lca(Node *head, Node *o1, Node *o2) {
auto *fatherMap = new map<Node *, Node *>();
fatherMap->insert(make_pair(head, head));
process(head, fatherMap);
auto *set1 = new set<Node *>();
set1->insert(o1);
Node *cur = o1;
while (cur != fatherMap->find(cur)->second) {
set1->insert(cur);
cur = fatherMap->find(cur)->second;
}
set1->insert(head);
cur = o2;
while (cur != fatherMap->find(cur)->second) {
if (set1->find(cur) != set1->end())
return cur;
else {
cur = fatherMap->find(cur)->second;
}
}
return head;
}
int main() {
Node *head = new Node(8);
head->left = new Node(6);
head->right = new Node(10);
head->left->left = new Node(4);
Node *o1 = head->left->right = new Node(7);
Node *o2 = head->left->left->left = new Node(1);
head->left->left->right = new Node(5);
head->right->left = new Node(9);
head->right->right = new Node(11);
cout<<lca(head, o1, o2)->value<<endl;
}
输出:6
左神原版本的代码用的是hash_ map,但是由与C++hash_map, 不支持自定义数据类型(虽然可以自定义hash模板),所以我只能用map了
在二叉树中找到一个节点的后继节点
后继节点,是中序遍历一个节点的的下一个节点
还是最开始的二叉树,它中序遍历的结果是1,4,5,6,7,8,9,10,11
那么节点4的后继节点就是5
二叉树的序列化和反序列化
微软面试题,折纸条
所以要从上到下打印所有折痕的方向,就是这颗二叉树中序遍历
这颗树的特点是,头节点是凹折痕,每个左子树的头节点都是凹折痕,每个右子树头节点都是凸折痕