MOOC 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

 小结:

        这道题给我启发挺大的,递归还能这么用?!好像慢慢要理解递归的威力啦。

        之前自己思考时,已经想到了先满足完全二叉树,再调整为二叉搜索树,但是在怎么求根结点那里卡住了,还是缺乏编程思维,没有了解递归的真谛;收获颇多,诸君共勉。

/*
给定一组序列,给出它的完全二叉搜索树,1.这棵树是完全二叉树 2.是二叉搜索树 3.所有子树都是完全二叉搜索树

思路:找树根->递归找左树根->递归找右树根

核心算法:如何找树根:先排序->根据给定的数据个数N,推算出这棵树的高度H(高度为H的完全二叉树 最大结点数是2^H-1)
			所以N<=2^H-1 ①H=1,while(pow(2,H)<=N){H++;} 可以算出H,进而可以求出左边的结点个数L
						 ②H>=log2(N+1) 可以求得完美二叉树的高度 如果 2^H-1==N H就是这棵树的高度 否则就是H+1
						math.h里有log函数 是指以自然数e为底 根据换底公式 可以得出以2为底 log(N+1)/log(2)
*/
#include <stdio.h>
#include <math.h>
#define index int

void FromSmallToLargeSort( int* SortArray,int N );//给数组排序

void Swap( int* a,int *b );  //排序时用到的交换数组中两个值

void Solve( int* SortArray,index SortArrayLeft,index SortArrayRight,int* CBST,index Root );//核心算法 
			 /* 排好序的数组      数组的左边下标      右边下标          树         树根*/

int GetLeftNumbers( int n ); //计算左子树的结点个数

int Min( int X,int Y);

int main()
{
	int N;
	scanf("%d",&N);
	
	int i,SortArray[N];
	for(i=0;i<N;i++){
		scanf("%d",&SortArray[i]);
	}
	
	FromSmallToLargeSort( SortArray,N );
		
	int CBST[N+1];
	
	Solve( SortArray,0,N-1,CBST,1);
	
	int first = 1;
	for(i=1;i<N+1;i++){
		if(first){
			printf("%d",CBST[i]);
			first = 0;
		}else{
			printf(" %d",CBST[i]);	
		}	
	}
	
	return 0;
}

void FromSmallToLargeSort( int* SortArray,int N )
{
	int i,j;
	for(i=1;i<N;i++){
		for(j=0;j<i;j++){
			if(SortArray[j] > SortArray[i]){
				Swap( &SortArray[j],&SortArray[i]);
			}
		}
	}	
}

void Swap( int* a,int *b )
{
	int Temp = *a;
	*a = *b;
	*b = Temp;
}

void Solve( int* SortArray,index SortArrayLeft,index SortArrayRight,int* CBST,index Root )
{           /*根据一组有序的数组SortArray,推算出对应完全二叉搜索树的树根*/
   //首次调用 时取数组的最左和最右 即0 和 N-1,树根下标是 1
	int n = SortArrayRight - SortArrayLeft +1;//数组个数
	
	if(n==0){
		return;//递归出口
	}else{
		int L,LeftRoot,RightRoot;
		
		L = GetLeftNumbers( n ); //左子树的结点个数
		
		CBST[Root] = SortArray[SortArrayLeft+L]; //根据左子树的结点个数 推算出根结点
		
		LeftRoot = Root*2;         //左子树
		RightRoot = LeftRoot+1;    //右子树
		
		Solve( SortArray,SortArrayLeft,SortArrayLeft+L-1,CBST,LeftRoot ); //递归求左子树的根结点
		Solve( SortArray,SortArrayLeft+L+1,SortArrayRight,CBST,RightRoot );//递归求右子树的根结点
	}
}

int GetLeftNumbers( int n )
{
	int K = (int)(log(n+1)/log(2));//完美二叉树的层数
	/*
	K =0;
	while(pow(2,K)-1<n){
		K++;
	}  这样求出的是总层数
	*/
	int X = n+1-(int)pow(2,K);     //根据完美二叉树的层数 求出 最下面一层非完美的结点个数
	
	int XL = Min( X,(int)pow(2,K-1));   //根左树最下一层结点个数 最多等于上一层结点个数;比上一层少 非完美结点全在左边,
	
	int nL = (int)pow(2,K-1) - 1 + XL; //根结点左边结点个数
	
	return nL;
}
/* 推导思路:N个结点的完全二叉树,最下一层非完美结点数为X  =0表示这是棵完美二叉树
           到第K层都是完美二叉树,总结点数为2^k-1  
           则N = 2^K-1+X;
        根左树也是完全二叉树(或完美二叉树) 有K-1完美层 2^(K-1)-1  
        结点总数NL=2^(K-1)-1 + XL  */

int Min( int X,int Y)
{
	return (X<Y?X:Y);
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值