菜鸡奋斗路04-树6 Complete Binary Search Tree

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
作者: 陈越
单位: 浙江大学
时间限制: 400ms
内存限制: 64MB
代码长度限制: 16KB


个人分析:题目要求根据输入,建立唯一的完全二叉搜索树,并且输出其层序遍历。

  首先,菜鸡就考虑用链表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;
}

测试结果:


总结:数学真重要,数字感觉真重要,教练!我要学数学!!!!溜了溜了.......


阅读更多
个人分类: data structe
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页

关闭
关闭
关闭