【数据结构八】树的存储结构以及遍历和哈夫曼树

101 阅读2分钟

树的存储结构

  • 顺序存储(双亲表示法)
    • 每个结点中保存指向双亲的“指针”(位置下标)

图片.png

#define MAX_TYPE_SIZE 100  //树中最多结点数
typedef struct{
	ElemType data; //数据元素
	int parent;  //双亲位置域 
}PTNode;
typedef struct{ //树的类型定义
	PTNode nodes[MAX_TYPE_SIZE]; //双亲表示
	int n;   //结点数 
}PTree; 

  • 顺序+链式存储(孩子表示法)
    • 顺序存储各个结点,每个结点中保存孩子链表头指针

图片.png

//顺序+链式
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; 
  • 链式存储(孩子兄弟表示法)

图片.png

  • 总结

图片.png

树的遍历

//树的先根遍历 —— (深度优先遍历)
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中只剩下一棵树为止

a900b097cd6c8b37cd46f3577d4480b.png

  • 每个初始结点最终都成为叶结点,且权值越小的结点到根结点的路径越大
  • 哈夫曼树的结点总数2n-1
  • 哈夫曼树中不存在度为1的结点
  • 哈夫曼树并不唯一,但WPL必然相同且为最优

a900b097cd6c8b37cd46f3577d4480b.png

哈夫曼编码

图片.png

总结:

图片.png