PTA习题:04-树6 Complete Binary Search Tree (30分)

04-树6 Complete Binary Search Tree (30分)

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

题目的大概意思是给一组数据,希望用这组数据创建一个既有二叉搜索树特点又有完全二叉树特点的完全二叉搜索树,最后用层序遍历输出各结点数据。
简单说一下思路:
以样例为例,如何确定根结点为6?
一共10个数据,因为有完全二叉树特点,所以从第一层开始每层结点数为1,2,4,最后一层没有填满,剩下的3个结点数,这3个结点从左边开始排起。由于3没有让最后一层超过半满,所以整棵树一共有4层,左子树有3层,右子树只有2层。
于是左子树总的结点数=1+2+3=6,右子树总的结点数=1+2=3。
由于有二叉搜索树的特点,左子树的所有结点均小于根结点,右子树的所有节点均大于根结点。将输入的10个数据从小到大排序,小的数在左子树,大的数在右子树。因此第7个数据(即这里的6)是完全二叉搜索树的根结点,0,1,2,3,4,5这6个结点组成左子树,7,8,9这3个结点组成右子树。
同理用0,1,2,3,4,5这6个数据按类似的方法确定根结点、左子树、右子树,递归可得左子树。
同理用7,8,9这3个数据按类似的方法确定根结点、左子树、右子树,递归可得右子树。
最后利用队列先进先出的特点,层序输出各结点。

C语言实现代码如下:

#include<stdio.h>
#include<stdlib.h>
struct Node
{
 int d;
 struct Node * left;
 struct Node * right;
};
typedef struct Node * Bintree;
struct row
{
 Bintree *a;
 int front;
 int rear;
};
typedef struct row * Row;
Bintree Create(int data[], int n);
void Print(Bintree B, int n);
void Add(Row R, Bintree B);
Bintree Delete(Row R);

int main()
{
 int n;
 scanf("%d", &n);
 if (n > 0)
 {
  int *data;
  data = (int *)malloc(n * sizeof(int));
  int i, j;
  Bintree B;
  //读入n个整数,存入数组data
  for (i = 0; i < n; i++)
  {
   scanf("%d", &data[i]);
  }
  //对数组data内的数据从小到大进行排序
  int temp, min, index = 0;
  for (i = 0; i < n; i++)
  {
   min = data[i];
   index = i;
   for (j = i + 1; j < n; j++)
   {
    if (data[j] < min) { min = data[j]; index = j; }
   }
   temp = data[i];
   data[i] = min;
   data[index] = temp;
  }
  //创建符合要求的完全二叉搜索树
  B = Create(data, n);
  //打印
  Print(B, n);
 }
 return 0;
}

//递归创建符合要求的完全二叉搜索树
Bintree Create(int data[], int n)
{
 Bintree B;
 //n==0和n==1是递归结束条件
 if (n == 0) { return NULL; }
 else if (n == 1)
 {
  B = (Bintree)malloc(sizeof(struct Node));
  B->d = data[0];
  B->left = B->right = NULL;
 }
 //递归主体
 else
 {
  int i = 1, j;
  //计算出n个结点搭建的完全二叉搜索树一共有多少层,用ceng记录
  int sum = 0;
  int layer[11];//layer数组记录每一层的结点数量,这里第i层对应layer[i]
  layer[0] = 0; layer[i] = 1;
  sum = sum + layer[1];
  while (sum < n)//用1,2,4,8...累加,加到sum超过n为止
  {
   i++;
   layer[i] = 2 * layer[i - 1];
   sum = sum + layer[i];
  }
  layer[i] = n - (sum - layer[i]);//最后一层可能未满,计算最后一层所含结点数
  int ceng = i;//记录完全二叉搜索树层数
  int leftn = 0, rightn = 0;//leftn记录左子树的结点个数,rightn记录右子树的结点个数
  for (i = 1; i < ceng; i++)
  {
   leftn = leftn + layer[i] / 2;
   rightn = rightn + layer[i] / 2;
  }
  //最后一层结点数少于半满状态,则右子树没有最后一层内的结点;超过半满,右子树有最后一层的结点
  if (layer[ceng] < layer[ceng - 1]) { leftn = leftn + layer[ceng]; }
  else {
   leftn = leftn + layer[ceng - 1];
   rightn = rightn + layer[ceng] - layer[ceng - 1];
  }
  //left数组记录左子树内从小到大排好序的结点,right数组记录右子树内从小到大排好序的结点
  int * left;
  left = (int *)malloc(leftn * sizeof(int));
  int * right;
  right = (int *)malloc(rightn * sizeof(int));
  for (i = 0; i < leftn; i++)
  {
   left[i] = data[i];
  }
  for (i = 0, j = leftn + 1; i < rightn; i++, j++)
  {
   right[i] = data[j];
  }
  //创建父结点,递归创建左子树和右子树
  B = (Bintree)malloc(sizeof(struct Node));
  B->d = data[leftn];
  B->left = B->right = NULL;
  B->left = Create(left, leftn);
  B->right = Create(right, rightn);
 }
 return B;
}

//层序遍历,打印结点
void Print(Bintree B, int n)
{
 int i;
 //创建队列
 Row R;
 R = (Row)malloc(sizeof(struct row));
 R->a = (Bintree *)malloc(n * sizeof(Bintree));
 for (i = 0; i < n; i++)
 {
  R->a[i] = (Bintree)malloc(sizeof(struct Node));
 }
 R->front = -1;
 R->rear = -1;
 //利用队列先进先出的特点。
 //先打印根结点,再将根结点左右子树压入队列,每弹出一个结点输出后,若其有左右子树,将其左右子树压入队列,直至队列为空
 Bintree T;
 printf("%d", B->d);
 if (n > 1)
 {
  Add(R, B->left);
  Add(R, B->right);
  while (R->front != R->rear)
  {
   T = Delete(R);
   printf(" %d", T->d);
   if (T->left != NULL) { Add(R, T->left); }
   if (T->right != NULL) { Add(R, T->right); }
  }
 }
}
void Add(Row R, Bintree B)
{
 R->rear++;
 R->a[R->rear] = B;
}
Bintree Delete(Row R)
{
 R->front++;
 return(R->a[R->front]);
}

9月13日补充:
C++实现:

#include <iostream>
using namespace std;
int flag = 0;
typedef struct bintree* BinTree;
struct bintree
{
	int d;
	BinTree Left;
	BinTree Right;
};
struct que
{
	BinTree* t;
	int front, rear;
};
typedef struct que* Queue;
Queue CreateQueue(int N)
{
	Queue Q = new struct que;
	Q->t = new BinTree[N];
	int i;
	for (i = 0; i < N; i++)
	{
		Q->t[i] = new struct bintree;
	}
	Q->front = Q->rear = -1;
	return Q;
}
void enqueue(Queue Q, BinTree X)
{
	Q->t[++Q->rear] = X;
}
BinTree dequeue(Queue Q)
{
	return Q->t[++Q->front];
}
bool IsEmpty(Queue Q)
{
	if (Q->front == Q->rear)return true;
	else return false;
}
int cmp(const void *a, const void *b)
{
	return *(int *)a - *(int *)b;
}
BinTree Set(int *data, int left, int N);
int main()
{
	int N;
	cin >> N;
	int * data = new int[N];
	int i;
	for (i = 0; i < N; i++)
	{
		cin >> data[i];
	}
	qsort(data, N, sizeof(int), cmp);
	BinTree BT=Set(data, 0, N);
	BinTree p = new struct bintree;
	Queue Q = CreateQueue(N);
	enqueue(Q, BT);
	while (!IsEmpty(Q))
	{
		p = dequeue(Q);
		if (flag == 0)
		{
			cout << p->d;
			flag = 1;
		}
		else cout << " " << p->d;
		if (p->Left != NULL)
		{
			enqueue(Q, p->Left);
		}
		if(p->Right!=NULL)
		{
			enqueue(Q, p->Right);
		}
	}
	return 0;
}
BinTree Set(int *data, int left, int N)
{
	if (N == 0)
	{
		return NULL;
	}
	if (N == 1)
	{
		BinTree B = new struct bintree;
		B->Left = B->Right = NULL;
		B->d = data[left];
		return B;
	}
	BinTree B = new struct bintree;
	B->Left = B->Right = NULL;
	int m = 1, sum = 1, lastlayer, root;
	while (sum < N)
	{
		m = m * 2;
		sum = sum + m;
	}
	if(sum!=N)sum = sum - m;
	lastlayer = N-sum;
	if (lastlayer <= m / 2)
	{
		root = lastlayer + (N - lastlayer) / 2+left;
		B->d = data[root];
	}
	else
	{
		root = m / 2 + (N - lastlayer) / 2+left;
		B->d = data[root];
	}
	B->Left=Set(data, left, root-left);
	B->Right=Set(data, root + 1, N - root - 1+left);
	return B;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值