2018.5.8
题目的意思很简单,给定一个任意的输入序列,把这个序列建成一棵完全二叉搜索树(既是一棵完全二叉树,又是一棵二叉搜索树),并且层次遍历打印出来。但是实现起来却并不那么轻松,完全二叉树一般用数组存储比较方便,而二叉搜索树用链表存储比较方便。
之前我们在《#数据结构与算法学习笔记#PTA10:层次遍历叶节点(JAVA)》中写到了如何利用队列将链表存储的二叉树进行层次遍历。因此最一开始,笔者就先用链表试着实现了一下,发现做一棵二叉搜索树简单,每个结点插入的时候按照大小比较的规则插入就好,但是要想将一棵二叉搜索树转变成一棵完全二叉树,转换方式极其繁琐,基本上每个结点插入都要将整棵树的结构重构。因此,放弃用链表存储,转而改用数组存储。
对于某一指定序列来说,无论先后顺序如何,其建成的完全二叉搜索树肯定都是一模一样的。如果能提前发现这点,就更应该直接用数组进行存储了(并且更方便进行层次遍历打印)。基本思想是,先将输入序列从小到大进行排——再计算该树左子树的结点数(给出该树总结点数total,必能算出左子树的结点数和其根节点所在位置,计算方法如注释)——最后依次在数组中层序装入个根节点值——递归装入每一个左右子树根节点。基本思想同《#数据结构与算法学习笔记#PTA11:先序遍历+中序遍历转后序遍历/二叉树非递归遍历/二叉树栈遍历(JAVA)》中的递归思想。
题目要求:
A Binary Search Tree (BST) is recursively defined as a binary tree which has the following properties:
1.The left subtree of a node contains only nodes with keys less than the node's key.
2.The right subtree of a node contains only nodes with keys greater than or equal to the node's key.
3.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.
实现代码:
// CompleteBinarySearchTree.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#include <iostream>
#include <vector>
#include <algorithm>
#include <cmath>
using namespace std;
//用于sort递增排序的比较函数
bool Compare(const int &a, const int &b);
//根据顺序序列创建完全二叉搜索树
void Create(vector<int>& input, vector<int>& tree, int left, int right, int root);
//获取该结点左子树结点数
int GetLeftNum(int total);
void Print(vector<int>& tree);
int main()
{
vector<int> input;
int num;
cin >> num;
int element;
for (int i = 0; i < num; i++) {
cin >> element;
input.push_back(element);
}
//从小到大排序
sort(input.begin(), input.end(), Compare);
//Print(input);
vector<int> tree(num);
Create(input, tree, 0, num - 1, 0);
Print(tree);
system("pause");
return 0;
}
bool Compare(const int &a, const int &b)
{
return a < b;
}
void Create(vector<int>& input, vector<int>& tree, int left, int right, int root) {
//该树总结点数
int total = right - left + 1;
if (total == 0)return;
//该树左子树的结点数
int leftnum = GetLeftNum(total);
tree[root] = input[left + leftnum];
//左子树根节点在tree序列的下标
int leftroot = root * 2 + 1;
//右子树根节点在tree序列的下标
int rightroot = leftroot + 1;
//递归创建其左右子树
Create(input, tree, left, left + leftnum - 1, leftroot);
Create(input, tree, left + leftnum + 1, right, rightroot);
}
int GetLeftNum(int total) {
int n = log(total) / log(2); //完美二叉树层数(除最底层)
int leftnum = total - (pow(2, n) - 1); //所有最底层叶子结点
int leftmax = pow(2, n - 1); //左子树最底层最大结点
int other = pow(2, n - 1) - 1; //左子树枝干分支结点
//若最底层叶子结点全在左子树,则返回最底层叶子结点+其枝干分支节点
if (leftnum < leftmax) {
return leftnum + other;
}
//若最底层叶子结点存在于左右子树,则返回左子树最底层最大结点+其枝干分支结点
else if(leftnum >= leftmax){
return leftmax + other;
}
}
void Print(vector<int>& tree) {
cout << tree[0];
for (int i = 1; i < tree.size(); i++) {
cout << " " << tree[i];
}
}
#Coding一小时,Copying一秒钟。留个言点个赞呗,谢谢你#