背景说明
以下程序整理于<<Essential C++>>中的以template进行编程的篇章。主要实现了一个基础的二叉查找树。
类的设计
二叉树包含两个类:一个是 BinaryTree
,用于存储一个指针,指向根节点;另一个是 BTnode
,用来存储节点值,以及连接左右两个子节点。节点值的类型即为参数化的部分。其中 BinaryTree
是提供给客户使用的类,包含以下可用操作:插入元素(insert)、移除元素(remove)、查找元素(find)、清除二叉树(clear)、打印二叉树(前序、中序、后序)。
实现
BinaryTree.h
#ifndef BINARYTREE_H_INCLUDED
#define BINARYTREE_H_INCLUDED
#include <iostream>
using uint_t = unsigned int;
// 类模板前置声明
template <class elemType>
class BinaryTree;
template <class valType>
class BTnode;
template <class valType>
class BTnode
{
friend class BinaryTree<valType>;
public:
// 普通构造函数,节点值为val
BTnode(const valType &val);
// 析构函数
~BTnode();
// 插入一个新节点,节点值为val
void insert_value(const valType &val);
// 移除一个节点,节点值为val,父节点为prev
void remove_value(const valType &val, BTnode * &prev);
// 查找一个结点,节点值为val
bool find_value(const valType &val) const;
// 前序打印:节点本身-左子节点-右子节点
void preorder(BTnode *pt, std::ostream &os) const;
// 中序打印:左子节点-节点本身-右子节点
void inorder(BTnode *pt, std::ostream &os) const;
// 后序打印:左子节点-右子节点-节点本身
void postorder(BTnode *pt, std::ostream &os) const;
// 获取节点值
const valType& value() const { return _val; }
// 获取节点值出现次数
uint_t occurs() const { return _cnt; }
// 遍历subtree节点下的左子树,将leaf接为最下层的叶子节点
static void lchild_leaf(BTnode *leaf, BTnode *subtree);
private:
// 拷贝构造函数
BTnode(const BTnode &rhs);
// 赋值运算符重载函数
BTnode& operator=(const BTnode &rhs);
// 打印节点值
void display_val(BTnode *pt, std::ostream &os) const;
private:
// 节点值
valType _val;
// 节点值出现次数
uint_t _cnt;
// 指向左子节点
BTnode *_lchild;
// 指向右子节点
BTnode *_rchild;
};
template <typename valType>
inline
BTnode<valType>::
BTnode(const valType& val)
: _val(val), _cnt(1), _lchild(nullptr), _rchild(nullptr)
{
*(BinaryTree<valType>::getOutStream()) << "调用普通构造函数BTnode<valType>::BTnode(const valType& val)" << std::endl;
}
template <typename valType>
inline
BTnode<valType>::
BTnode(const BTnode &rhs)
: _val(rhs._val), _cnt(1), _lchild(nullptr), _rchild(nullptr)
{
*(BinaryTree<valType>::getOutStream()) << "调用拷贝构造函数BTnode<valType>::BTnode(const BTnode &rhs)" << std::endl;
}
template <typename valType>
inline BTnode<valType>&
BTnode<valType>::
operator=(const BTnode &rhs)
{
_val = rhs._val;
_cnt = 1;
_lchild = nullptr;
_rchild = nullptr;
*(BinaryTree<valType>::getOutStream()) << "调用赋值运算符重载函数BTnode<valType>::BTnode(const BTnode &rhs)" << std::endl;
}
template <typename valType>
inline
BTnode<valType>::
~BTnode()
{
*(BinaryTree<valType>::getOutStream()) << "调用析构函数BTnode<valType>::~BTnode()" << std::endl;
}
template <typename valType>
void
BTnode<valType>::
insert_value(const valType &val)
{
if (val == _val)
{
++_cnt;
return;
}
else if (val < _val)
{
if (_lchild)
_lchild->insert_value(val);
else
_lchild = new BTnode(val);
}
else
{
if (_rchild)
_rchild->insert_value(val);
else
_rchild = new BTnode(val);
}
}
template <typename valType>
void
BTnode<valType>::
lchild_leaf(BTnode *leaf, BTnode *subtree)
{
while (subtree->_lchild)
subtree = subtree->_lchild;
subtree->_lchild = leaf;
}
template <typename valType>
void
BTnode<valType>::
remove_value(const valType &val, BTnode * &prev)
{
// 算法:
// 以删除节点的右子节点取代删除节点本身
// 若无右子节点,就以左子节点取代删除节点本身
// 搬移左子节点,使其成为右子节点的左子树的叶节点
if (val == _val)
{
if (_rchild)
{
prev = _rchild;
if (_lchild)
{
if (prev->_lchild)
BTnode<valType>::lchild_leaf(_lchild, prev->_lchild);
else
prev->_lchild = _lchild;
}
}
else
{
prev = _lchild;
}
delete this;
}
else if (val < _val)
{
if (_lchild)
_lchild->remove_value(val, _lchild);
}
else
{
if (_rchild)
_rchild->remove_value(val, _rchild);
}
}
template <typename valType>
bool
BTnode<valType>::
find_value(const valType &val) const
{
if (val == _val)
{
return true;
}
else if (val < _val)
{
if (_lchild)
return _lchild->find_value(val);
else
return false;
}
else
{
if (_rchild)
return _rchild->find_value(val);
else
return false;
}
}
template <typename valType>
void
BTnode<valType>::
preorder(BTnode *pt, std::ostream &os) const
{
if (pt)
{
// 节点本身-左子节点-右子节点
display_val(pt, os);
if (pt->_lchild)
preorder(pt->_lchild, os);
if (pt->_rchild)
preorder(pt->_rchild, os);
}
}
template <typename valType>
void
BTnode<valType>::
inorder(BTnode *pt, std::ostream &os) const
{
if (pt)
{
// 左子节点-节点本身-右子节点
if (pt->_lchild)
inorder(pt->_lchild, os);
display_val(pt, os);
if (pt->_rchild)
inorder(pt->_rchild, os);
}
}
template <typename valType>
void
BTnode<valType>::
postorder(BTnode *pt, std::ostream &os) const
{
if (pt)
{
// 左子节点-右子节点-节点本身
if (pt->_lchild)
postorder(pt->_lchild, os);
if (pt->_rchild)
postorder(pt->_rchild, os);
display_val(pt, os);
}
}
template <typename valType>
void
BTnode<valType>::
display_val(BTnode *pt, std::ostream &os) const
{
if (pt)
{
os << pt->_val;
if (pt->_cnt > 1)
os << "(" << pt->_cnt << ") ";
else
os << ' ';
}
}
template <class elemType>
class BinaryTree
{
public:
// 默认构造函数
BinaryTree();
// 拷贝构造函数
BinaryTree(const BinaryTree &rhs);
// 赋值运算符重载函数
BinaryTree& operator=(const BinaryTree &rhs);
// 析构函数
~BinaryTree();
// 插入新节点,节点值为elem
void insert(const elemType& elem);
// 移除节点,节点值为elem
void remove(const elemType &elem);
// 查找节点是否在二叉树,节点值为val
bool find(const elemType &val) const;
// 二叉树是否为空
bool empty() { return (nullptr == _root); }
// 清除整个二叉树
void clear() { clear(_root); _root = nullptr; }
// 前序打印:节点本身-左子节点-右子节点
void preorder(std::ostream &os = *_current_os) const { _root->preorder(_root, os); os << std::endl; }
// 中序打印:左子节点-节点本身-右子节点
void inorder(std::ostream &os = *_current_os) const { _root->inorder(_root, os); os << std::endl; }
// 后序打印:左子节点-右子节点-节点本身
void postorder(std::ostream &os = *_current_os) const { _root->postorder(_root, os); os << std::endl; }
// 获取当前输出流
static std::ostream* getOutStream() { return _current_os; }
// 设置当前输出流
static void setOutStream(std::ostream *os) { if (os) _current_os = os; }
private:
// 将src指向的子树复制到tar指向的子树
void copy(BTnode<elemType> *&tar, const BTnode<elemType> *src);
// 清除二叉树
void clear(BTnode<elemType> *pt);
// 移除根节点
void remove_root();
private:
// 指向二叉树根节点
BTnode<elemType> *_root;
// 指向输出流
static std::ostream *_current_os;
};
template <typename elemType>
inline
BinaryTree<elemType>::
BinaryTree()
: _root(nullptr)
{
*_current_os << "调用默认构造函数BinaryTree<elemType>::BinaryTree()" << std::endl;
}
template <typename elemType>
inline
BinaryTree<elemType>::
BinaryTree(const BinaryTree &rhs)
{
copy(_root, rhs._root);
*_current_os << "调用拷贝构造函数BinaryTree<elemType>::BinaryTree(const BinaryTree &rhs)" << std::endl;
}
template <typename elemType>
inline BinaryTree<elemType>&
BinaryTree<elemType>::
operator=(const BinaryTree &rhs)
{
if (this != &rhs)
{
clear();
copy(_root, rhs._root);
}
*_current_os << "调用赋值运算符重载函数BinaryTree<elemType>::operator=(const BinaryTree &rhs)" << std::endl;
return *this;
}
template <typename elemType>
inline BinaryTree<elemType>::
~BinaryTree()
{
clear();
*_current_os << "调用析构函数BinaryTree<elemType>::~BinaryTree()" << std::endl;
}
template <typename elemType>
void
BinaryTree<elemType>::
insert(const elemType &elem)
{
if (_root)
_root->insert_value(elem);
else
_root = new BTnode<elemType>(elem);
}
template <typename elemType>
void
BinaryTree<elemType>::
remove(const elemType &elem)
{
if (_root)
{
if (elem == _root->_val)
remove_root();
else
_root->remove_value(elem, _root);
}
}
template <typename elemType>
bool
BinaryTree<elemType>::
find(const elemType &elem) const
{
if (_root)
{
return _root->find_value(elem);
}
else
{
return false;
}
}
template <typename elemType>
void
BinaryTree<elemType>::
remove_root()
{
// 算法:
// 以删除节点的右子节点取代删除节点本身
// 若无右子节点,就以左子节点取代删除节点本身
// 搬移左子节点,使其成为右子节点的左子树的叶节点
if (_root)
{
BTnode<elemType> * const oldroot = _root;
if (oldroot->_rchild)
{
_root = oldroot->_rchild;
BTnode<elemType> *oldlc = oldroot->_lchild;
BTnode<elemType> *newlc = _root->_lchild;
if (oldlc)
{
if (newlc)
BTnode<elemType>::lchild_leaf(oldlc, newlc);
else
_root->_lchild = oldlc;
}
}
else
{
_root = oldroot->_lchild;
}
delete oldroot;
}
}
template <typename elemType>
void
BinaryTree<elemType>::
clear(BTnode<elemType> *pt)
{
if (pt)
{
clear(pt->_lchild);
clear(pt->_rchild);
delete pt;
}
}
template <typename elemType>
void
BinaryTree<elemType>::
copy(BTnode<elemType> *&tar, const BTnode<elemType> *src)
{
if (src)
{
tar = new BTnode<elemType>(src->val);
if (src->_lchild)
copy(tar->_lchild, src->_lchild);
if (src->_rchild)
copy(tar->_rchild, src->_rchild);
}
}
#endif // BINARYTREE_H_INCLUDED
main.cpp
#include "BinaryTree.h"
#include <string>
#include <fstream>
template<typename elemType>
std::ostream *BinaryTree<elemType>::_current_os = &std::cout;
const std::string log_file = "logfile.txt";
int main()
{
std::ofstream log(log_file);
if (!log)
{
std::cerr << "错误:无法打开文件[" << log_file << "]" << std::endl;
return -1;
}
else
{
BinaryTree<std::string>::setOutStream(&log);
}
BinaryTree<std::string> bt;
if (bt.empty())
{
log << "二叉树为空" << std::endl;
}
else
{
log << "二叉树不为空" << std::endl;
log << "前序: ";
bt.preorder(log);
log << "中序: ";
bt.inorder(log);
log << "后序: ";
bt.postorder(log);
}
bt.insert("Piglet");
bt.insert("Eeyore");
bt.insert("Roo");
bt.insert("Tigger");
bt.insert("Chris");
bt.insert("Chris");
bt.insert("Chris");
bt.insert("Pooh");
bt.insert("Kanga");
log << "前序: ";
bt.preorder(log);
log << "中序: ";
bt.inorder(log);
log << "后序: ";
bt.postorder(log);
bt.remove("Piglet");
log << "前序: ";
bt.preorder(log);
log << "中序: ";
bt.inorder(log);
log << "后序: ";
bt.postorder(log);
bt.remove("Roo");
log << "前序: ";
bt.preorder(log);
log << "中序: ";
bt.inorder(log);
log << "后序: ";
bt.postorder(log);
if (bt.find("Kanga"))
{
log << "存在Kanga" << std::endl;
}
else
{
log << "不存在Kanga" << std::endl;
}
if (bt.find("hsy"))
{
log << "存在hsy" << std::endl;
}
else
{
log << "不存在hsy" << std::endl;
}
bt.clear();
if (bt.empty())
{
log << "二叉树为空" << std::endl;
}
else
{
log << "二叉树不为空" << std::endl;
bt.preorder(log);
bt.inorder(log);
bt.postorder(log);
}
return 0;
}
运行结果如下
调用默认构造函数BinaryTree<elemType>::BinaryTree()
二叉树为空
调用普通构造函数BTnode<valType>::BTnode(const valType& val)
调用普通构造函数BTnode<valType>::BTnode(const valType& val)
调用普通构造函数BTnode<valType>::BTnode(const valType& val)
调用普通构造函数BTnode<valType>::BTnode(const valType& val)
调用普通构造函数BTnode<valType>::BTnode(const valType& val)
调用普通构造函数BTnode<valType>::BTnode(const valType& val)
调用普通构造函数BTnode<valType>::BTnode(const valType& val)
前序: Piglet Eeyore Chris(3) Kanga Roo Pooh Tigger
中序: Chris(3) Eeyore Kanga Piglet Pooh Roo Tigger
后序: Chris(3) Kanga Eeyore Pooh Tigger Roo Piglet
调用析构函数BTnode<valType>::~BTnode()
前序: Roo Pooh Eeyore Chris(3) Kanga Tigger
中序: Chris(3) Eeyore Kanga Pooh Roo Tigger
后序: Chris(3) Kanga Eeyore Pooh Tigger Roo
调用析构函数BTnode<valType>::~BTnode()
前序: Tigger Pooh Eeyore Chris(3) Kanga
中序: Chris(3) Eeyore Kanga Pooh Tigger
后序: Chris(3) Kanga Eeyore Pooh Tigger
存在Kanga
不存在hsy
调用析构函数BTnode<valType>::~BTnode()
调用析构函数BTnode<valType>::~BTnode()
调用析构函数BTnode<valType>::~BTnode()
调用析构函数BTnode<valType>::~BTnode()
调用析构函数BTnode<valType>::~BTnode()
二叉树为空
调用析构函数BinaryTree<elemType>::~BinaryTree()
评论 (0)