双亲表示法
在树中,除了根节点外的任意一个结点都有一个唯一的双亲结点,因此可以考虑使用一组连续的储存空间储存树中的每一个结点,数组中的一个元素可以表示为树中的一个结点。在数组元素中除包含结点元素本身,还包含它的双亲在数组中的序号(从0开始)。根节点的双亲域赋值为-1。
这种表示方法称为双亲表示法。图例如下:
- 这种方法求某个节点的双亲比较方便,但是如果想要求某个结点的孩子结点,则需要查询整个数组。
- 这种方法也不能直接反应各兄弟结点之间的关系,所以求兄弟也比较困难。
实际上,可以在数组元素中增加两个域以解决上述问题:一个数据域存放该结点的第一个孩子结点在数组中的序号;另一个存放该结点的兄弟结点在数组中的序号。
孩子表示法
多重链表法 用一个多重链表表示树,链表中的每一个结点包含一个数据域(存放该结点的元素)和多个指针域(存放该结点的孩子)。
因为各个结点的孩子数不同,所以结点的指针域个数有两种不同的设置方法:
- 每个结点的指针域个数等于该结点的度数。这种方法比较直接,但是由于各结点构造不同,实际操作中较少使用。
- 每个结点指针域个数等于树的度数。这种方法各个结点是同构的。但是由于树中各结点的度数一般小于树的度数,容易造成存储空间的浪费。
数组表示法 用一维数组顺序存储树中的各个结点的信息,并将各结点的孩子信息组成一个单链表。孩子链表的每一个结点表示一个孩子结点,它由两个域组成,其中一个数据域存放孩子结点在数组中的序号,另一个指针域存放它的兄弟结点。
双亲-孩子表示法
就是将上述两个方法结合起来
代码实现:
template <class ElemType>
struct ChildParentTreeNode
{
// 数据成员:
ElemType data; // 数据域
Node<int> *childLkList; // 孩子链表
int parent; // 双亲位置域
// 构造函数:
ChildParentTreeNode(); // 无参数的构造函数
ChildParentTreeNode(ElemType item, int pt = -1, Node<int> *childlk = NULL);// 已知数据域值和双亲位置建立结构
};
孩子双亲表示树类:
template <class ElemType>
class ChildParentTree
{
protected:
// 树的数据成员:
ChildParentTreeNode<ElemType> *nodes; // 存储树结点
int maxSize; // 树结点最大个数
int root, num; // 根的位置及结点数
// 辅助函数:
void PreRootOrderHelp(int r, void (*Visit)(const ElemType &)) const; // 先根序遍历
void PostRootOrderHelp(int r, void (*Visit)(const ElemType &)) const; // 后根序遍历
int HeightHelp(int r) const; // 返回以r为根的高
int DegreeHelp(int r) const; // 返回以r为根的树的度
public:
// 树方法声明及重载编译系统默认方法声明:
ChildParentTree(); // 无参构造函数
virtual ~ChildParentTree(); // 析构函数
int GetRoot() const; // 返回树的根
bool Empty() const; // 判断树是否为空
Status GetElem(int cur, ElemType &e) const; // 用e返回结点元素值
Status SetElem(int cur, const ElemType &e); // 将结cur的值置为e
void PreRootOrder(void (*Visit)(const ElemType &)) const; // 树的先序遍历
void PostRootOrder(void (*Visit)(const ElemType &)) const; // 树的后序遍历
void LevelOrder(void (*Visit)(const ElemType &)) const; // 树的层次遍历
int NodeCount() const; // 返回树的结点个数
int NodeDegree(int cur) const; // 返回结点cur的度
int Degree() const; // 返回树的度
int FirstChild(int cur) const; // 返回结点cur的第一个孩子
int RightSibling(int cur) const; // 返回结点cur的右兄弟
int Parent(int cur) const; // 返回结点cur的双亲
Status InsertChild(int cur, int i, const ElemType &e);
// 将数据元素插入为cur的第i个孩子
int Height() const; // 返回树的高
ChildParentTree(const ElemType &e, int size = DEFAULT_SIZE);
// 建立以数据元素e为根的树
ChildParentTree(ElemType items[], int parents[], int r, int n, int size = DEFAULT_SIZE);
// 建立数据元素为items[],对应结点双亲为parents[],根结点位置为r,结点个数为n的树
};
孩子-兄弟表示法
这是一种链式存储结构,链表中一个结点表示树中的一个结点。它除一个信息域外,还有两个指针域。一个指针域指向该结点的第一个孩子结点;另一个指向该结点的兄弟结点。这种方法又称为二重链表表示法。
我们一般采用此方法进行树的存储。
代码实现:
// 孩子兄弟表示树结点类
template <class ElemType>
struct ChildSiblingTreeNode
{
// 数据成员:
ElemType data; // 数据域
ChildSiblingTreeNode<ElemType> *firstChild; // 指向首孩子指针域
ChildSiblingTreeNode<ElemType> *nextSibling;// 指向右兄弟指针域
// 构造函数:
ChildSiblingTreeNode(); // 无参数的构造函数
ChildSiblingTreeNode(ElemType val, // 有参数的构造函数
ChildSiblingTreeNode<ElemType> *fChild = NULL,
ChildSiblingTreeNode<ElemType> *nSibling = NULL);
};
由此可以对使用该种方法表示的树进行各种典型操作:
template <class ElemType>
class ChildSiblingTree
{
protected:
// 树的数据成员:
ChildSiblingTreeNode<ElemType> *root; // 根指针
// 辅助函数:
void Destroy(ChildSiblingTreeNode<ElemType> * &r); // 销毁以r为根的树
void PreRootOrder(ChildSiblingTreeNode<ElemType> *r, void (*Visit)(const ElemType &)) const;
// 先根遍历以r为根的数
void PostRootOrder(ChildSiblingTreeNode<ElemType> *r, void (*Visit)(const ElemType &)) const;
// 后根遍历以r为根的数
int NodeCount(ChildSiblingTreeNode<ElemType> *r) const; // 求以r为根的树的结点个数
int Height(ChildSiblingTreeNode<ElemType> *r) const; // 求以r为根的树的高
int Degree(ChildSiblingTreeNode<ElemType> *r) const; // 求以r为根的树的度
ChildSiblingTreeNode<ElemType> *Parent(ChildSiblingTreeNode<ElemType> *r,
const ChildSiblingTreeNode<ElemType> *cur) const; // 求cur的双亲
ChildSiblingTreeNode<ElemType> *CopyTree(ChildSiblingTreeNode<ElemType> *copy);
// 复制树
ChildSiblingTreeNode<ElemType> *CreateTreeGhelp(ElemType items[], int parents[], int r, int n);
// 建立数据元素为items[],对应结点双亲为parents[],根结点位置为r,结点个数为n的树,并 求树的根
public:
// 孩子兄弟表示树类方法的声明:
ChildSiblingTree(); // 无参数的构造函数
virtual ~ChildSiblingTree(); // 析构函数
ChildSiblingTreeNode<ElemType> * GetRoot() const; // 求树的根
bool IsEmpty() const; // 判断树是否为空
Status GetElem(ChildSiblingTreeNode<ElemType> *cur, ElemType &e) const;
// 用e 求结点元素值
Status SetElem(ChildSiblingTreeNode<ElemType> *cur, const ElemType &e);
// 将结cur的值置为e
void PreRootOrder(void (*Visit)(const ElemType &)) const; // 树的先根序遍历
void PostRootOrder(void (*Visit)(const ElemType &)) const; // 树的后根序遍历
void LevelOrder(void (*Visit)(const ElemType &)) const; // 树的层次遍历
int NodeCount() const; // 求树的结点个数
int NodeDegree(ChildSiblingTreeNode<ElemType> *cur) const; // 求结点cur的度
int Degree() const; // 求树的度
ChildSiblingTreeNode<ElemType> *FirstChild(ChildSiblingTreeNode<ElemType> *cur) const;
// 求树结点cur的第一个孩子
ChildSiblingTreeNode<ElemType> *NextSibling(ChildSiblingTreeNode<ElemType> *cur) const;
// 求树结点cur的下一个兄弟
ChildSiblingTreeNode<ElemType> *Parent(ChildSiblingTreeNode<ElemType> *cur) const;
// 求结点cur的双亲
Status InsertChild(ChildSiblingTreeNode<ElemType> *cur, int i, const ElemType &e);
// 将数据元素e插入为cur的第i个孩子
Status DeleteChild(ChildSiblingTreeNode<ElemType> *cur, int i);// 删除cur的第i个棵子树
int Height() const; // 求树的高
ChildSiblingTree(const ElemType &e); // 建立以数据元素e为根的树
ChildSiblingTree(const ChildSiblingTree<ElemType> ©); // 复制构造函数
ChildSiblingTree(ElemType items[], int parents[], int n);
// 建立数据元素为items[],对应结点双亲为parents[],根结点位置为r,结点个数为n的树
ChildSiblingTree(ChildSiblingTreeNode<ElemType> *r);// 建立以r为根的树
ChildSiblingTree<ElemType> &operator=(const ChildSiblingTree<ElemType>& copy);
// 重载赋值运算
};