概念:
节点:树的元素
根节点:没有父节点
内部节点:除根节点外的节点
叶节点:没有用子节点
深度depth:节点到根节点所经过的边的数目
根节点的深度 0,属于第0层
节点的度degree:节点所拥有的的子节点数(直接子节点)
叶节点的度为0.
树的高度:所有节点深度的最大值叫做树的高度。
子树:节点及该节点所有的后代和边组成子树
子树的高度
树中节点的各子树从左至右是有序的,则成为有序树,否则为无序树。
接口与实现
父节点表示法或双亲表示法
c++实现
tree_parent.h文件
#ifndef _TREE_PARENT
#define _TREE_PARENT
#include <iostream>
#include <vector>
// 树的节点
template <class type>
class Tree_Parent_Node
{
public:
type data; // 数据域
int parent; // 父节点,根节点的父节点可以设置为-1
};
// 树结构,用vector存储单个节点
template <class type>
class Tree_Parent
{
public:
Tree_Parent_Node<type> &operator[](int i);
template <class type1>
friend std::ostream &operator<<(std::ostream &out, Tree_Parent<type1> &t);
private:
std::vector<Tree_Parent_Node<type>> tree;
};
// 重载[]运算符
template <class type>
Tree_Parent_Node<type> &Tree_Parent<type>::operator[](int i)
{
return tree[i];
}
// 重载<<运算符
template <class type1>
std::ostream &operator<<(std::ostream &out, Tree_Parent<type1> &t)
{
for (int i = 0; i < t.size(); i++)
{
out << "index: " << i << " "
<< "data: " << t[i].data << " "
<< "parent: " << t[i].parent << "\n";
}
return out;
}
#endif
这样站到某个节点的父节点很容易, 时间复杂度O(1)。但是孩子节点需要遍历整个树。
这个时候,我们可以在每个节点中增加一个第一个孩子节点,这样就可以快速找到节点的孩子。
template <class type>
class Tree_Parent_Node
{
public:
type data;
int parent, firstchild; // 没有孩子节点firstchild就可以设置为-1
};
但是一个节点有多个孩子的问题,并没有解决,还是需要遍历树,可以继续增加孩子节点来表示第二个、第三个孩子,但是这样会存在空间浪费的问题。
类似的,兄弟节点之间的关系,可以增加一个右兄弟节点,来表示某个节点的有兄弟
template <class type>
class Tree_Parent_Node
{
public:
type data;
int parent, rightsib;// 没有有兄弟时,rightsib为-1
};
这上面的三种方式时可以灵活组合的。
孩子表示法
把每个节点的孩子节点用单链表的存储,n个节点就有n个孩子链表,n个头指针用顺序存储结构,放在数组中.
// 某个节点的孩子节点的位置组成的链表
class Tree_Child_Nodechild
{
int child;
Tree_Child_Nodechild *next;
};
// 树的节点
template <class type>
class Tree_Child_Node
{
type data;
Tree_Child_Nodechild *head;
};
// 树, 用vector存储
template <class type>
class Tree_Child
{
private:
std::vector<Tree_Child_Node<type>> tree;
int r, n;// 根节点的位置和节点数
};
树的节点里面还可以增加表示父节点的位置,方便找到父节点
// 树的节点
template <class type>
class Tree_Child_Node
{
type data;
int parent;
Tree_Child_Nodechild *head;
};
上面两种方式都是将节点存储在了数组之中,这样的好处,可以快速根据位置找到节点。
每个节点中包括数据域、父节点在数组中的位置或孩子节点在数组中的位置或者兄弟节点在数组中的位置,或者数据域中包含了该节点的孩子节点组成的链表。
孩子兄弟表示法
节点包含数据域,第一个孩子节点的指针,右兄弟节点的指针。然后有个头指针指向根节点。
节点表示:
template <class datatype>
class CSNode
{
datatype data;
CSNode *firstchild, *rightsib;
};
然后树的定义:
template <class datatype>
class Tree
{
private:
CSNode *head;
};
这种表示可以很方便的找到某个节点的孩子节点,先找到第一个孩子节点,然后第一个孩子节点的有兄弟节点,一次类推往后找孩子节点。另外还可以在节点中增加一个parent指针表示父节点
template <class datatype>
class CSNode
{
datatype data;
CSNode *parent, *firstchild, *rightsib;
};
这种方式根据位置找对应节点时,需要进行遍历的。但是这种的好处是可以将树转化成二叉树。这样可以利用很多二叉树的性质。
孩子兄弟表示法应该是比较常用的表示树结构的方式