题目大意:给定一些结点,构建完全二叉搜索树。
(注意完全二叉树不是满二叉树,而是一层一层从左往右叠满的,所以最后一层可能有空的位置。)
思路:我们知道二叉搜索树的中序遍历即为每个结点的从小到大排序,故我们可以先将结点排序,于是我们就得到了这课二叉树的中序遍历,于是问题就转化成了:已知中序遍历,求满二叉搜索树。我们要想使用中序遍历构建二叉树,关键点在于找到树(子树)的根结点,剩下的就好说了。那么满二叉树的根结点有什么规律呢?
首先,我们考虑满二叉树,结点数为:2^n-1(n为层数),那么如果我们将完全二叉树补满,则需要的结点数设为sub,sub可求,那么我们可以知道完全二叉树的最后一层结点的分布情况。将最后一层的结点分成所属左右子树两部分,则左子树的整棵树结点数可以求出设为num,则在中序遍历中前面的num个结点都所属左子树,则第num+1个结点就是根结点,然后以此类推,写一个递归就行了。
简而言之就是:已知完全二叉树的结点数,求左子树的结点数num,则根为第num+1个结点。
#include<bits/stdc++.h>
using namespace std;
struct node{
int val;
node* l;
node* r;
node(int x):val(x){}
};
int n;
int p[1010];
int fill(int x){
x++;
int k=log(x)/log(2);
if(pow(2,k)==x)return x-1;
else return pow(2,k+1)-1;
}
int bottom(int x){
int k=log(fill(x)+1)/log(2)-1;
return pow(2,k);
}
node* create(int l,int r){
if(l>r)return nullptr;
int len=r-l+1;
int sub=fill(len)-len;
int leaf=bottom(len)-sub;
int pos;
if(leaf>=sub){
pos=l+fill(len)/2;
}else{
pos=l+fill(len)/2-(bottom(len)/2-leaf);
}
node *nod=new node(p[pos]);
nod->l=create(l,pos-1);
nod->r=create(pos+1,r);
return nod;
}
int flag=0;
void leverorder(node* nod){
queue<node*>q;
q.push(nod);
while(q.size()){
int len=q.size();
while(len--){
node* f=q.front();
q.pop();
if(flag)cout<<' ';
cout<<f->val;flag=1;
if(f->l)
q.push(f->l);
if(f->r)
q.push(f->r);
}
}
}
int main(){
cin>>n;
for(int i=0;i<n;i++)cin>>p[i];
sort(p,p+n);
node* root=create(0,n-1);
leverorder(root);
}