树的存储结构
- 顺序存储(双亲表示法)
- 每个结点中保存指向双亲的“指针”(位置下标)
#define MAX_TYPE_SIZE 100 //树中最多结点数
typedef struct{
ElemType data; //数据元素
int parent; //双亲位置域
}PTNode;
typedef struct{ //树的类型定义
PTNode nodes[MAX_TYPE_SIZE]; //双亲表示
int n; //结点数
}PTree;
- 顺序+链式存储(孩子表示法)
- 顺序存储各个结点,每个结点中保存孩子链表头指针
//顺序+链式
struct CTNode{
int child; //孩子结点在数组中的位置
struct CTNode *next; //下一个孩子
};
typedef struct{
ElemType data;
struct CTNode *firstChild; //第一个孩子
}CTBox;
typedef struct{
CTBox nodes[MAX_TYPE_SIZE];
int n, r; //结点数和根的位置
}CTree;
- 链式存储(孩子兄弟表示法)
- 总结
树的遍历
//树的先根遍历 —— (深度优先遍历)
void PreOrder(TreeNode *R){
if(R != NULL){
visit(R); //访问根节点
while(R还有下一个子树T)
PreOrder(T); //先根遍历下一棵子树
}
}
//树的后根遍历 —— (深度优先遍历)
void PostOrder(TreeNode *R){
if(R != NULL){
while(R还有下一个子树T)
PostOrder(T); //先根遍历下一棵子树
}
visit(R); //访问根节点
}
//树的层序遍历 —— (广度优先遍历)
1. 若树非空,则根节点入队
2. 若队列非空,队头元素出队并访问,同时将该元素的孩子依次入队
3. 重复(2)直到队列为空
哈夫曼树
- 基本概念
- 结点的权:有某种现实含义的数值(如:表示结点的重要性等)
- 结点的带权路径长度:从树的根到该结点的路径长度(经过的边数)与该结点上权值的乘积
- 树的带权路径长度:树中所有叶子结点的带权路径长度之和
- 在含有n个带权叶结点的二叉树中,其中带权路径长度(WPL)最小的二叉树称为哈夫曼树,也称最优二叉树
哈夫曼树的构造
--给定n个权值分别为W1, W2, W3,...,Wn的结点,构造算法如下:
- 将这n个结点分别作为n棵仅含一个结点的二叉树,构成森林F
- 构造一个新结点,从F中选取两棵根结点权值最小的树作为新结点的左、右子树,并且将新结点的权值置为左、右子树上根结点的权值之和’
- 从F中删除刚才选出的两棵树,同时将新得到的树加入F中
- 重复步骤2, 3, 直至F中只剩下一棵树为止
- 每个初始结点最终都成为叶结点,且权值越小的结点到根结点的路径越大
- 哈夫曼树的结点总数为2n-1
- 哈夫曼树中不存在度为1的结点
- 哈夫曼树并不唯一,但WPL必然相同且为最优
哈夫曼编码
总结: