BST定义
二叉查找树(Binary Search Tree,BST),(又:二叉搜索树,二叉排序树)它或者是一棵空树,或者是具有下列性质的二叉树:
- 若它的左子树不空,则左子树上所有结点的值均小于它的根结点的值;
- 若它的右子树不空,则右子树上所有结点的值均大于它的根结点的值;
- 它的左、右子树也分别为二叉排序树。
二叉搜索树作为一种经典的数据结构,它既有链表的快速插入与删除操作的特点,又有数组快速查找的优势;所以应用十分广泛,例如在文件系统和数据库系统一般会采用这种数据结构进行高效率的排序与检索操作。
例题
这是二叉搜索树吗
题意:
给定一个整数键值序列,现请你编写程序,判断这是否是对一棵二叉搜索树或其镜像进行前序遍历的结果。
有如下结论:
在此定义广义BST包括:一般BST和一般BST的镜像
用广义BST的先序a1构造出来的BST是唯一的,它的先序a2也是唯一的,满足 a 1 = = a 2 a1==a2 a1==a2
用非广义BST的先序a1构造出来的BST是唯一的,它的先序a2也是唯一的,满足 a 1 ! = a 2 a1!=a2 a1!=a2
思路:
直接用给定的整数键值序列a1来构造BST,之后求BST和其镜像的先序a2和a3,(递归求镜像的时候将leftchild和rightchild互换位置就好啦),只要a1和a2相同 或 a1和a3相同,就输出YES,反之输出NO.
注意:
1.用vector便于序列比较(不用去循环实现了)
2.通过样例一可发现:二叉搜索树可以有数值相等的节点
代码:
#include<bits/stdc++.h>
#define LL long long
#define fo(i,a,b) for(int i=a;i<b;i++)
using namespace std;
struct node{int data;node*lc;node*rc;};
vector<int> ori,pre,prem,post,postm;
void insert(node* &root,int d){//注意&的位置
if(root==NULL){
root=new node;//缺少竟然不会报错,是个坑
root->data=d;
root->lc=root->rc=NULL;
return;
}
if(d<root->data)insert(root->lc,d);
else if(d>=root->data)insert(root->rc,d);
}
//void preorder(node* &root,vector<int> &pre){:&没必要加
void preorder(node* root,vector<int> &pre){
if(root==NULL)return;
pre.push_back(root->data);
preorder(root->lc,pre);
preorder(root->rc,pre);
}
void preordermirror(node* root,vector<int> &prem){
if(root==NULL)return;
prem.push_back(root->data);
preordermirror(root->rc,prem);
preordermirror(root->lc,prem);
}
void postorder(node* root,vector<int> &post){
if(root==NULL)return;
postorder(root->lc,post);
postorder(root->rc,post);
post.push_back(root->data);
}
void postordermirror(node* root,vector<int> &postm){
if(root==NULL)return;
postordermirror(root->rc,postm);
postordermirror(root->lc,postm);
postm.push_back(root->data);
}
int main(){
int n,t;
cin>>n;
node* root=NULL;//空全部要大写
fo(i,0,n){
scanf("%d",&t);
ori.push_back(t);
insert(root,t);
}
preorder(root,pre);
preordermirror(root,prem);
postorder(root,post);
postordermirror(root,postm);
if(ori==pre){
cout<<"YES"<<endl;
int k=post.size();
fo(i,0,k){
if(i!=k-1)printf("%d ",post[i]);
else printf("%d",post[i]);
}
}
else if(ori==prem){
cout<<"YES"<<endl;
int k=postm.size();
fo(i,0,k){
if(i!=k-1)printf("%d ",postm[i]);
else printf("%d",postm[i]);
}
}
else cout<<"NO";
return 0;
}
二叉搜索树的结构
首先想的是利用插点法建树,数组存树,可能是数组没办法开太大,导致只有20分
20分代码:
#include <bits/stdc++.h>
#define debug(x) cout<<#x<<":"<<x<<endl;
#define f(i,a,n) for(int i=a;i<n;++i)
#define ff(i,a,n) for(int i=a;i<=n;++i)
const int INF=0x3f3f3f3f;
using namespace std;
typedef long long ll;
//
const int N=1e5+5;
int tree[N];
int n;
map<int,int> dep,pp;
int main(){
cin>>n;
f(i,0,n){
int t;cin>>t;
int pos=1,d=0;
while(tree[pos]){
if(t>tree[pos])pos=pos*2+1;
else pos=pos*2;
d++;
}
tree[pos]=t;
pp[t]=pos;
dep[t]=d;
}
int q;cin>>q;
string s;
while(q--){
int k1,k2;cin>>k1;
cin>>s;
if(s[0]=='a'){
cin>>k2;
cin>>s>>s;
//A and B are siblings
if(s[0]=='s'){
if(pp[k1]/2==pp[k2]/2)cout<<"Yes";
else cout<<"No";
}
//A and B are on the same level
else{
cin>>s>>s>>s;
if(dep[k1]==dep[k2])cout<<"Yes";
else cout<<"No";
}
}
else{
cin>>s>>s;
//A is the parent of B
if(s[0]=='p'){
cin>>s>>k2;
if(pp[k2]/2==pp[k1])cout<<"Yes";
else cout<<"No";
}
//A is the left child of B
else if(s[0]=='l'){
cin>>s>>s>>k2;
if(pp[k2]*2==pp[k1])cout<<"Yes";
else cout<<"No";
}
else{
//A is the root
if(s=="root"){
if(pp[k1]==1)cout<<"Yes";
else cout<<"No";
}
else{
cin>>s>>s>>k2;
if(pp[k2]*2+1==pp[k1])cout<<"Yes";
else cout<<"No";
}
}
}
cout<<endl;
}
return 0;
}
ac代码:
#include <bits/stdc++.h>
using namespace std;
struct node {
int num, lc, rc, parent, level;
node() {
//构造函数初始化
lc = rc = parent = -1;
}
}Tr[128];
int n, m, a, b, in, cnt, root = 1, f;
//离散化
map<int, int> mp;
string t;
void insert(int x) {
int now = root;
while(Tr[now].num != x) {
if (x < Tr[now].num) {
if (Tr[now].lc == -1) {
Tr[cnt].num = x;
Tr[cnt].level = Tr[now].level + 1;
Tr[cnt].parent = now;
Tr[now].lc = cnt;
}
now = Tr[now].lc;
}
else {
if (Tr[now].rc == -1) {
Tr[cnt].num = x;
Tr[cnt].level = Tr[now].level + 1;
Tr[cnt].parent = now;
Tr[now].rc = cnt;
}
now = Tr[now].rc;
}
}
}
int main() {
cin >> n >> in;
//Tree一般都从1开始,而不是0
Tr[++cnt].num = in;
mp[in] = cnt;
for (int i = 1; i < n; i++) {
cin >> in;
mp[in] = ++cnt;
insert(in);
}
cin >> m;
while (m--) {
f = 0;
cin >> a >> t;
if (t == "is") {
cin >> t >> t;
if (t == "root") {
if (mp[a] == root) f = 1;
}
else if (t == "parent") {
cin >> t >> b;
if (Tr[mp[b]].parent == mp[a]) f = 1;
}
else if (t == "left") {
cin >> t >> t >> b;
if (Tr[mp[b]].lc == mp[a]) f = 1;
}
else {
cin >> t >> t >> b;
if (Tr[mp[b]].rc == mp[a]) f = 1;
}
}
else {
cin >> b >> t >> t;
if (t == "siblings") {
if (mp[a] && mp[b] && Tr[mp[a]].parent == Tr[mp[b]].parent) f = 1;
}
else {
cin >> t >> t >> t;
if (mp[a] && mp[b] && Tr[mp[a]].level == Tr[mp[b]].level) f = 1;
}
}
cout << (f ? "Yes" : "No") << '\n';
}
return 0;
}
是否同一棵二叉搜索树
数组顺序存储求解即可
代码:
#include <bits/stdc++.h>
#define debug(x) cout<<#x<<":"<<x<<endl;
#define f(i,a,n) for(int i=a;i<n;++i)
#define ff(i,a,n) for(int i=a;i<=n;++i)
const int INF=0x3f3f3f3f;
using namespace std;
typedef long long ll;
//
const int N=1030;
vector<int> v1(N),v2(N);
void createTree(int n,vector<int> &v){
int key;
int index;
for (int i = 0; i < n; i++){
cin >> key;
index = 1;
while (v[index] != 0){ // 寻找插入点
if (key >= v[index]) index = index * 2 + 1;
else index *= 2;
}
v[index] = key;
}
}
int main() {
int n, L;
while (cin >> n){
if (n == 0)
break;
cin >> L;
f(i,0,v1.size())v1[i]=0;
createTree(n,v1);
for (int i = 0; i < L; i++){
f(j,0,v2.size())v2[j]=0;
createTree(n, v2);
if (v1==v2)
cout << "Yes" << endl;
else
cout << "No" << endl;
}
}
return 0;
}
是否完全二叉搜索树
完全二叉树:
一棵深度为k的有n个结点的二叉树,对树中的结点按从上至下、从左到右的顺序进行编号,如果编号为
i
(
1
≤
i
≤
n
)
i(1≤i≤n)
i(1≤i≤n)的结点与满二叉树中编号为
i
i
i 的结点在二叉树中的位置相同,则这棵二叉树称为完全二叉树。
代码:
#include <bits/stdc++.h>
#define closeSync ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
#define debug(x) cout<<#x<<":"<<x<<endl;
#define f(i,a,n) for(int i=a;i<n;++i)
#define ff(i,a,n) for(int i=a;i<=n;++i)
using namespace std;
const int N=(1<<21);
int tree[N];
int n;
int main(){
cin >> n;
int mx = 0;
//数组存树,构建二叉搜索树
f(i,0,n){
int x;
cin >> x;
int now = 1;
while(tree[now]){
if(x > tree[now]) now = now * 2;
else now = now * 2 + 1;
}
tree[now] = x;
if(now > mx)mx = now;
}
bool flg = true;
ff(i,1,mx){
//该位置有节点
if(tree[i]){
if(i != 1)
cout << " ";
cout << tree[i];
}
//该位置是空的
else
flg = false;
}
cout << endl;
if(flg)
cout << "YES" << endl;
else
cout << "NO" << endl;
return 0;
}
Complete Binary Search Tree
1064 Complete Binary Search Tree (30 分)
思路:
因为二叉排序树中序遍历单调递增,所以对输入数据从小到大排序,该顺序即为二叉排序树中序遍历的顺序,使用节点间的下标关系,对二叉排序树进行中序遍历,中序遍历过程中利用完全二叉树限制节点下标最大值即可
代码:
#include <cstdio>
#include <algorithm>
using namespace std;
const int maxn = 1010;
int n, number[maxn], CBT[maxn], index = 0;
void inOrder(int root){//中序遍历&&数据递增建立BST树
if(root > n)return;
inOrder(root * 2); //建立CBT树
CBT[root] = number[index++];
inOrder(root * 2 + 1); //建立CBT树
}
int main(){
scanf("%d", &n);
for(int i = 0; i < n; i++)
scanf("%d", &number[i]);
sort(number, number + n);
inOrder(1);//1号位为根节点
for(int i = 1; i <= n; i++){//CBT本身就是层序遍历
printf("%d", CBT[i]);
if(i < n)printf(" ");
}
return 0;
}
Build A Binary Search Tree
1099 Build A Binary Search Tree (30 分)
大意:
给一颗二叉树,并给一个序列,将这个序列填入二叉树中,使其构成二叉搜索树,输出层序遍历
思路:
利用二叉搜索树中序遍历是元素从小到大排列的顺序,把给定序列排序即可得到中序,中序遍历二叉树的同时填入数据即可
代码:
#include <cstdio>
#include <queue>
#include <algorithm>
using namespace std;
const int maxn = 110;
int data[maxn];
int n;
struct node{
int data;
int lc, rc;
}Node[maxn];
int num;
void inorder(int rt){
if (rt == -1)return;
inorder(Node[rt].lc);
Node[rt].data = data[num ++];
inorder(Node[rt].rc);
}
void layer_order(int rt){
queue<int> q;
q.push(rt);
int num = 0;
while (!q.empty()){
int now = q.front();
q.pop();
num ++;
printf("%d", Node[now].data);
if (num < n)printf(" ");
if (Node[now].lc != -1) q.push(Node[now].lc);
if (Node[now].rc != -1) q.push(Node[now].rc);
}
}
int main(){
scanf("%d", &n);
int lc, rc;
for (int i = 0; i < n; i ++){
scanf("%d %d", &lc, &rc);
Node[i].lc = lc;
Node[i].rc = rc;
}
for (int i = 0; i < n; i ++)scanf("%d", &data[i]);
sort(data, data + n);
inorder(0);//中序建树
layer_order(0);//层序遍历
return 0;
}