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.
输入格式
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.
输出格式
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.
样例
输入样例
10
1 2 3 4 5 6 7 8 9 0
输出样例
6 3 8 1 5 7 9 0 2 4
思路
因为是完全二叉树,显然用数组存储更为方便。
刚开始我一想,CBT,那不是比平衡二叉树更厉害的东西么,平衡二叉树都把我折磨成这样了,更别说这个了。
后来细品了一下,这里明确提到,一个序列能够只能确定唯一的一个CBT。这是什么意思呢,就是说在建立平衡二叉树的时候,需要按照插入序列一个个插入并且调整,这就是为什么平衡二叉树的建立如此的复杂。但是CBT就不一样了,不管插入序列如何,一个序列只能有一个唯一的CBT,这就意味着,可以不用管插入序列如何也不用一个一个插入然后调整,只要根据最终的序列确定一种方法建立CBT即可。
显然我们已知,一个二叉搜索树的中序遍历序列是一个递增序列,那么CBT更是如此。所以当我们拿到一个生成序列的时候将其排好序就形成了一个CBT的中序遍历序列。接下来就是好戏登场了。
中序遍历的过程visit()是将该结点的元素输出形成遍历序列,那么我们已经遍历序列,能否使用逆过程呢,即将visit()改成将遍历序列上对应的值赋值给结点元素。
这样当遍历完成后,一棵原本的空树就变成了一个存储好的树,此时只要将这个数组输出就默认是层序遍历了。
实现
分析见代码备注
完整代码
#include<iostream>
#include<algorithm>
using namespace std;
const int MaxSize = 1001;
//设置全局变量方便递归函数使用
int num; //树元素个数
int i = 0; //遍历序列递归的时候要用
void myInorder(int t[], int a[], int p) { //这里的p是完全二叉树存储的数组中的位置
if (p > num) //超出边界,返回即可
return;
else {
myInorder(t, a, p * 2); //位置为p的结点,p*2就是它左孩子结点的位置
t[p] = a[i++]; //逐个将中序遍历序列赋值给CBT存储数组
myInorder(t, a, p * 2 + 1); //位置为p的结点,p*2+1就是它右孩子结点的位置
return;
}
}
int main() {
int input[MaxSize] = { 0, }; //生成序列,该序列排序好之后就是中序遍历序列
int tree[MaxSize] = { 0, }; //空白的CBT序列
cin >> num;
for (int i = 0; i < num; i++)
cin >> input[i];
sort(input, input + num); //排序完,此时就是中序遍历序列
myInorder(tree, input, 1); //对于一个用数组存储的CBT而言,位置1就是根结点位置
int flag = 0; //输出格式要求
for (int i = 1; i <= num; i++) {
if (flag == 1) {
cout << " ";
}
cout << tree[i];
flag = 1;
}
return 0;
}