A Binary Search Tree (BST) is recursively defined as a binary tree which has the following properties:
The left subtree of a node contains only nodes with keys less than the node's key.The right subtree of a node contains only nodes with keys greater than or equal to the node's key.Both the left and right subtrees must also be binary search trees.A Complete Binary Tree (CBT) is a tree that is completely filled, with the possible exception of the bottom level, which is filled from left to right.
Now given a sequence of distinct non-negative integer keys, a unique BST can be constructed if it is required that the tree must also be a CBT. You are supposed to output the level order traversal sequence of this BST.
Input Specification:
Each input file contains one test case. For each case, the first line contains a positive integer N (≤1000). Then N distinct non-negative integer keys are given in the next line. All the numbers in a line are separated by a space and are no greater than 2000.
Output Specification:
For each test case, print in one line the level order traversal sequence of the corresponding complete binary search tree. All the numbers in a line must be separated by a space, and there must be no extra space at the end of the line.
Sample Input:
10
1 2 3 4 5 6 7 8 9 0
Sample Output:
6 3 8 1 5 7 9 0 2 4
个人分析:题目要求根据输入,建立唯一的完全二叉搜索树,并且输出其层序遍历。
首先,菜鸡就考虑用链表or数组来表示树,在这道题里,完全二叉树,意味着即使是数组存储,也不会存在空间的浪费。并且,数组存储的顺序就是层序遍历的输出顺序,这么看来,如果使用数组,只需要解决建树问题,层序遍历可以直接输出。
其次,如何实现建立完全二叉搜索树,乍一看有两种想法:
1.实时模拟结点插入过程。菜鸡已经知道如何建立平衡二叉搜索树,其窍门是在每次插入结点的时候实时判断父结点是否平衡,从而调控树。那么在这里,也应该可以在每次插入结点的时候改进判断条件,调整树,得到正确的完全二叉搜索树。
(然而,很惨烈的是,这里的判断条件菜鸡没能想出来,在平衡二叉搜索树时,只需要检验某结点的左右子树高度,就能判断是否平衡;完全二叉搜索树时,某结点左右子树的结点数之间没有很明确的关系。)
2.调整已有完全二叉树。所谓完全二叉树,一旦确定总结点数,其形状结构是完全确定的。也就是说,我们可以根据传入的总结点数,默认已经建立起一颗完全二叉树,其从上到下从左到右的结点即为输入数列。我们需要做的,就是把这棵树,一个结点一个结点的调整成搜索树(或一个结点一个结点提取出来,放入另一空树内)。
最后,采取第2方法,特别注意:
如何调整成搜索树呢?
先确定根位置该放哪个结点,再递归的调整其左子树+右子树。而根结点数值=左子树结点数+1。所以我们设法取得左子树的结点数:
先把输入序列递增排序,这样才能确保上述方法可行。
设树高h层,那么前H=h-1层一定都是满的,而最后第h层情况特殊。所以,先确定左子树在前H层的结点数目,而第h层中左子树所占的结点数=Min{ (树总结点数 - H层满树结点数);第h层满结点/2}。
——————我是分割线啦啦啦————————————
其他细节,代码里有注释。上代码:
#include<stdio.h>
#include<stdlib.h>
#include<cmath>
#include<math.h>
#define Maxsize 1000
int GetLeftLength(int n)
{
int h,X,L;
h=floor(log(n+1)/log(2)); //floor(i)返回一个小于i的最大整数,用于取得树高h
X=n-pow(2,h)+1; //最底层结点数X(可能值)
if(pow(2,h-1)>X)
L=pow(2,h-1)-1+X;
else
L=pow(2,h-1)-1+pow(2,h-1);
return L;
}
void solve(int ALeft,int ARight,int TRoot,int T[],int A[])
{
int n,L,LeftTRoot,RightTRoot; //n为当前处理段的总结点数,L为当前结点左子树结点数
n=ARight-ALeft+1; //LeftTRoot左儿子,RightTRoot右儿子
if(n==0) return; //退出递归的条件:已到叶结点
L=GetLeftLength(n);
T[TRoot]=A[ALeft+L]; //确定当前根位置结点数值
LeftTRoot=TRoot*2+1;
RightTRoot=LeftTRoot+1;
solve(ALeft,ALeft+L-1,LeftTRoot,T,A); //递归得解决左子树
solve(ALeft+L+1,ARight,RightTRoot,T,A); //递归得解决右子树
}
void setorder(int A[],int N) //orz,直接用了O(N2)简单排序,顾不得那么多了...
{
for(int i=0;i<N;i++)
{
for(int j=0;j<N-i-1;j++)
{
if(A[j]>A[j+1])
{
int c=A[j+1];
A[j+1]=A[j];
A[j]=c;
}
}
}
}
int main()
{
int A[Maxsize],T[Maxsize];//A为输入完全二叉树,T为空树,需将A中结点按要求填入T中。
int num;
scanf("%d",&num);
getchar();
for(int i=0;i<num;i++)
scanf("%d",&A[i]);
setorder(A,num); //将输入序列递增排序
solve(0,num-1,0,T,A); //根据要求建立完全二叉搜索树
printf("%d",T[0]);
for(int j=1;j<num;j++)
{
printf(" %d",T[j]);
}
return 0;
}
测试结果:
总结:数学真重要,数字感觉真重要,教练!我要学数学!!!!溜了溜了.......