二叉树:完全二叉树判断
时间限制: 1s
类别: DS:树->中等
问题描述
目的:使用C++模板设计并逐步完善二叉树的抽象数据类型(ADT)。
内容:(1)请参照链表的ADT模板,设计二叉树并逐步完善的抽象数据类型。(由于该环境目前仅支持单文件的编译,故将所有内容都集中在一个源文件内。在实际的设计中,推荐将抽象类及对应的派生类分别放在单独的头文件中。参考教材、课件,以及网盘中的链表ADT原型文件,自行设计二叉树的ADT。)
注意:二叉树ADT的基本操作的算法设计很多要用到递归的程序设计方法。
(2)基本操作16:在二叉树的二叉链表存储形式建立的基础上,设计并完成判断二叉树是否为完全二叉树的算法。完成后将其加入到二叉树的ADT基本操作集中。
提示:如果一棵二叉树是完全二叉树,那么按照二叉树的性质5可知,按层编号的最后一个结点的编号等于树上的结点总数。因此,可以层次遍历这棵树。在层次遍历时,对树的每一个结点标记一个数值。标记方法如下:根结点为1。对于每个标记值为n的结点,它的两个孩子结点的标号值分别为2n和2n+1。在遍历时,顺便统计树上的结点个数。当结点数等于最后一个结点的编号时,这棵树是完全二叉树,反之为非完全二叉树。与层次遍历(基本操作5)不同的是,在判断完全二叉树时,队列中不仅要保存指向结点的指针,还需要保存结点的编号。为此在二叉树的数据成员里添加了一个结构体类型作为队列中的元素类型。它的定义如下:
struct elem{
BinaryTreeNode<ElemType> *node;
int num;
};
参考函数原型:
template<class ElemType> 判断是否是完全二叉树
bool BinaryTree<ElemType>::isCompleteTree() const;
输入说明
第一行:表示无孩子或指针为空的特殊分隔符
第二行:二叉树的先序序列(结点元素之间以空格分隔)
输出说明
第一行:完全二叉树:true
非完全二叉树:false
#include <iostream>
#include <sstream>
#include <vector>
#include <string>
#include <queue>
using namespace std;
// 二叉树结点的定义
template<class ElemType>
struct BinaryTreeNode {
ElemType data;
BinaryTreeNode<ElemType>* LChild;
BinaryTreeNode<ElemType>* RChild;
BinaryTreeNode(ElemType item = ElemType(), BinaryTreeNode<ElemType>* L = nullptr, BinaryTreeNode<ElemType>* R = nullptr)
: data(item), LChild(L), RChild(R) {}
};
// 定义存储队列元素的结构体
template<class ElemType>
struct QueueElement {
BinaryTreeNode<ElemType>* node;
int num; // 结点编号
QueueElement(BinaryTreeNode<ElemType>* n, int num) : node(n), num(num){}};
// 二叉树类
template<class ElemType>
class BinaryTree {
private:
BinaryTreeNode<ElemType>* root;
// 递归销毁二叉树
void destroy(BinaryTreeNode<ElemType>*& node) {
if (node != nullptr) {
destroy(node->LChild);
destroy(node->RChild);
delete node;
node = nullptr;
}
}
public:
BinaryTree() : root(nullptr) {}
// 析构函数
~BinaryTree() {
destroy(root);
}
// 从先序序列创建二叉树
void createFromPreorder(vector<ElemType> elements, ElemType empty) {
auto it = elements.begin();
root = create(it, elements.end(), empty);
}
// 递归创建二叉树
BinaryTreeNode<ElemType>* create(typename vector<ElemType>::iterator& it, typename vector<ElemType>::iterator end, ElemType empty) {
if (it == end || *it == empty) {
return nullptr;
}
BinaryTreeNode<ElemType>* node = new BinaryTreeNode<ElemType>(*it);
++it;
node->LChild = create(it, end, empty);
++it;
node->RChild = create(it, end, empty);
return node;
}
// 判断二叉树是否为完全二叉树
bool isCompleteTree() const {
if (!root) return true;
queue<QueueElement<ElemType>> q;
int count = 1; // 记录结点个数
q.push(QueueElement<ElemType>(root, 1));
while (!q.empty()) {
QueueElement<ElemType> elem = q.front();
q.pop();
if (elem.node->LChild) {
q.push(QueueElement<ElemType>(elem.node->LChild, 2 * elem.num));
++count;
}
if (elem.node->RChild) {
q.push(QueueElement<ElemType>(elem.node->RChild, 2 * elem.num + 1));
++count;
}
}
// 判断结点个数是否等于最后一个结点的编号
return count == q.back().num;
}
};
int main() {
string nullSymbol;
string preorderInput;
getline(cin, nullSymbol);
getline(cin, preorderInput);
stringstream ss(preorderInput);
string item;
vector<string> elements;
while (ss >> item) {
elements.push_back(item);
}
BinaryTree<string> tree;
tree.createFromPreorder(elements, nullSymbol);
bool isComplete = tree.isCompleteTree();
cout << (isComplete ? "true" : "false") << endl;
return 0;
}