本文使用C++实现二叉树数据结构,与之前实现的向量、列表、栈和队列不同,树是一种分层结构,虽然树是分层结构,但若附加某种约束,如遍历次序,则树结构也可以转变成线性次序,因此树属于半线性结构。树结构具有非常多的变种,在算法理论和实际应用中,各种树结构扮演着最为关键的角色。
另外,任何有根有序的多叉树,都能转变成二叉树,因此二叉树数据结构具有非常重要的地位。
两种特殊的二叉树:完全二叉树、满二叉树
完全二叉树: 叶子结点只能出现在最底部的两层,且最底层叶节点均处于次底层叶节点的左侧。
满二叉树: 所有叶节点同处于最底层(非底层节点均为内部结点)。
二叉树的实现和列表数据结构有很大的相似性,都需要为相互临近的节点之间维护正确的指针指向。这里二叉树数据结构的实现包括binNode类和binTree类,前者主要描述单个二叉树的结构和对其的操作,而binTree类主要描述整个二叉树的结构和对其进行的操作。
操作 | 功能 | 对象 |
binNode() | 默认构造函数 | |
binNode(T e, binNode* p, binNode *lc, binNode *rc, int h) | 构造函数,设置节点数据,父节点,孩子节点,高度 | |
~binNode() | 析构函数 | |
insertAsLC(const T& e) | 作为本节点的左孩子插入 | 二叉树节点 |
insertAsRC(const T& e) | 作为本节点的右孩子插入 | 二叉树节点 |
succ() | 定位在中序遍历中节点v的直接后续 | 二叉树节点 |
重载运算符== | 相等判断运算符 | 二叉树节点 |
重载运算符< | 小于运算符 | 二叉树节点 |
操作 | 功能 | 对象 |
binTree() | 默认构造函数 | |
~binTree() | 析构函数 | |
size() | 返回二叉树的规模 | 二叉树 |
empty() | 判断二叉树是否为空 | 二叉树 |
root() | 返回根节点的指针 | 二叉树 |
insertAsRoot(const T& e) | 将指定元素作为根节点插入 | 二叉树 |
insertAsLC(binNode<T>* bn, const T& e) | 将指定元素插入作为指定节点的左孩子 | 二叉树 |
insertAsRC(binNode<T>* bn, const T& e) | 将指定元素插入作为指定节点的右孩子 | 二叉树 |
attachAsLC(binNode<T>* bn, binTree<T>* &bt) | 将指定子树插入作为指定节点的左孩子 | 二叉树 |
attachAsRC(binNode<T>* bn, binTree<T>* &bt) | 将指定子树插入作为指定节点的右孩子 | 二叉树 |
updateHeight(binNode<T>* bn) | 更新节点的高度 | 二叉树 |
updateHeightAbove(binNode<T>* bn) | 更新此节点祖先节点的高度(插入或删除节点要执行更新) | 二叉树 |
removeAt(binNode<T>* bn) | 删除节点bn及其后代,并返回删掉的二叉树节点的总数 | 二叉树 |
remove(binNode<T>* bn) | 删除以bn为根节点的子树 | 二叉树 |
secede(binNode<T>* bn) | 子树分离,将节点bn及其后代从二叉树中分离出来,然后形成一个独立的二叉树 | 二叉树 |
travPre_R(binNode<T>* bn_r, void(*func)(T& bn)) | 先序遍历(递归版本:简洁易懂) | 二叉树 |
travIn_R(binNode<T>* bn_r, void(*func)(T& bn)) | 中序遍历(递归版本:简洁易懂) | 二叉树 |
travPost_R(binNode<T>* bn_r, void(*func)(T& bn)) | 后序遍历(递归版本:简洁易懂) | 二叉树 |
visitAlongLeftBranch(binNode<T>* bn, void(*func)(T& bn), stack<binNode<T>*> &s) | 沿着左轮廓线遍历 | 二叉树 |
travPre_I(binNode<T>* bn_i, void(*func)(T& bn)) | 先序遍历(迭代版本:时间、空间复杂度低) | 二叉树 |
goAlongLeftBranch(binNode<T>* bn, stack<binNode<T>*> &s) | 从当前节点开始,沿着左分支深入入栈 | 二叉树 |
travIn_I(binNode<T>* bn_i, void(*func)(T& bn)) | 中序遍历(迭代版本:时间、空间复杂度低) | 二叉树 |
gotoHLVFL(stack<binNode<T>*> &s) | 在以s栈顶节点为根的子树中,找到最高左侧可见节点 | 二叉树 |
travPost_I(binNode<T>* bn_i, void(*func)(T& bn)) | 后序遍历(迭代版本:时间、空间复杂度低) | 二叉树 |
travLevel(binNode<T>* bn_i, void(*func)(T& bn)) | 层次遍历 | 二叉树 |
(1) binNode.h
#pragma once
#define stature(p) ((p)?(p)->height:-1) //宏定义不要忘记带括号
#define NULL 0
template<typename T> struct binNode
{
//成员变量
T data;
binNode<T> *parent, *lc, *rc; //指向父类,左孩子右孩子的指针
int height; //高度
//构造函数
binNode() :data(NULL), lc(nullptr), rc(nullptr), height(0) {}
binNode(T e, binNode* p = nullptr, binNode *lc = nullptr, binNode *rc = nullptr, int h = 0) :
data(e), parent(p), lc(lc), rc(rc), height(h) {}
//析构函数
~binNode() {}
//成员函数
binNode<T>* insertAsLC(const T& e); //作为本节点的左孩子插入
binNode<T>* insertAsRC(const T& e); //作为本节点的右孩子插入
int size(); //返回以本节点为root的二叉树的规模
binNode<T>* succ(); //定位在中序遍历中节点v的直接后续
//重载运算符
bool operator==(const binNode<T>& bn); //等于运算符
bool operator<(const binNode<T>& bn); //小于运算符
};
template<typename T> binNode<T>* binNode<T>::insertAsLC(const T& e)
{
return lc = new binNode<T>(e, this);
}
template<typename T> binNode<T>* binNode<T>::insertAsRC(const T& e)
{
return rc = new binNode<T>(e, this);
}
template<typename T> int binNode<T>::size()
{
int n = 0;
if (lc&&rc)
n = 1 + lc->size() + rc->size();
if (lc && (!rc))
n = 1 + lc->size();
if ((!lc) && rc)
n = 1 + rc->size();
if ((!lc) && (!rc))
return 1; //递归基
return n;
}
template<typename T> bool binNode<T>::operator==(const binNode<T>& bn)
{
return data == bn.data;
}
template<typename T> bool binNode<T>::operator<(const binNode<T>& bn)
{
return data < bn.data;
}
template<typename T> binNode<T>* binNode<T>::succ()
{
binNode<T>* s = this; //记录后续的临时变量
if (rc) //若有右孩子,则直接后继一定在右子树中的最左边
{
s = rc;
while (s->lc) s = s->lc;
}
else //若没有右孩子,则直接后继是将当前节点包含在左子树中的最低祖先
{
while ((s->parent->lc) != s)
s = s->parent;
s = s->parent;
}
return s;
}
(2) binTree.h
#pragma once
#include"binNode.h"
#include"stack.h"
#include"queue.h"
#define max(a,b) (((a)>=(b))?(a):(b))
template<typename T> class binTree
{
protected:
//成员变量
int _size; //二叉树规模
binNode<T>* _root;//根节点指针
public:
//构造函数
binTree() :_size(0), _root(nullptr) {}
//析构函数
~binTree(); //删除掉所有的子二叉树
//成员函数
int size(); //返回二叉树规模
bool empty(); //判断二叉树是否为空
binNode<T>* root(); //返回根节点的指针
binNode<T>* insertAsRoot(const T& e); //将指定元素插入作为根节点
binNode<T>* insertAsLC(binNode<T>* bn, const T& e); //将指定元素插入作为指定节点的左孩子
binNode<T>* insertAsRC(binNode<T>* bn, const T& e); //将指定元素插入作为指定节点的右孩子
binNode<T>* attachAsLC(binNode<T>* bn, binTree<T>* &bt); //将指定子树插入作为指定节点的左孩子
binNode<T>* attachAsRC(binNode<T>* bn, binTree<T>* &bt); //将指定子树插入作为指定节点的右孩子
virtual int updateHeight(binNode<T>* bn); //更新节点的高度
void updateHeightAbove(binNode<T>* bn); //更新此节点祖先节点的高度(插入或删除节点要执行更新)
int removeAt(binNode<T>* bn); //删除节点bn及其后代,并返回删掉的二叉树节点的总数
int remove(binNode<T>* bn); //删除以bn为根节点的子树
binTree<T>* secede(binNode<T>* bn); //子树分离,将节点bn及其后代从二叉树中分离出来,然后形成一个独立的二叉树
void travPre_R(binNode<T>* bn_r, void(*func)(T& bn)); //先序遍历(递归版本:简洁易懂)
void travIn_R(binNode<T>* bn_r, void(*func)(T& bn)); //中序遍历(递归版本:简洁易懂)
void travPost_R(binNode<T>* bn_r, void(*func)(T& bn)); //后序遍历(递归版本:简洁易懂)
void visitAlongLeftBranch(binNode<T>* bn, void(*func)(T& bn), stack<binNode<T>*> &s); //沿着左轮廓线遍历
void travPre_I(binNode<T>* bn_i, void(*func)(T& bn));//先序遍历(迭代版本:时间、空间复杂度低)
void goAlongLeftBranch(binNode<T>* bn, stack<binNode<T>*> &s); //从当前节点开始,沿着左分支深入入栈
void travIn_I(binNode<T>* bn_i, void(*func)(T& bn));//中序遍历(迭代版本:时间、空间复杂度低)
void gotoHLVFL(stack<binNode<T>*> &s); //在以s栈顶节点为根的子树中,找到最高左侧可见节点
void travPost_I(binNode<T>* bn_i, void(*func)(T& bn));//后序遍历(迭代版本:时间、空间复杂度低)
void travLevel(binNode<T>* bn_i, void(*func)(T& bn)); //层次遍历
};
template<typename T> binTree<T>::~binTree()
{
if (_size)
remove(_root);
}
template<typename T> int binTree<T>::size()
{
return _size;
}
template<typename T> bool binTree<T>::empty()
{
return _root ? true : false;
}
template<typename T> binNode<T>* binTree<T>::root()
{
return _root;
}
template<typename T> binNode<T>* binTree<T>::insertAsRoot(const T& e)
{
if (_root) return nullptr;
_size = 1;
return _root = new binNode<T>(e);
}
template<typename T> binNode<T>* binTree<T>::insertAsLC(binNode<T>* bn, const T& e)
{
if (bn->lc) return nullptr; //若左孩子已经存在则返回
_size++;
bn->lc = new binNode<T>(e, bn);
updateHeightAbove(bn->lc);
return bn->lc;
}
template<typename T> binNode<T>* binTree<T>::insertAsRC(binNode<T>* bn, const T& e)
{
if (bn->rc) return nullptr; //若右孩子已经存在则返回
_size++;
bn->rc = new binNode<T>(e, bn);
updateHeightAbove(bn->rc);
return bn->rc;
}
template<typename T> binNode<T>* binTree<T>::attachAsLC(binNode<T>* bn, binTree<T>* &bt)
{
if (bn->lc) return nullptr;
bn->lc = bt->root();
bt->root()->parent = bn;
updateHeightAbove(bn->lc);
_size += bt->size();
//释放bt
bt->_root = nullptr;
bt->_size = 0;
//release(bt);
bt = nullptr;
return bn->lc;
}
template<typename T> binNode<T>* binTree<T>::attachAsRC(binNode<T>* bn, binTree<T>* &bt)
{
if (bn->rc) return nullptr;
bn->rc = bt->root();
bt->root()->parent = bn;
updateHeightAbove(bn->rc);
_size += bt->size();
//释放bt
bt->_root = nullptr;
bt->_size = 0;
bt = nullptr;
return bn->rc;
}
template<typename T> int binTree<T>::updateHeight(binNode<T>* bn)
{
return bn->height = (1 + max(stature(bn->lc), stature(bn->rc)));
}
template<typename T> void binTree<T>::updateHeightAbove(binNode<T>* bn)
{
while (bn)
{
updateHeight(bn);
bn = bn->parent;
}
}
template<typename T> int binTree<T>::removeAt(binNode<T>* bn)
{
int n = 0;
if (bn == nullptr) return 0;
n = 1 + removeAt(bn->lc) + removeAt(bn->rc);
delete bn;
return n;
}
template<typename T> int binTree<T>::remove(binNode<T>* bn)
{
if (bn != _root)
{
((bn->parent->lc) == bn) ? (bn->parent->lc) = nullptr : (bn->parent->rc) = nullptr;
}
binNode<T>* bp = bn->parent;
int n = removeAt(bn);
updateHeightAbove(bp);
_size -= n;
return n;
}
template<typename T> binTree<T>* binTree<T>::secede(binNode<T>* bn)
{
//首先清除原二叉树与待删除子树的关联
if (bn != _root)
{
((bn->parent->lc) == bn) ? (bn->parent->lc) = nullptr : (bn->parent->rc) = nullptr;
}
//更新height
binNode<T>* bp = bn->parent;
updateHeightAbove(bp);
//封装成新二叉树
binTree<T>* bt = new binTree<T>();
bt->_root = bn;
bn->parent = nullptr;
//更新size
bt->_size = bn->size();
_size -= bt->_size;
//特殊情况处理
if (_root = bn)
_root = nullptr;
return bt;
}
template<typename T> void binTree<T>::travPre_R(binNode<T>* bn_r, void(*func)(T& bn))
{
if (!bn_r) return;
func(bn_r->data);
travPre_R(bn_r->lc, func);
travPre_R(bn_r->rc, func);
}
template<typename T> void binTree<T>::travIn_R(binNode<T>* bn_r, void(*func)(T& bn))
{
if (!bn_r) return;
travIn_R(bn_r->lc, func);
func(bn_r->data);
travIn_R(bn_r->rc, func);
}
template<typename T> void binTree<T>::travPost_R(binNode<T>* bn_r, void(*func)(T& bn))
{
if (!bn_r) return;
travPost_R(bn_r->lc, func);
travPost_R(bn_r->rc, func);
func(bn_r->data);
}
template<typename T> void binTree<T>::visitAlongLeftBranch(binNode<T>* bn, void(*func)(T& bn), stack<binNode<T>*> &s)
{
while (bn)
{
func(bn->data);
s.push(bn->rc); //右孩子入栈
bn = bn->lc; //沿着左边沿遍历
}
}
template<typename T> void binTree<T>::travPre_I(binNode<T>* bn_i, void(*func)(T& bn))
{
stack<binNode<T>*> S;
while (true)
{
visitAlongLeftBranch(bn_i, func, S); //遍历且入栈
if (S.empty()) break;
bn_i = S.pop();
}
}
template<typename T> void binTree<T>::goAlongLeftBranch(binNode<T>* bn, stack<binNode<T>*> &s)
{
while (bn)
{
s.push(bn);
bn = bn->lc;
}
}
template<typename T> void binTree<T>::travIn_I(binNode<T>* bn_i, void(*func)(T& bn))
{
stack<binNode<T>*> S;
while (true)
{
goAlongLeftBranch(bn_i, S);
if (S.empty()) break;
bn_i = S.pop();
func(bn_i->data);
bn_i = bn_i->rc;
}
}
template<typename T> void binTree<T>::gotoHLVFL(stack<binNode<T>*> &s)
{
while (binNode<T>* bn_i = s.top())
{
if (bn_i->lc)
{
if (bn_i->rc)
s.push(bn_i->rc);
s.push(bn_i->lc);
}
else
{
s.push(bn_i->rc);
}
}
s.pop();
}
template<typename T> void binTree<T>::travPost_I(binNode<T>* bn_i, void(*func)(T& bn))
{
stack<binNode<T>*> S;
if (bn_i)
S.push(bn_i);
while (!S.empty())
{
if (S.top() != bn_i->parent)
gotoHLVFL(S);
bn_i = S.pop();
func(bn_i->data);
}
}
template<typename T> void binTree<T>::travLevel(binNode<T>* bn_i, void(*func)(T& bn))
{
queue<binNode<T>*> q;
q.enqueue(bn_i);
while (!q.empty()) //队列非空
{
bn_i = q.dequeue();
func(bn_i->data);
if(bn_i->lc)
q.enqueue(bn_i->lc);
if(bn_i->rc)
q.enqueue(bn_i->rc);
}
}