binary search tree(bst)
什么是bst?
bst树,通常称为二叉搜索树,又叫二叉排序树,bst是一种特殊的二叉树结构,也是一种常见的数据结构类型,其中,bst很明显的特性是根节点大于左子树的节点小于右子树的节点,并且满足其子树又是一颗独立的bst树。
二叉搜索树的应用基本有名次树(树堆),AVL(平衡二叉树),splay树,sbt树和恶名昭著红黑树
bst的基本操作有建树(插入),删除,查找,其中删除有较为特殊,分为两种情况,其余细节请自行baidu或者查书
这里简单说说bst的几个细节小性质:
1.建树如果给定序列,则形成的bst是唯一的,最坏情况是单枝树,最好情况是一颗完美二叉树(满二叉树)
2.在删除bst节点的时候,如果是删除非叶节点,一般是找左子树的最大节点或者是右子树的最小节点,
换句话说,就是左子树的最右节点和右子树的最左节点(请思考是为甚么)
3.bst的inorder是可以得到一个有序的in序列的,从小到大排序的一般是
4.键值最大的bst节点没有右儿子,键值最小的节点没有左儿子
上面就是bst的几个小性质,主要还是练手,其中练手题基本以bst的建立和遍历有关,说实话我见到的bst的题没怎么有删除的,当然poj的2418还没做,这个就不予评价了
pta:
https://pintia.cn/problem-sets/994805342720868352/problems/994805440976633856
https://pintia.cn/problem-sets/994805342720868352/problems/994805407749357568
https://pintia.cn/problem-sets/994805342720868352/problems/994805367987355648
hdu:
http://acm.hdu.edu.cn/showproblem.php?pid=3999
http://acm.hdu.edu.cn/showproblem.php?pid=3791
p:
http://poj.org/problem?id=2418(还没做不知道啥情况)
按顺序讲:
pta1043:
题目大意:
给定一个bst的序列,要求判断这个序列是否是bst的先序序列或者是镜像先序序列,所谓镜像就是交换左右子树,
如果是先序序列就输出YES并且输出后序序列
如果是镜像先序序列就输出YES同样输出镜像后序序列
两者都非是No;
问?怎么设计?
答:用vector会方便很多,这样就不用for循环判断了,其余的就是bst算法,用给定的序列建树,并且进行先序遍历和镜像先序遍历,并根据给的条件进行输出
参考code:
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define int long long 4 #define IOS ios_base::sync_with_stdio(0);cin.tie(0);cout.tie(0); 5 int n; 6 vector<int>a; 7 vector<int>pre; 8 vector<int>post; 9 vector<int>preM; 10 vector<int>postM; 11 struct node { 12 int data; 13 node *l; 14 node *r; 15 node(int data=0,node *l=NULL,node *r=NULL):data(data),l(l),r(r) {} 16 }; 17 void insert(node *&root,int x) { 18 if(root==NULL) { 19 root=new node; 20 root->data=x; 21 root->l=root->r=NULL; 22 return ; 23 } else if(root->data>x) { 24 insert(root->l,x); 25 } else { 26 insert(root->r,x); 27 } 28 } 29 30 void preorder(node *&root) { 31 if(root!=NULL) { 32 pre.push_back(root->data); 33 preorder(root->l); 34 preorder(root->r); 35 } 36 } 37 void postorder(node *&root) { 38 if(root!=NULL) { 39 postorder(root->l); 40 postorder(root->r); 41 post.push_back(root->data); 42 } 43 } 44 void preorderM(node *&root) { 45 if(root!=NULL) { 46 preM.push_back(root->data); 47 preorderM(root->r); 48 preorderM(root->l); 49 } 50 } 51 void postorderM(node *&root) { 52 if(root!=NULL) { 53 postorderM(root->r); 54 postorderM(root->l); 55 postM.push_back(root->data); 56 } 57 } 58 node *buildtree(node *&root) 59 { 60 cin>>n; 61 for(int i=0; i<n; i++) { 62 int d; 63 cin>>d; 64 a.push_back(d); 65 insert(root,d); 66 } 67 return root; 68 } 69 signed main() { 70 IOS; 71 node *root=NULL; 72 root=buildtree(root); 73 preorder(root); 74 preorderM(root); 75 postorder(root); 76 postorderM(root); 77 if(pre==a) { 78 cout<<"YES"<<endl; 79 for(int i=0; i<post.size(); i++) { 80 cout<<post[i]; 81 if(i<post.size()-1) 82 cout<<" "; 83 } 84 } else if(preM==a) { 85 cout<<"YES"<<endl; 86 for(int i=0; i<postM.size(); i++) { 87 cout<<postM[i]; 88 if(i<postM.size()-1) 89 cout<<" "; 90 } 91 } else { 92 cout<<"NO"; 93 } 94 return 0; 95 }
pta1064:
题目大意:给定一个序列,要求输出完全bst的层序遍历序列
完全bst是完全二叉树+bst
问?怎么做?
答:这个题就比较有意思了,因为你要是按照常规建树bfs,会发现不行。
其实我们可以设一个数组来表示经过bfs后的完全bst的序列,只不过还没有赋值
并且,对于一颗完全二叉树来讲,2*index是他的左孩子,2*index+1是右孩子,所以说我们在建树和遍历的过程中就可以充分利用这条性质
前面说到,bst的inorder得到的是一个有序的序列,我们就可以将题目给我们的序列进行一个排序,这样得到的就是一个中序bst序列,在将这个中序bst序列在中序遍历中挨个赋值给我们设计的bfs后的bst序列,最后输出就可以了
AC正确参考代码:
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define int long long 4 #define IOS ios_base::sync_with_stdio(0);cin.tie(0);cout.tie(0); 5 const int N=1e3+10; 6 struct node 7 { 8 int data; 9 node *l; 10 node *r; 11 node(int data=0,node *l=NULL,node *r=NULL):data(data),l(l),r(r){} 12 };//其实这个结构体定不定义都无所谓了 13 int a[N]; 14 int n; 15 int cbt[N];//经过bfs后的complete bst 16 int cnt=1; 17 void inorder(int root) 18 { 19 if(root>n) 20 return ; 21 inorder(root*2);//完全二叉树的性质左孩子 22 cbt[root]=a[cnt++];//将中序的序列挨个赋值 23 inorder(root*2+1);//右孩子 24 } 25 signed main() 26 { 27 IOS; 28 cin>>n; 29 for(int i=1;i<=n;i++) 30 cin>>a[i]; 31 sort(a+1,a+1+n);//得到一个中序序列 32 inorder(1);//根节点从第一层开始 33 for(int i=1;i<=n;i++) 34 { 35 cout<<cbt[i]; 36 if(i<n) 37 cout<<" "; 38 } 39 return 0; 40 }
再给一个错误代码以供鞭打:
wrong answer:
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define int long long 4 #define IOS ios_base::sync_with_stdio(0);cin.tie(0);cout.tie(0); 5 const int N=1e3+10; 6 int n; 7 int a[N]; 8 int level[N]; 9 int cnt; 10 struct node 11 { 12 int data; 13 node *l; 14 node *r; 15 node(int data=0,node *l=NULL,node *r=NULL):data(data),l(l),r(r){} 16 }; 17 void bfs(node *&root) 18 { 19 queue<node *>q; 20 q.push(root); 21 while(!q.empty()) 22 { 23 node *now=q.front(); 24 q.pop(); 25 cout<<now->data; 26 cnt++; 27 if(cnt<n) 28 cout<<" "; 29 if(now->l!=NULL) 30 q.push(now->l); 31 if(now->r!=NULL) 32 q.push(now->r); 33 } 34 } 35 void insert(node *&root,int x) 36 { 37 if(root==NULL) 38 { 39 root=new node; 40 root->data=x; 41 root->l=root->r=NULL; 42 return ; 43 } 44 else if(root->data==x) 45 return ; 46 else if(root->data>x) 47 { 48 insert(root->l,x); 49 } 50 else 51 { 52 insert(root->r,x); 53 } 54 } 55 node *buildtree(node *&root) 56 { 57 for(int i=1;i<=n;i++) 58 { 59 insert(root,a[i]); 60 } 61 return root; 62 } 63 signed main() 64 { 65 IOS; 66 cin>>n; 67 for(int i=1;i<=n;i++) 68 cin>>a[i]; 69 node *root=buildtree(root); 70 bfs(root); 71 //for(int i=1;i<=n;i++) 72 //{ 73 //cout<<level[i]; 74 //if(i<n) 75 //cout<<" " 76 // 77 // return 0; 78 }
pta1099
题目大意:给定一组不同数字的数组,并且有唯一的方式来填满这颗树
给定的输入是酱紫的:
9//总结点
1 6//左孩子,右孩子的下标,如果是-1就证明该位置没有孩子
2 3
-1 -1
-1 4
5 -1
-1 -1
7 -1
-1 8
-1 -1
73 45 11 58 82 25 67 38 42//给定的序列
题目要求输出这个bst的层序遍历序列
问?咋弄?
答:用静态二叉树写法就可以啦,因为出现-1了,直接用静态二叉树来表示,如果节点是-1就相当于该位置NULL,如果你不嫌麻烦用二叉树写法也可以,判断该位置后赋一个NULL也行
其余的就是正常建树插入bfs了
参考code
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define int long long 4 #define IOS ios_base::sync_with_stdio(0);cin.tie(0);cout.tie(0); 5 const int N=1e2+10; 6 int a[N]; 7 int n; 8 struct node 9 { 10 int data; 11 int l; 12 int r; 13 }bst[N]; 14 int cnt1; 15 int cnt2; 16 void bfs(int root) 17 { 18 queue<int>q; 19 q.push(root); 20 while(!q.empty()) 21 { 22 int now=q.front(); 23 q.pop(); 24 cout<<bst[now].data; 25 cnt1++; 26 if(cnt1<n) 27 cout<<" "; 28 if(bst[now].l!=-1) 29 q.push(bst[now].l); 30 if(bst[now].r!=-1) 31 q.push(bst[now].r); 32 } 33 } 34 void inorder(int root) 35 { 36 if(root!=-1){ 37 inorder(bst[root].l); 38 bst[root].data=a[cnt2++]; 39 inorder(bst[root].r); 40 } 41 } 42 signed main() 43 { 44 IOS; 45 cin>>n; 46 for(int i=0;i<n;i++) 47 { 48 int lc,rc; 49 cin>>lc>>rc; 50 bst[i].l=lc; 51 bst[i].r=rc; 52 } 53 for(int i=0;i<n;i++) 54 cin>>a[i]; 55 sort(a,a+n); 56 inorder(0); 57 bfs(0); 58 /*for(int i=1;i<=n;i++) 59 { 60 cout<<bst[i].data; 61 if(i<n) 62 cout<<" ";*/ 63 return 0; 64 }
hduoj 3999:
题目大意:
给定一组bst序列,要求和这颗树同构的字典序最小的序列
问?how deal with it?
答:一个先序遍历就够了?为甚么是先序遍历呢?先序遍历得到的是字典序最小码?
是的,因为先序序列是左-根-右的遍历形式
而bst的性质是根大于左而小于右,所以说一个先序遍历就可以求出字典序最小的同构序列了
参考代码:
1 Problem: The order of a Tree 2 // Contest: HDOJ 3 // URL: http://acm.hdu.edu.cn/showproblem.php?pid=3999 4 // Memory Limit: 32 MB 5 // Time Limit: 2000 ms 6 // 7 // Powered by CP Editor 8 #include<bits/stdc++.h>//hduoj 3999 9 using namespace std; 10 #define int long long 11 #define IOS ios_base::sync_with_stdio(0);cin.tie(0);cout.tie(0); 12 const int N=1e5+10; 13 int n; 14 int a[N]; 15 int cnt1; 16 int cnt2; 17 int cnt3; 18 int cnt4; 19 int pre[N]; 20 int in[N]; 21 int post[N]; 22 int level[N]; 23 struct node { 24 int data; 25 node *l; 26 node *r; 27 node(int data=0,node *l=NULL,node *r=NULL):data(data),l(l),r(r) {} 28 }; 29 void insert(node *&root,int x) { 30 if(root==NULL) { 31 root=new node; 32 root->data=x; 33 root->l=root->r=NULL; 34 return ; 35 } else if(root->data>x) { 36 insert(root->l,x); 37 } else { 38 insert(root->r,x); 39 } 40 } 41 node *buildtree(node *&root) 42 { 43 for(int i=0; i<n; i++) { 44 insert(root,a[i]); 45 } 46 return root; 47 } 48 void preorder(node *&root) 49 { 50 if(root!=NULL) 51 { 52 pre[cnt1++]=root->data; 53 preorder(root->l); 54 preorder(root->r); 55 } 56 } 57 void inorder(node *&root) 58 { 59 if(root!=NULL) 60 { 61 inorder(root->l); 62 in[cnt2++]=root->data; 63 inorder(root->r); 64 } 65 } 66 void postorder(node *&root) 67 { 68 if(root!=NULL) 69 { 70 postorder(root->l); 71 postorder(root->r); 72 post[cnt3++]=root->data; 73 } 74 } 75 void bfs(node *&root) 76 { 77 queue<node *>q; 78 q.push(root); 79 while(!q.empty()) 80 { 81 node *now=q.front(); 82 q.pop(); 83 cout<<now->data; 84 cnt4++; 85 if(cnt4<n) 86 cout<<" "; 87 if(now->l!=NULL) 88 q.push(now->l); 89 if(now->r!=NULL) 90 q.push(root->r); 91 } 92 } 93 signed main() { 94 IOS; 95 node *root=NULL; 96 cin>>n; 97 for(int i=0;i<n;i++) 98 cin>>a[i]; 99 root=buildtree(root); 100 preorder(root); 101 for(int i=0;i<n;i++) 102 { 103 cout<<pre[i]; 104 if(i<n-1) 105 cout<<" "; 106 } 107 cout<<endl; 108 return 0; 109 110 }
hduoj 3791
题目大意:呸,中文题翻个pi
这道题是zju的研究生复试上机题,兄弟们给我冲
参考代码:
1 // Problem: 二叉搜索树 2 // Contest: HDOJ 3 // URL: http://acm.hdu.edu.cn/showproblem.php?pid=3791 4 // Memory Limit: 32 MB 5 // Time Limit: 2000 ms 6 // 7 // Powered by CP Editor 8 #include<bits/stdc++.h>//hduoj 3791 9 using namespace std; 10 #define int long long 11 #define IOS ios_base::sync_with_stdio(0);cin.tie(0);cout.tie(0); 12 const int N=1e5+10; 13 int n; 14 using namespace std; 15 struct node{ 16 node *l,*r; 17 char v; 18 }; 19 void build(node *&a,char c) 20 { 21 if(a==NULL) 22 { 23 a=new node; 24 a->l=a->r=NULL; 25 a->v=c; 26 return; 27 } 28 if(c < a->v) 29 build(a->l,c); 30 else 31 build(a->r,c); 32 } 33 34 bool cmp(node *a,node *b) 35 { 36 if(a==NULL&&b==NULL) 37 return true; 38 if((a==NULL&&b!=NULL)||(a!=NULL&&b==NULL)) 39 return false; 40 if(a->v!=b->v) 41 return false; 42 return cmp(a->l,b->l)&&cmp(a->r,b->r); 43 } 44 45 signed main() 46 { 47 IOS; 48 while(cin>>n&&n) 49 { 50 node *root=NULL,*tree=NULL; 51 string str1,str2; 52 cin>>str1; 53 for(int i=0;i<str1.size();i++) 54 { 55 build(root,str1[i]); 56 } 57 for(int i=0;i<n;i++) 58 { 59 cin>>str2; 60 if(str1.size()!=str2.size()) 61 printf("NO\n"); 62 else 63 { 64 tree=NULL; 65 for(int j=0;j<str2.size();j++) 66 { 67 build(tree,str2[j]); 68 } 69 if(cmp(root,tree)) 70 printf("YES\n"); 71 else 72 printf("NO\n"); 73 } 74 } 75 } 76 return 0; 77 }
poj 2418没做不知道难度,不过肯定也不好做
本文来自博客园,作者:江上舟摇,转载请注明原文链接:https://www.cnblogs.com/LQS-blog/p/16593109.html