全知识整理目录
数据结构整理的目录包括了许多的数据结构相关知识。
目录
概述
什么是哈夫曼树呢?
哈夫曼树,又称为最优二叉树。给定n个权值作为n个叶子节点,构造一颗二叉树,若树的带权路径长度达到最小,则这棵树称为哈夫曼树。
简易理解:带权路径长度(WPL)最小的树就是哈夫曼树,WPL=所有叶子节点的权值*路径长度。
基本概念
路径长度:经过一个结点,路径长度就要+1,下图根节点到c的路径长度为3。
权值:每个结点都有一个权值(通常情况下,为了统一哈夫曼树,左边通常是小的权值结点)。
WPL(带权路径长度):WPL=7*1+5*2+3*(2+4)
构造哈夫曼树(过程)
构造哈夫曼树的基本步骤:
- 在给定权值中,选出最小的两个权值,对应两个结点组成一个新的二叉树,且新结点为两个左右孩子权值的和。
- 再选权值最小的结点,作为第一次组成的二叉树的根节点的兄弟结点。
这样就能排列出,一颗哈夫曼树。下面给出具体的步骤:
首先选出最小的两个结点(c,d)构成树。
再选出最小结点(b)和根节点构成二叉树。
再选出最小结点(a)和根节点构成二叉树。
得到最后的哈夫曼树。
构造哈夫曼树(代码)
结点构成
typedef struct{
int weight; //结点的权值
int parent,left,right; //父节点,左孩子,右孩子在数组中的位置下标。
}HTNode,*HuffmanTree;
哈夫曼树查找算法
//HT是哈夫曼树,end是HT数组存放结点的最后位置,s1.s2是传递数组种权重最小的那两个结点的位置
void Select(HuffmanTree HT, int end, int *s1, int *s2)
{
int min1, min2;
//遍历数组初始下标为 1
int i = 1;
//找到还没构建树的结点
while(HT[i].parent != 0 && i <= end){
i++;
}
min1 = HT[i].weight;
*s1 = i;
i++;
while(HT[i].parent != 0 && i <= end){
i++;
}
//对找到的两个结点比较大小,min2为大的,min1为小的
if(HT[i].weight < min1){
min2 = min1;
*s2 = *s1;
min1 = HT[i].weight;
*s1 = i;
}else{
min2 = HT[i].weight;
*s2 = i;
}
//两个结点和后续的所有未构建成树的结点做比较
for(int j=i+1; j <= end; j++)
{
//如果有父结点,直接跳过,进行下一个
if(HT[j].parent != 0){
continue;
}
//如果比最小的还小,将min2=min1,min1赋值新的结点的下标
if(HT[j].weight < min1){
min2 = min1;
min1 = HT[j].weight;
*s2 = *s1;
*s1 = j;
}
//如果介于两者之间,min2赋值为新的结点的位置下标
else if(HT[j].weight >= min1 && HT[j].weight < min2){
min2 = HT[j].weight;
*s2 = j;
}
}
}
哈夫曼编码
哈夫曼编码就是在哈夫曼树的基础上建立的,这种编码的有点是,使用最少的字符,包含最多的信息。
对于树种的每一个子树,统一规定其左孩子标记为0,统一规定其右孩子标记为1。用到那个字符就从哈夫曼树的根节点开始,经过依次写出结点的标记,最终得到的就是哈夫曼编码。
所以,文本字符出现的次数越多就越接近树根,编码长度越短。
如上图所示:字符a的哈夫曼编码是0,字符b的编码为10,字符c的编码为110,字符d的编码为111。