题目:
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 Ndistinct 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
题目理解
大概就是输入的这个序列,能唯一地组成一棵既是完全二叉树,又是二叉搜索树的树。要求输出这棵树的层序遍历。
思路
因为既是完全二叉树又是二叉搜索树,那么两者的特征这棵树也有。完全二叉树可以凭借节点的数量来确定树的形状,二叉搜索树每个节点的左子树所有节点一定小于该节点,右子树一定大于。凭借这两点可以发现这种树的根节点很好确认。
发现可以不用递归,就用循环去做了。先将输入序列由小到大进行排序,存储在数组a中(意外发现这是中序的顺序x),然后利用树的特征算出左右子树的大小,在a中找到根节点。接下来对左右子树做同样的操作,得到左右子树的根节点。
因为没用递归所以换了结构体来存储根节点的信息,比如该节点左右子树的大小,该节点的值与该节点于a中的下标。循环写起来就没有递归简洁了但是我实在太怕爆栈啊啥的…
代码
#include<stdio.h>
#include<stdlib.h>
#include<math.h>
#pragma warning(disable:4996)
#define MAXN 1005
int N, a[MAXN];
typedef struct TreeNode *PtrT;
struct TreeNode
{
int index;
int leftsize;
int rightsize;
int value;
};
int less(int i, int j)
{
return i < j;
}
void exch(int *a, int i, int j)
{
int t;
t = *(a + i);
*(a + i) = *(a + j);
*(a + j) = t;
}
void Sort(int *a,int N)
{
int h = 1, i, j;
while (h < N / 3)
h = h * 3 + 1;
while (h >= 1)
{
for (i = h; i < N; i++)
for (j = i; j >= h && less(a[j], a[j - h]); j -= h)
exch(a, j, j - h);
h = h / 3;
}
}
PtrT FindHead(int *a, int Size, int Pos)
{
PtrT T;
T = (PtrT)malloc(sizeof(struct TreeNode));
if (Size == 1)
{
T->value = a[Pos];
T->index = Pos;
T->leftsize = 0;
T->rightsize = 0;
}
else
{
int k, lev, head, indH;
for (k = 0; pow(2, k) - 1 <= Size; k++);
lev = Size - pow(2, k - 1) + 1;
if (lev < pow(2, k - 2))
head = (Size + lev) / 2;
else head = pow(2, k - 1) - 1;
indH = Pos + head;
T->value = a[indH];
T->index = indH;
T->leftsize = head;
T->rightsize = Size - 1 - head;
}
return T;
}
int main()
{
scanf("%d", &N);
TreeNode T[MAXN];
for (int i = 0; i < N; i++)
scanf("%d", a + i);
Sort(a, N);
T[0] = *(FindHead(a, N, 0));
for (int i = 1; i < N; i++)
{
int indexF, sizeT, posL;
if (i % 2)
{
indexF = i / 2;
sizeT = T[indexF].leftsize;
posL = T[indexF].index - sizeT;
}
else
{
indexF = (i - 1) / 2;
sizeT = T[indexF].rightsize;
posL = T[indexF].index + 1;
}
T[i] = *(FindHead(a, sizeT, posL));
}
int i;
for (i = 0; i < N - 1; i++)
printf("%d ", T[i].value);
printf("%d\n", T[i].value);
/*for (i = 0; i < N - 1; i++)
{
printf("value:%d index:%d ls:%d rs:%d\n", T[i].value, T[i].index, T[i].leftsize, T[i].rightsize);
}
printf("value:%d index:%d ls:%d rs:%d\n", T[i].value, T[i].index, T[i].leftsize, T[i].rightsize);*/
system("pause");
return 0;
}
之后又在网上查到一种方法,比较抽象但是真滴很简洁。
将层序遍历的顺序(即下标)用中序输出,得到数组b。则有层序输出为:c[b[i]]=a[i]
画个图,可能会清楚一点
想通了大概就是,为了层序输出,需要把层序输出的顺序和树的节点对应上,即树的节点在层序输出中的下标对应上。将下标以中序输出,与节点的中序输出同步上了,即知道了层序输出的每个下标对应了哪个节点。最后按下标的层序(即由小到大)输出其对应的节点,也就是树的层序输出(好罗嗦哦)