数据结构 - 树 - 一般树和森林的基本介绍
树的存储结构
双亲表示法
通过保存树中每个结点的双亲结点的位置,来表示树中结点之间的结构关系。
#define MAX_TREE_SIZE 100
typedef struct PTNode
{
ElemType data;
int parent; // 双亲位置(双亲的下标)
} PTNode;
typedef struct
{
PTNode nodes[MAX_TREE_SIZE];
int r, n; // r为根的位置,n为结点数
} Ptree;
孩子表示法
通过保存树中每个结点的孩子结点的位置,表示树中结点之间的结构关系。
方法一:多重链表
类似于二叉链表,我们可以用多叉链表。具体实现有两种方式:定长结点和不定长结点。
- 定长结点:优点是结点结构一致,便于实现树的操作,缺点是浪费一些内存空间。
- 不定长结点:优点是节省内存空间,缺点是不定长的结点会使一些操作实现变复杂。
方法二:孩子链表
将树中的每个结点的孩子排列起来,看成一个线性表,采用线性链表进行存储。
树的孩子链表的类型定义如下:
typedef struct CTNode // 孩子结点
{
int child;
struct CTNode* next;
} *ChildPtr;
typedef struct
{
ElemType data;
ChildPtr firstchild; // 孩子链表头指针
} CTBox;
typedef struct
{
CTBox nodes[MAX_TREE_SIZE];
int n, r; // 结点数和根的位置
} CTree;
孩子兄弟表示法
我们也可以仍用二叉链表作为树的存储结构。
树的孩子兄弟表示法的类型定义如下:
typedef struct CSNode
{
ElemType data;
struct CSNode
* firstchild, //指向第一个孩子
* nextsibling; //指向下一个兄弟
} CSNode, * CSTree;
树与二叉树
树与二叉树的转换
二叉树和树都可以用二叉链表存储,我们可以以二叉链表为中介,实现树与二叉树之间的转换。其转换的方法图示如下:
森林与二叉树的转换
森林:树的集合。
将森林中的树的根结点看作兄弟,用树与二叉树的转换方法,进行森林与二叉树的转换。
树的遍历
遍历:按一定规律走遍树的各个顶点,且使每一顶点仅被访问一次,即找一个完整而有规律的走法,以得到树中所有结点的一个线性序列。
常用方法如下:
-
先根(序)遍历:先访问树的根结点,然后依次先根遍历根的每棵子树。
-
后根(序)遍历:先依次后根遍历每棵子树,然后访问根结点。
-
层次遍历:先访问第一层上的结点,然后依次遍历第二层,一直到最后一层的结点。