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;
}
测试结果:
总结:数学真重要,数字感觉真重要,教练!我要学数学!!!!溜了溜了.......