一、树
树是n(n≥0)个结点的有限集合。n=0时称为空树。在任意一棵非空树中:
(1)有且仅有一个特定的称为根(root)的结点;
(2)当n>1时,其余结点可分为m(m>0)个互不相交的有限集T1,T2,…,Tm,其中每一个集合本身又有一棵树,并且称为根的子树。
结点拥有的子树数称为结点的度(degree)。度为0的结点称为叶结点(leaf)或终端结点;度不为0的结点称为非终端结点或分支结点。除根结点之外,分支结点也称为内部结点。树的度是树内各结点的度的最大值。树中结点的最大层次称为树的深度(depth)或高度。
如果将树中结点的各子树看成从左至右是有序的,不能互换的,则称该树为有序树,否则称为无序树。
森林(forest)是m(m≥0)棵互不相交的树的集合。
树的存储结构的常用表示法是孩子表示法,即每个结点有多个指针域,其中每个指针指向一棵子树的根结点,即用多重链表来表示树。
树的常见操作有:
(1)初始化,建立一个空的树;
(2)销毁树;
(3)按照给定内容创建一棵树;
(4)将树中数据清空;
(5)判断树是否为空;
(6)获得树的深度;
(7)获得树的根结点;
(8)获得树中给定结点处的数据值;
(9)将树中给定结点处赋值为给定值;
(10)获得树的指定结点的父结点;
(11)获得树的指定结点的左孩子结点;
(12)获得树的指定结点的右孩子结点;
(13)在树中指定结点处插入给定值作为新的结点;
(14)删除树中的指定结点;
(15)查找在树的结点中是否有结点的数据值与给定值相等;
(16)树的所有结点的顺序遍历。
二、二叉树
普通树的操作是很复杂的,且没有良好的性质,一般不常用。常用的是树的一个特例,二叉树。
二叉树(binary tree)是n(n≥0)个结点的有限集合,该集合或者为空集(称为空二叉树),或者由一个根结点和两棵互不相交的,分别称为根结点的左子树和右子树的二叉树组成。
在一棵二叉树中,如果所有分支结点都存在左子树和右子树,并且所有叶子都在同一层上,这样的二叉树称为满二叉树。
对一棵具有n个结点的二叉树按层序编号,如果编号为i(1≤i≤n)的结点与同样深度的满二叉树中编号为i的结点在二叉树中位置完全相同,则这棵二叉树称为完全二叉树。
二叉树具有以下性质:
(1)在二叉树的第i层上至多有2^(i-1)个结点(i≥1)。
(2)深度为k的二叉树至多有2^k-1个结点(k≥1)。
(3)对任何一棵二叉树T,如果其终端结点数为n0,度为2的结点数为n2,则n0=n2+1。
(4)具有n个结点的完全二叉树的深度为floor(log2N)+1。
(5)如果对一棵有n个结点的完全二叉树的结点按层序编号(从第1层到最后一层,每层从左到右),对任一结点i(1≤i≤n)有:
①如果i=1,则结点i是二叉树的根,无双亲;如果i>1,则其双亲是结点floor(i/2);
②如果2i>n,则结点i无左孩子(结点i为叶子结点);否则其左孩子是结点2i;
③如果2i+1>n,则结点i无右孩子;否则其右孩子是结点2i+1。
二叉树一般用二叉链表表示,二叉链表的结点结构为:
template<typename T>
class Node
{
public:
T data;
Node *lchild, *rchild;
Node(T _data)
{
data = _data;
lchild = nullptr;
rchild = nullptr;
}
~Node()
{
if (lchild != nullptr)
{
delete lchild;
}
if (rchild != nullptr)
{
delete rchild;
}
}
};
template<typename T>
class BinaryTree
{
private:
Node *root;
public:
BinaryTree()
{
root = nullptr;
}
~BinaryTree()
{
delete root;
}
void build_demo()
{
root = new Node(1);
root->lchild = new Node(2);
root->rchild = new Node(3);
root->lchild->lchild = new Node(4);
root->lchild->rchild = new Node(5);
root->rchild->rchild = new Node(6);
}
};
二叉树的常见创建方式有:
// 根据A(,C)形式的字符串构建二叉树
template<typename T>
Node<T> *str2Tree(const string &str)
{
int len = str.length();
if (len == 0)
{
return nullptr;
}
Node<T> *p = new Node<T>(str[0]);
Node<T> *finalPtr = p;
stack<Node<T>*> s;
int state = 0;
for (int i = 1; i < len; ++i)
{
switch (str[i])
{
case '(':
s.push(p);
state =