#数据结构与算法学习笔记#PTA16:完全二叉搜索树(C/C++)

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];
	}
}

猜你喜欢

转载自blog.csdn.net/qq_20304723/article/details/80238338