使用C++编写一个类模板,实现二叉树的创建(通过前序序列和中序序列非递归地创建)、遍历(前序、中序、后序、层次遍历)、查找(根据值查找,二叉树中的值唯一)、删除、打印功能。
根据前序序列和中序序列非递归地创建二叉树
众所周知,若已知一个中序序列和其他三种遍历序列中的任意一个,就可以唯一确定一棵二叉树。已知一棵二叉树的前序序列和中序序列,如何非递归地创建二叉树呢?
假设有如下二叉树:
其前序序列为:1,2,4,5,3,6,7,8
其中序序列为: 4,2,5,1,3,7,6,8
可以看到,每个结点的左右子树在序列中都是连续的,比如根结点1的左子树在前序序列中是连续的2、4、5,在中序序列中是连续的4、2、5。并且前序序列中每一段的第一个即是子树根结点的值,所以可以用两个数组来表示这两个序列,通过根结点在中序数组中的下标确定左右子树的下标范围进而得知左右子树的长度,因为左右子树在前序数组中的表示是连续的(左子树后紧跟着右子树),所以左子树最后一个结点的下一个结点就是右子树的根结点。
设计如下结构体用于保存必要的信息(前序数组中的根结点下标、中序数组中的左右子树范围下标、指向当前结点的父结点的指针、表示当前结点是否为左孩子的布尔值):typedef struct data { size_t start{};//前序序列中的下一个子树根结点位置 size_t start_in{};//中序序列中左右子树起始位置 size_t end_in{};//中序序列中左右子树结束位置 NODE* parent{}; bool isLeft{ true }; } DATA;
使用一个队列保存每个结点对应的结构体DATA,当要创建一个结点时,读取队列头的结构体,从结构体中获取该结点的父结点,并将本结点设为父结点的左孩子或者右孩子,父结点总是先于子结点被创建。需要注意的是,根结点没有父结点,为了简化代码,可以为根结点创建一个临时的父结点,根结点作为其左孩子。过程如下:
代码实现如下://根据前序序列和中序序列创建二叉树 template<typename T> inline typename BinaryTree<T>::NODE* BinaryTree<T>::create(const vector<T>& prev, const vector<T>& in){ if (m_num != 0) { throw std::exception("二叉树已经创建"); } if (prev.empty() || in.empty()) { throw std::exception("空的数组"); } if (prev.size() != in.size()) { throw std::exception("两个序列长度不一致"); } typedef struct data { size_t start{};//前序序列中的下一个子树根结点位置 size_t start_in{};//中序序列中左右子树起始位置 size_t end_in{};//中序序列中左右子树结束位置 NODE* parent{}; bool isLeft{ true }; } DATA; auto length{ prev.size() }; deque<DATA> d{};//队列 NODE* proot = new NODE(); proot->leftChild = nullptr; d.push_back({ 0,0,length - 1,proot,true });//队列中第一个元素用于开始循环,是一个以根结点为左孩子的结点 size_t start{};//前序序列左右子树起始位置 size_t end{ length - 1 };//前序序列左右子树结束位置 size_t index{};//中序序列索引 while (!d.empty()) { auto start = d.front().start; auto start_in = d.front().start_in; auto end_in = d.front().end_in; auto parent = d.front().parent; auto isLeft = d.front().isLeft; d.pop_front(); index = start_in; while ((prev[start] != in[index]) && (index <= end_in)) { index++; } if (index > end_in) { throw std::exception("错误的序列"); } auto rootValue{ in[index] };//子树根结点值 auto curNode = new NODE(); curNode->value = rootValue; if (isLeft) { parent->leftChild = curNode; m_num++; } else { parent->rightChild = curNode; m_num++; } if (start_in == end_in) { continue; } if (index > start_in && index < end_in) {//既有左子树又有右子树 d.push_back({ start + 1,start_in,index - 1,curNode,true }); d.push_back({ start + 1 + (index - 1 - start_in + 1),index + 1,end_in,curNode,false }); } if (index == start_in) {//只有右子树 d.push_back({ start + 1,index + 1,end_in,curNode,false }); } if (index == end_in) {//只有左子树 d.push_back({ start + 1,start_in,index - 1,curNode,true }); } //如果start_in等于end_in,则该位置的结点为叶结点 } m_root = proot->leftChild;//获取根结点 return m_root; }
BinaryTree.hpp
#pragma once
#include <memory>
#include <vector>
#include <deque>
#include <iostream>
using std::cout;
using std::endl;
using std::deque;
using std::vector;
template<typename T>
class BinaryTree {
public:
BinaryTree();
BinaryTree(const BinaryTree& src);
BinaryTree(BinaryTree&& src)noexcept;
BinaryTree& operator=(const BinaryTree& rhs);
BinaryTree& operator=(BinaryTree&& rhs)noexcept;
~BinaryTree();
public:
using NODE = struct binaryTreeNode {
struct binaryTreeNode* leftChild{};//左孩子
struct binaryTreeNode* rightChild{};//右孩子
T value{};//结点值
};
NODE* m_root{};//根结点
size_t m_num{};//结点个数
public:
std::unique_ptr<T[]> preOrder();//前序遍历
std::unique_ptr<T[]> inOrder();//中序遍历
std::unique_ptr<T[]> postOrder();//后序遍历
std::unique_ptr<T[]> levelOrder();//层次遍历
void print();//打印二叉树
NODE* create(const vector<T>& prev, const vector<T>& in);//通过前序序列和中序序列创建二叉树
NODE* find(const T& value);
void erase(NODE* node);
};
//默认构造函数
template<typename T>
BinaryTree<T>::BinaryTree() {
}
//拷贝构造函数
template<typename T>
BinaryTree<T>::BinaryTree(const BinaryTree& src) :BinaryTree{} {
m_num = src.m_num;
deque<NODE*> d_src{};
NODE** d{ new NODE * [m_num] };
size_t head{};
size_t rear{};
d_src.push_back(src.m_root);
d[0] = new NODE;
d[0]->value = src.m_root->value;//复制根结点
m_root = d[0];
NODE* front{};
while (!d_src.empty()) {
front = d_src.front();
d_src.pop_front();
auto* left = front->leftChild;
auto* right = front->rightChild;
if (left) {
d_src.push_back(left);
NODE* node = new NODE;
node->value = front->leftChild->value;//复制左子结点值
d[head]->leftChild = node;
d[++rear] = node;
}
if (right) {
d_src.push_back(right);
NODE* node = new NODE;
node->value = front->rightChild->value;//复制右子结点值
d[head]->rightChild = node;
d[++rear] = node;
}
head++;
}
delete[] d;//释放指针数组
}
//移动构造函数
template<typename T>
BinaryTree<T>::BinaryTree(BinaryTree&& src)noexcept {
m_root = src.m_root;
m_num = src.m_num;
src.m_root = nullptr;
src.m_num = 0;
}
//拷贝赋值运算符
template<typename T>
BinaryTree<T>& BinaryTree<T>::operator=(const BinaryTree& rhs) {
if (this == &rhs)return *this;//检查自我赋值
if (m_num != 0) {
deque<NODE*> d1{};
d1.push_back(m_root);
while (!d1.empty()) {
if (d1.front()->leftChild) {
d1.push_back(d1.front()->leftChild);
}
if (d1.front()->rightChild) {
d1.push_back(d1.front()->rightChild);
}
delete d1.front();
d1.pop_front();
}//删除原来的结点
}
m_num = rhs.m_num;
deque<NODE*> d_rhs{};
NODE** d2{ new NODE * [m_num] };
size_t head{};
size_t rear{};
d_rhs.push_back(rhs.m_root);
d2[0] = new NODE;
d2[0]->value = rhs.m_root->value;//复制根结点
m_root = d2[0];
NODE* front{};
while (!d_rhs.empty()) {
front = d_rhs.front();
d_rhs.pop_front();
auto* left = front->leftChild;
auto* right = front->rightChild;
if (left) {
d_rhs.push_back(left);
NODE* node = new NODE;
node->value = front->leftChild->value;//复制左子结点值
d2[head]->leftChild = node;
d2[++rear] = node;
}
if (right) {
d_rhs.push_back(right);
NODE* node = new NODE;
node->value = front->rightChild->value;//复制右子结点值
d2[head]->rightChild = node;
d2[++rear] = node;
}
head++;
}
delete[] d2;//释放指针数组
return *this;
}
//移动赋值运算符
template<typename T>
BinaryTree<T>& BinaryTree<T>::operator=(BinaryTree&& rhs)noexcept {
if (this == &rhs)return *this;
if (m_num != 0) {
deque<NODE*> d{};
d.push_back(m_root);
while (!d.empty()) {
if (d.front()->leftChild) {
d.push_back(d.front()->leftChild);
}
if (d.front()->rightChild) {
d.push_back(d.front()->rightChild);
}
delete d.front();
d.pop_front();
}//删除原来的结点
}
m_num = rhs.m_num;
m_root = rhs.m_root;
rhs.m_num = 0;
rhs.m_root = nullptr;
return *this;
}
//析构函数
template<typename T>
inline BinaryTree<T>::~BinaryTree()
{
if (m_num != 0) {
deque<NODE*> d{};
d.push_back(m_root);
while (!d.empty()) {
if (d.front()->leftChild) {
d.push_back(d.front()->leftChild);
}
if (d.front()->rightChild) {
d.push_back(d.front()->rightChild);
}
delete d.front();
d.pop_front();
}
m_root = nullptr;
}
}
//前序遍历
template<typename T>
inline std::unique_ptr<T[]> BinaryTree<T>::preOrder()
{
std::unique_ptr<T[]> res{ new T[m_num] };
vector<NODE*> v{};
size_t count{};
NODE* got{};
auto p{ m_root };
while (p || !v.empty()) {
if (p) {
res[count++] = p->value;
v.push_back(p);
p = p->leftChild;
}
else {
p = v.back()->rightChild;
v.pop_back();
}
}
return res;
}
//中序遍历
template<typename T>
inline std::unique_ptr<T[]> BinaryTree<T>::inOrder()
{
std::unique_ptr<T[]> res{ new T[m_num] };
vector<NODE*> v{};
size_t count{};
NODE* got{};
auto p{ m_root };
while (p || !v.empty()) {
if (p) {
v.push_back(p);
p = p->leftChild;
}
else {
res[count++] = v.back()->value;
p = v.back()->rightChild;
v.pop_back();
}
}
return res;
}
//后序遍历
template<typename T>
inline std::unique_ptr<T[]> BinaryTree<T>::postOrder()
{
auto res{ std::make_unique<T[]>(m_num) };
size_t count{};
vector<NODE*> v{};
NODE* got{};
NODE* p{ m_root };
while (!v.empty() || p) {
if (p) {
v.push_back(p);
p = p->leftChild;
}
else {
p = v.back();
if (p->rightChild && p->rightChild != got) {
p = p->rightChild;
}
else {
res[count++] = v.back()->value;
got = v.back();
p = nullptr;
v.pop_back();
}
}
}
return res;
}
//层次遍历
template<typename T>
inline std::unique_ptr<T[]> BinaryTree<T>::levelOrder()
{
std::unique_ptr<T[]> res{ new T[m_num] };
deque<NODE*> d{};
d.push_back(m_root);
size_t count{};
NODE* front{};
while (!d.empty()) {
front = d.front();
res[count++] = front->value;
if (front->leftChild) {
d.push_back(front->leftChild);
}
if (front->rightChild) {
d.push_back(front->rightChild);
}
d.pop_front();
}
return res;
}
template<typename T>
inline void BinaryTree<T>::print()
{
if (m_num == 0) {
cout << "二叉树为空" << endl;
return;
}
deque<NODE*> d{};
d.push_back(m_root);
auto* front = d.front();
cout << "二叉树共有" << m_num << "个结点" << endl;
while (!d.empty()) {
front = d.front();
if (front->leftChild && front->rightChild) {
cout << front->value << " L: " << front->leftChild->value << " R: " << front->rightChild->value << "\n";
d.push_back(front->leftChild);
d.push_back(front->rightChild);
}
else if (front->leftChild) {
cout << front->value << " L: " << front->leftChild->value << "\n";
d.push_back(front->leftChild);
}
else if (front->rightChild) {
cout << front->value << " R: " << front->rightChild->value << "\n";
d.push_back(front->rightChild);
}
else {
cout << front->value << " 是叶结点\n";
}
d.pop_front();
}
return;
}
//根据前序序列和中序序列创建二叉树
template<typename T>
inline typename BinaryTree<T>::NODE* BinaryTree<T>::create(const vector<T>& prev, const vector<T>& in){
if (m_num != 0) {
throw std::exception("二叉树已经创建");
}
if (prev.empty() || in.empty()) {
throw std::exception("空的数组");
}
if (prev.size() != in.size()) {
throw std::exception("两个序列长度不一致");
}
typedef struct data {
size_t start{};//前序序列中的下一个子树根结点位置
size_t start_in{};//中序序列中左右子树起始位置
size_t end_in{};//中序序列中左右子树结束位置
NODE* parent{};
bool isLeft{ true };
} DATA;
auto length{ prev.size() };
deque<DATA> d{};//队列
NODE* proot = new NODE();
proot->leftChild = nullptr;
d.push_back({ 0,0,length - 1,proot,true });//队列中第一个元素用于开始循环,是一个以根结点为左孩子的结点
size_t start{};//前序序列左右子树起始位置
size_t end{ length - 1 };//前序序列左右子树结束位置
size_t index{};//中序序列索引
while (!d.empty()) {
auto start = d.front().start;
auto start_in = d.front().start_in;
auto end_in = d.front().end_in;
auto parent = d.front().parent;
auto isLeft = d.front().isLeft;
d.pop_front();
index = start_in;
while ((prev[start] != in[index]) && (index <= end_in)) {
index++;
}
if (index > end_in) {
throw std::exception("错误的序列");
}
auto rootValue{ in[index] };//子树根结点值
auto curNode = new NODE();
curNode->value = rootValue;
if (isLeft) {
parent->leftChild = curNode;
m_num++;
}
else {
parent->rightChild = curNode;
m_num++;
}
if (start_in == end_in) {
continue;
}
if (index > start_in && index < end_in) {//既有左子树又有右子树
d.push_back({ start + 1,start_in,index - 1,curNode,true });
d.push_back({ start + 1 + (index - 1 - start_in + 1),index + 1,end_in,curNode,false });
}
if (index == start_in) {//只有右子树
d.push_back({ start + 1,index + 1,end_in,curNode,false });
}
if (index == end_in) {//只有左子树
d.push_back({ start + 1,start_in,index - 1,curNode,true });
}
//如果start_in等于end_in,则该位置的结点为叶结点
}
m_root = proot->leftChild;//获取根结点
return m_root;
}
template<typename T>
inline typename BinaryTree<T>::NODE* BinaryTree<T>::find(const T& value)
{
deque<NODE*> d{ m_root };
while (d.front()) {
if (d.front()->value == value) {
return d.front();
}
else {
if (d.front()->leftChild) {
d.push_back(d.front()->leftChild);
}
if (d.front()->rightChild) {
d.push_back(d.front()->rightChild);
}
}
d.pop_front();
}
return nullptr;
}
template<typename T>
inline void BinaryTree<T>::erase(NODE* node)
{
deque<NODE*> D{};
D.push_back(m_root);
NODE* front_D{};
NODE* front_d{};
while (!D.empty()) {
front_D = D.front();
if ((front_D->leftChild == node) || (front_D->rightChild == node) || (front_D == node)){
deque<NODE*> d{};
d.push_back(node);
while (!d.empty()) {
front_d = d.front();
if (front_d->leftChild) {
d.push_back(front_d->leftChild);
}
if (front_d->rightChild) {
d.push_back(front_d->rightChild);
}
delete front_d;
m_num--;
d.pop_front();
}
if (front_D->leftChild == node) {
front_D->leftChild = nullptr;
}
if (front_D->rightChild == node) {
front_D->rightChild = nullptr;
}
break;
}
if (front_D->leftChild) {
D.push_back(front_D->leftChild);
}
if (front_D->rightChild) {
D.push_back(front_D->rightChild);
}
D.pop_front();
}
return;
}
main.cpp
#include "BinaryTree.hpp"
#include <memory>
#include <iostream>
using std::cout;
using std::cin;
using std::endl;
using std::move;
using std::string;
int main()
{
_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);
vector<int> vprev1{ 1,2,4,6,11,5,8,9,3,7,10 };
vector<int> vin1{ 6,11,4,2,8,5,9,1,3,7,10 };
BinaryTree<int> bt{};
try {
bt.create(vprev1, vin1);
auto bt1{ bt };
bt1 = move(bt);
cout << "后序遍历\n";
auto res = bt1.postOrder();
for (int i{}; i < 11; ++i) {
cout << res[i] << " ";
}
cout << endl;
bt1.print();
auto p{ bt1.find(5) };
bt1.erase(p);
bt1.print();
}
catch (const std::exception& e) {
cout << e.what() << endl;
}
return 0;
}