————————————————————————————————
BST
————————————————————————————————
BST的插入建立,镜像
1043
// 1.BST的建立: 空指针开始, 插入函数:赋值函数+递归调用,
// 2.树的镜像:遍历的时候对换左右孩子节点的顺序就好
// 3.两个vector可以直接比较
//核心: 单序列建BST + 树的镜像BST
//1.单序列建BST:
// (1)BST树的创建只需要一个插入序列即可
// (2)struct node: 带参数的构造函数
// (3)for()输入插入 + insert(node*& root, int x) !!!!一定注意第一个参数的类型哦
// (4)insert:
// 1)root==nullptr: 新建一个节点返回
// 2)x<root->value: insert(root->left) //直接调用, 没有赋值哦
// 3)x>=root->value: insert(root->right) //直接调用, 没有赋值哦
// (5)注意和两序列建树的辨析
//2.树的镜像: 建树的时候正常, 访问的时候左右节点掉换即可
//3.Debug: F11单步调试----检查建树是否成功比较有用, 其他直接打印即可
#include <iostream>
#include <vector>
using namespace std;
struct node{
int value;
node *left, *right;
node(int x) {
value = x;
left = nullptr;
right = nullptr;
}
};
int n,flag;
vector<int>inputs, pre, preM;
void insert(node*& root, int x) {
if (root == nullptr) {
root = new node(x);
return;
}
//cout << "Come Here?" << endl;
if (x < root->value)insert(root->left, x);
else if (x >= root->value)insert(root->right, x);
//return root;
}
void preOrder(node* root) {
if (root == nullptr)return;
pre.push_back(root->value);
preOrder(root->left);
preOrder(root->right);
}
void preOrderM(node* root) {
if (root == nullptr)return;
preM.push_back(root->value);
preOrderM(root->right);
preOrderM(root->left);
}
void postOrder(node* root) {
if (root == nullptr)return;
postOrder(root->left);
postOrder(root->right);
if (flag == 0) {
flag = 1;
printf("%d", root->value);
}
else printf(" %d", root->value);
}
void postOrderM(node* root) {
if (root == nullptr)return;
postOrderM(root->right);
postOrderM(root->left);
if (flag == 0) {
flag = 1;
printf("%d", root->value);
}
else printf(" %d", root->value);
}
int main() {
scanf("%d", &n);
node* root = nullptr;
for (int i = 0; i < n; i++) {
int tmp;
scanf("%d", &tmp);
insert(root, tmp);
inputs.push_back(tmp);
}
preOrder(root);
preOrderM(root);
if (inputs == pre) {
printf("YES\n");
flag = 0;
postOrder(root);
printf("\n");
}
else if (inputs == preM) {
printf("YES\n");
flag = 0;
postOrderM(root);
printf("\n");
}
else printf("NO\n");
return 0;
}
BST的插入建立, 层数记录
1115
方法一: BST建树+BFS
//核心: BST单序列建树 + BFS处理每一层
//1.BST单序列建树:
// (1)struct node:和构造函数
// (2)insert函数:
// 1)参数: !!(node*&root, int x)
// 2)如果 root==nullptr: 新建节点 + return
// 3)x<=root->value: insert(root->left, x);
// 4)x>root->value: insert(root->right, x);
// (3)for(){ insert(root, x); }
//2.BFS处理每一层:nullptr的运用
//3.!!!自己设计, 自己思考特殊样例成功: 在看到题的时候, 对某些逻辑和情况有疑虑就记录下来, 没准Debug的时候有用
#include <iostream>
#include <queue>
using namespace std;
struct node{
int value;
node *left, *right;
node(int x) {
value = x;
left = nullptr;
right = nullptr;
}
};
int n;
vector<int>counts;
void insert(node*& root, int x) {
if (root == nullptr) {
root = new node(x);
return;
}
if (x <= root->value)insert(root->left, x);
else insert(root->right, x);
}
void BFS(node* root) {
queue<node*>q;
q.push(root);
q.push(nullptr);
int cnt = 0;
while(!q.empty()) {
node* current = q.front();
q.pop();
if (current == nullptr) {
counts.push_back(cnt);
//cout <<"###cnt: " <<cnt << endl;
cnt = 0;
if (!q.empty())q.push(nullptr);
}
else {
cnt++;
//cout << "Come here?" << endl;
if (current->left != nullptr)q.push(current->left);
if (current->right != nullptr)q.push(current->right);
}
}
}
//void preOrder(node* root) {
// if (root == nullptr)return;
//
// cout << root->value<<" "<< endl;
// preOrder(root->left);
// preOrder(root->right);
//}
int main() {
scanf("%d", &n);
node* root = nullptr;
for (int i = 0; i < n; i++) {
int tmp;
scanf("%d", &tmp);
insert(root, tmp);
}
//preOrder(root);
BFS(root);
//cout <<"####" <<counts.size() << endl;
//for (int i = 0; i < counts.size(); i++)cout << counts[i] << " ";
//cout << endl;
if (counts.size() >= 2) {
int a, b;
a = counts[counts.size() - 1];
b = counts[counts.size() - 2];
printf("%d + %d = %d", counts[counts.size() - 1], counts[counts.size() - 2], a + b);
}
else if (counts.size() == 1) {
printf("%d + 0 = %d", counts[counts.size() - 1], counts[counts.size() - 1]);
}
return 0;
}
方法二:建树时节点维护layer变量, 遍历时记录最大两个layer的数量
(有时间, 自己试一遍喽)
// 1.和最常用的函数重名的变量名最好不要取, PAT的编译器不过
// 2.BST插入建树的时候, 如果有部分样例不过, 记得>=和<=
// 3.再次熟练BST的insert函数:如果==nullprt就新建, !=则叶子等于左查, 右叶子等于右插
// 4.nowNode的写法
// 5.积累BST建树的时候记录层数的功能
// 6.prinf的便利
//#include <bits/stdc++.h>
#include <iostream>
using namespace std;
int Max=0, cnt1=0, cnt2=0;
struct node {
int data, layer;
node*left;
node*right;
};
node* newNode(int x, int depth){
node* tmp = new node;
tmp->data = x;
tmp->layer = depth;
tmp->left = nullptr;
tmp->right = nullptr;
return tmp;
}
node* insert(node*& root, int x, int depth){ //这里不加会怎么样
if (root == nullptr) {
root = newNode(x, depth);
if (depth > Max)Max = depth;
return root;
}
if (x <= root->data) {
root->left = insert(root->left, x, depth + 1);
}
else if (x > root->data) {
root->right = insert(root->right, x, depth + 1);
}
return root;
}
void inOrder(node* root) {
if (root == nullptr) return;
inOrder(root->left);
if (root->layer == Max)cnt1++;
else if (root->layer == (Max - 1))cnt2++;
inOrder(root->right);
return;
}
int main() {
int nums;
cin >> nums;
node*root=nullptr;
for (int i = 0; i < nums; i++) {
int tmp;
cin >> tmp;
insert(root, tmp, 0);
}
inOrder(root);
printf("%d + %d = %d", cnt1, cnt2, cnt1 + cnt2);
return 0;
}
完全BST的中序建立
1064
// 1.BST的中序遍历是插入序列的排序
// 2.用中序序列建立BST(常用数组): 递归终止条件root的值大存储节点的index, 递归传tree,input,index,root
// 3.BST的层序遍历就是tree的顺序访问
// 4.vector可以使用algortihm里面的sort(v.begin(),v.end())进行访问
//核心: 完全BST的中序建树BST
//1.BST的中序遍历, 是个排序
//2.如果知道完全二叉树的某种访问序列, 就可以用这个序列建树:
// (1)参数: root, index
// (2)递归终止条件: root> 序列.size()-1
// (3)干活: tree[root]=序列[index++]
// (4)递归: root的参数: 2*(root+1)+1, 2*(root+1)
// (5)场外: root, index
//3.完全二叉树用数组装树, 顺序访问就是层序遍历
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int n;
vector<int>inputs, tree;
void inOrder(int root, int &index) {
if (root > (inputs.size() - 1))return;
inOrder(2*(root+1)-1, index);
tree[root] = inputs[index++];
inOrder(2*(root + 1), index);
}
int main() {
scanf("%d", &n);
inputs.resize(n);
tree.resize(n);
for (int i = 0; i < n; i++) scanf("%d", &inputs[i]);
sort(inputs.begin(), inputs.end());
int index = 0;
inOrder(0,index);
for (int i = 0; i < tree.size(); i++) {
if (i != 0)printf(" ");
printf("%d", tree[i]);
}
return 0;
}
数组型BST的中序建立,层序输出
1099
// 1.核心: 用中序遍历建立BST
// 2.数组型树中序遍历建立BST的inOrder直接用左右叶子, 直接是数组的用2*(root+1)-1和2*root表示
// 3.函数能否用和头文件的位置也有关系
// 4.(就是前面知识点的组合, 不难, 都是一次过的嘛)
//核心: 数组建树 + 中序遍历给BST赋值 + 层序遍历输出BST
//1.数组建树:
// (1)动手过样例: 根据下标画树
// (2)数据结构: struct node{} + vector<node>tree
// (3)访问, 动作: 和普通的节点树一样
// (4)!!!常常会说 index=0是根, 所以做题的时候注意审题, 不必浪费不必要的时间寻找根
//2.中序遍历给BST赋值:
// (1)sort
// (2)int index=0; inOrder(0, index);
// (3)递归终止条件: 分数据结构: 数组型树, 数组树 不同
// (4)递归调用:
// 左边:inOrder(2*(root+1)-1, &index)
// 右边:inOrder(2*(root+1), &index)
// (5)干活: tree[root].value= inputs[index++]
//3.层序遍历输出
//4.BST建法:
// (1)insert
// (2)sort + inOrder
#include <iostream>
#include <vector>
#include <queue>
#include <algorithm>
using namespace std;
struct node {
int value, left, right;
};
int n;
vector<node>tree;
vector<int>inputs;
void inOrder(int root, int &index) {
if (root == -1)return;
inOrder(tree[root].left, index);
tree[root].value = inputs[index++];
inOrder(tree[root].right, index);
}
void leverOrder(int root) {
queue<int>q;
q.push(root);
int flag = 0;
while (!q.empty()) {
int current = q.front();
q.pop();
if (!flag) {
flag = 1;
printf("%d", tree[current].value);
}else printf(" %d", tree[current].value);
if (tree[current].left != -1)q.push(tree[current].left);
if (tree[current].right != -1)q.push(tree[current].right);
}
}
int main() {
scanf("%d", &n);
inputs.resize(n);
for (int i = 0; i < n; i++) {
node nodeTmp;
scanf("%d %d", &nodeTmp.left, &nodeTmp.right);
tree.push_back(nodeTmp);
}
for (int i = 0; i < n; i++)scanf("%d", &inputs[i]);
sort(inputs.begin(), inputs.end());
int index = 0; //因为有&, 所以这里必须在外面声明
inOrder(0,index);
leverOrder(0);
return 0;
}
BST的前序建立+DFS+红黑树的判断(可以背代码块)
1135
//1.红黑树:
// (1)是BST
// (2)根节点是黑色
// (3)NULL是黑色
// (4)红色节点两个孩子是黑色
// (5)任意节点到叶子节点, 黑色节点数相等
//2.如果是BST:只要给一个序列就可以建树
// 3.积累 BST建树
// 4.积累 树DFS的写法和用处:
// (1)写法:
// 1)递归终止条件,
// 2)该节点的处理(计数, 节点数值判断, 左右孩子判断等)
// 3)递归
// 4)并且可以带返回值
// (2)用处:记录层数, 特殊节点计数
//核心: BST的单序列建树 + 红黑树的判断(可以背代码块)
//1.BST的单序列建树:
// (1)node 构造函数
// (2)insert(root*&, int x)
// (3)for() insert
//2.红黑树的判断:
// (1)三个条件:
// 1)递归外: root->value >0
// 2) 到叶子节点的黑节点数量相等, 注意参数sum (有&和没&的区别: 有则值按整个顺序来, 没有下一个参数就是这次处理的值)
// 3)红色节点的两个孩子必须是黑色
//3.参数 有&和没&的区别
//4.熟练运用断点调试, 单步调试
#include <iostream>
#include <vector>
#include <cmath>
using namespace std;
int k, n, cntBlack = 0;
struct node {
int value;
node *left, *right;
node(int x) {
value = x;
left = right = nullptr;
}
};
void insert(node*& root, int x) {
if (root == nullptr) {
root = new node(x);
return;
}
if (abs(x) <= abs(root->value))insert(root->left, x); //这里题目没说==, 看情况
else if (abs(x) > abs(root->value))insert(root->right, x);
}
bool isRedBlack(node* root, int sum) {
if (root == nullptr) {
if (cntBlack == sum)return true;
else return false;
}
if (root->value > 0)sum++;
else {
if (root->left != nullptr && (root->left->value < 0))return false;
if (root->right != nullptr && (root->right->value < 0))return false;
}
return isRedBlack(root->left, sum) && isRedBlack(root->right, sum);
}
int main() {
scanf("%d", &k);
while (k--) {
//建树
scanf("%d", &n);
node* root = nullptr;
for (int i = 0; i < n; i++) {
int tmp;
scanf("%d", &tmp);
insert(root, tmp);
}
//判断是否红黑树
node *tmpNode = root;
cntBlack = 0;
while (tmpNode != nullptr) {
if (tmpNode->value > 0)cntBlack++;
tmpNode = tmpNode->left;
}
int sum = 0;
bool flag = (root->value>0)&&isRedBlack(root,sum);
if (flag)printf("Yes\n");
else printf("No\n");
}
return 0;
}
————————————————————————————————
AVL
————————————————————————————————
AVL建树(AVL标准模板)
1066
//核心: AVL建树
//AVL检查的好办法: 注释掉AVL的部分, 只检查BST;
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
struct node {
int value;
node *left, *right;
node(int x) {
value = x;
left = nullptr;
right = nullptr;
}
};
int n;
node* root=nullptr;
int getHeight(node* tree) {
if (tree == nullptr)return 0;
int l = getHeight(tree->left);
int r = getHeight(tree->right);
return max(l, r) + 1;
}
node* leftRotate(node* tree) {
node* tmp = tree->right;
tree->right = tmp->left;
tmp->left = tree;
return tmp;
}
node* rightRotate(node* tree) {
node* tmp = tree->left;
tree->left = tmp->right;
tmp->right = tree;
return tmp;
}
node* lrRotate(node* tree) {
tree->left = leftRotate(tree->left);
return rightRotate(tree);
}
node* rlRotate(node* tree) {
tree->right = rightRotate(tree->right);
return leftRotate(tree);
}
node* insert(node* &tree, int x) {
if (tree == nullptr) {
tree = new node(x);
return tree;
}
if (tree->value > x) {
insert(tree->left, x);
int l = getHeight(tree->left);
int r = getHeight(tree->right);
if ((l - r) >= 2) {
if (x < tree->left->value)tree = rightRotate(tree);
else tree = lrRotate(tree);
}
}
else if (tree->value <= x) {
insert(tree->right, x);
int l = getHeight(tree->left);
int r = getHeight(tree->right);
if ((r - l) >= 2) {
if (x > tree->right->value)tree = leftRotate(tree);
else tree = rlRotate(tree);
}
}
return tree;
}
//void preOrder(node* tree) {
// if (tree == nullptr)return;
//
// printf("%d ", tree->value);
// preOrder(tree->left);
// preOrder(tree->right);
//}
int main() {
scanf("%d", &n);
for (int i = 0; i < n; i++) {
int tmp;
scanf("%d", &tmp);
root = insert(root, tmp);
}
//preOrder(root);
//printf("\n");
printf("%d", root->value);
return 0;
}
AVL建树+判断完全二叉树+层序遍历
1123
//核心: AVL建立平衡二叉树 + 判断是否平衡二叉树 + 层序遍历输出
//1.AVL:
// (1)理解AVL的本质: 就是BST, 在插入的时候分情况
// (2)数据结构: 树:一般是node*的形式
// (3)操作:
// 1)建树: 输入 + insert(node* &root, int x);
// 2)其他如普通树的操作
// (4)函数:
// 1)int getHeight(node* tree){
// if(tree==nullptr)return 0;
// int l=getHeight(tree->left);
// int r=getHeight(tree->right);
// return max(l, r)+1;
// }
//
// 2)node* leftRotate(node* tree){
// node* tmp=tree->right; //哪边有获得哪边
// tree->right=tmp->left; //原本的位置补一个空缺
// tmp->left=tree; //什么叫左旋
// return tmp;
// }
// 3)node* rightRotate(node* tree){
// node* tmp=tree->left; //哪边有获得哪边
// tree->left=tmp->right; //原本的位置补一个空缺
// tmp->right=tree; //什么叫右旋
// return tmp;
// }
//
// 4)lrRotate(node* tree){
// tree->left=leftRotate(tree->left);
// return rightRotate(tree);
// }
// 5)rlRotate(node* tree){
// tree->right=rightRotate(tree->right);
// return leftRotate(tree);
// }
// 6)insert(node* &tree, int x){
// if(tree==nullptr){
// tree=new node(x);
// return tree;
// }
// if(tree->value>x){
// insert(tree->left, x);
// int l=getHeight(tree->left);
// int r=getHeight(tree->right);
// if((l-r)>=2){
// if(x<tree->left->value)rightRotate(tree);
// else tree=lrRotate(tree);
// }
// }
// if(tree->value<x){
// insert(tree->right,x);
// int l=getHeight(tree->left);
// int r=getHeight(tree->right);
// if((r-l)>=2){
// if(x>tree->right->value)leftRotate(tree);
// else tree=rlRotate(tree);
// }
// }
// return tree;
// }
//2.判断一棵树是否平衡二叉树:
// (1)特殊样例: 根节点: 左没有, 右有: flag==2;
// (2)if else 语句判别
//3.结尾多一个“\n”也会PE, 没有“\n”会WA
#include<iostream>
#include<vector>
#include<unordered_map>
#include<set>
#include<queue>
#include<algorithm>
using namespace std;
struct node {
int value;
node *left, *right;
node(int x) {
value = x;
left = nullptr;
right = nullptr;
}
};
int n, flag=0;
node* root=nullptr;
int getHeight(node *tmpRoot) {
if (tmpRoot == nullptr)return 0;
int l = getHeight(tmpRoot->left);
int r = getHeight(tmpRoot->right);
return max(l, r) + 1;
}
node* leftRotate(node* tmpRoot) {
node* tmp = tmpRoot->right;
tmpRoot->right = tmp->left;
tmp->left = tmpRoot;
return tmp;
}
node* rightRotate(node* tmpRoot) {
node* tmp = tmpRoot->left;
tmpRoot->left = tmp->right;
tmp->right = tmpRoot;
return tmp;
}
node* rlRotate(node* tmpRoot) {
tmpRoot->right = rightRotate(tmpRoot->right);
return leftRotate(tmpRoot);
}
node* lrRotate(node* tmpRoot) {
tmpRoot->left = leftRotate(tmpRoot->left);
return rightRotate(tmpRoot);
}
node* insert(node* &tmpRoot, int tmp) {
if (tmpRoot == nullptr) {
tmpRoot = new node(tmp);
return tmpRoot;
}
if (tmpRoot->value > tmp) {
tmpRoot->left=insert(tmpRoot->left, tmp);
int l = getHeight(tmpRoot->left);
int r = getHeight(tmpRoot->right);
if ((l - r) >= 2) {
if (tmp < tmpRoot->left->value)tmpRoot = rightRotate(tmpRoot);
else tmpRoot = lrRotate(tmpRoot);
}
}
else if (tmpRoot->value <= tmp) {
tmpRoot->right=insert(tmpRoot->right, tmp);
int l = getHeight(tmpRoot->left);
int r = getHeight(tmpRoot->right);
if ((r - l) >= 2) {
if (tmp > tmpRoot->right->value) tmpRoot = leftRotate(tmpRoot);
else tmpRoot = rlRotate(tmpRoot);
}
}
return tmpRoot;
}
void levelOrder(node* tmpRoot) {
queue<node*>q;
q.push(tmpRoot);
if (tmpRoot->left == nullptr && (tmpRoot->right != nullptr))flag = 2;
while (!q.empty()) {
node* current = q.front();
q.pop();
if (current != tmpRoot)printf(" ");
printf("%d",current->value);
if (flag == 0 && (current->left == nullptr || current->right == nullptr))flag = 1;
else if (flag == 1 && (current->left != nullptr || current->right != nullptr))flag = 2;
if (current->left != nullptr)q.push(current->left);
if (current->right != nullptr)q.push(current->right);
}
printf("\n");
if (flag == 2)printf("NO");
else printf("YES");
}
int main() {
scanf("%d", &n);
for (int i = 0; i < n; i++) {
int tmp;
scanf("%d", &tmp);
root = insert(root, tmp);
}
levelOrder(root);
printf("\n");
return 0;
}