Huffman Tree的构建
赫夫曼树的构建步骤如下:
1、将给定的n个权值看做n棵只有根节点(无左右孩子)的二叉树,组成一个集合HT,每棵树的权值为该节点的权值。
2、从集合HT中选出2棵权值最小的二叉树,组成一棵新的二叉树,其权值为这2棵二叉树的权值之和。
3、将步骤2中选出的2棵二叉树从集合HT中删去,同时将步骤2中新得到的二叉树加入到集合HT中。
4、重复步骤2和步骤3,直到集合HT中只含一棵树,这棵树便是赫夫曼树。
Huffman编码的C实现
/*
赫夫曼树的存储结构,它也是一种二叉树结构,
*/
typedef struct Node
{
int weight;//权值
int parent;//父节点的序号,为-1的是跟节点
int lchild,rchild;//左右孩子节点,为-1是叶子节点
}HYNode,*HuffmanTree;//用来存储赫夫曼树中的所有节点
typedef char **HUffmanCode;
/*
根据给定的n个权值构造一棵赫夫曼树,wet中存放n个权值
*/
HuffmanTree create_HuffmanTree(int *wet,int n)
{
//一棵有n个叶子节点的赫夫曼树共有2n-1个节点
int total=2*n-1;
HuffmanTree HT=(HuffmanTree)malloc(total*sizeof(HTNode));
if(!HT)
{
printf("HuffmanTree malloc failed ");
exit(-1);
}
int i;
//以下初始化序号全部用-1表示,
//这样在编码函数中进行循环判断parent或lchild或rchild的序号时,
//不会与HT数组中的任何一个下标混淆
//HT[0],HT[1]...HT[n-1]中存放需要编码的n个叶子节点
for(i=0;i<n;i++)
{
HT[i].parent=-1;
HT[i].lchild=-1;
HT[i].rchild = -1;
HT[i].weight = *wet;
wet++;
}
//HT[n],HT[n+1]...HT[2n-2]中存放的是中间构造出的每棵二叉树的根节点
for(;i<total;i++)
{
HT[i].parent = -1;
HT[i].lchild = -1;
HT[i].rchild = -1;
HT[i].weight = 0;
}
int min1,min2;/用来保存每一轮选出的两个weight最小且parent为0的节点
//每一轮比较后选择出min1和min2构成一课二叉树,最后构成一棵赫夫曼树
for(i=n;i<total;i++)
{
select_minium(HT,i,min1,min2);
HT[min1].parent=i;
HT[min2].parent=i;
//这里左孩子和右孩子可以反过来,构成的也是一棵赫夫曼树,只是所得的编码不同
HT[i].lchild = min1;
HT[i].rchild = min2;
HT[i].weight =HT[min1].weight + HT[min2].weight;
}
return HT;
}
/*
从HT数组的前k个元素中选出weight最小且parent为-1的两个,分别将其序号保存在min1和min2中
*/
void select_minium(HuffmanTree HT,int k,int &min1,int &min2)
{
min1=min(HT,k);
min2=min(HT,k);
}
/*
从HT数组的前k个元素中选出weight最小且parent为-1的元素,并将该元素的序号返回
*/
int min(HuffmanTree HT,int k)
{
int i=0;
int min;//用来存放weight最小且parent为-1的元素的序号
int min_weight;//用来存放weight最小且parent为-1的元素的weight值
//先将第一个parent为-1的元素的weight值赋给min_weight,留作以后比较用。
//注意,这里不能按照一般的做法,先直接将HT[0].weight赋给min_weight,
//因为如果HT[0].weight的值比较小,那么在第一次构造二叉树时就会被选走,
//而后续的每一轮选择最小权值构造二叉树的比较还是先用HT[0].weight的值来进行判断,
//这样又会再次将其选走,从而产生逻辑上的错误。
while(HT[i].parent!=-1)
i++;
min_weight=HT[i].weight;
min=i;
//选出weight最小且parent为-1的元素,并将其序号赋给min
for(;i<k;i++)
{
if(HT[i].weight<min_weight&&HT[i].parent==-1)
{
min_weight=HT[i].weight;
min=i;
}
}
HT[min].weight=1;
return min;
}
两种Huffman编码方法
1、采用从叶子节点到根节点逆向遍历求每个字符的赫夫曼编码
/*
从叶子节点到根节点逆向求赫夫曼树HT中n个叶子节点的赫夫曼编码,并保存在HC中
*/
void HuffmanCoding(HuffmanTree HT,HuffmanCode &HC,int n)
{
//用来保存指向每个赫夫曼编码串的指针
HC = (HuffmanCode)malloc(n*sizeof(char *));
if(!HC)
{
printf("HuffmanCode malloc faild!");
exit(-1);
}
//临时空间,用来保存每次求得的赫夫曼编码串
//对于有n个叶子节点的赫夫曼树,各叶子节点的编码长度最长不超过n-1
//外加一个'\0'结束符,因此分配的数组长度最长为n即可
char *code = (char *)malloc(n*sizeof(char));
if(!code)
{
printf("code malloc faild!");
exit(-1);
}
code[n-1] = '\0'; //编码结束符,亦是字符数组的结束标志
//求每个字符的赫夫曼编码
int i;
for(i=0;i<n;i++)
{
int current = i; //定义当前访问的节点
int father = HT[i].parent; //当前节点的父节点
int start = n-1; //每次编码的位置,初始为编码结束符的位置
//从叶子节点遍历赫夫曼树直到根节点
while(father != -1)
{
if(HT[father].lchild == current) //如果是左孩子,则编码为0
code[--start] = '0';
else //如果是右孩子,则编码为1
code[--start] = '1';
current = father;
father = HT[father].parent;
}
//为第i个字符的编码串分配存储空间
HC[i] = (char *)malloc((n-start)*sizeof(char));
if(!HC[i])
{
printf("HC[i] malloc faild!");
exit(-1);
}
//将编码串从code复制到HC
strcpy(HC[i],code+start);
}
free(code); //释放保存编码串的临时空间
}
2、采用从根节点到叶子节点无栈非递归遍历赫夫曼树,求每个字符的赫夫曼编码,
/*
从根节点到叶子节点无栈非递归遍历赫夫曼树HT,求其中n个叶子节点的赫夫曼编码,并保存在HC中
*/
void HuffmanCoding2(HuffmanTree HT,HuffmanCode &HC,int n)
{
//用来保存指向每个赫夫曼编码串的指针
HC = (HuffmanCode)malloc(n*sizeof(char *));
if(!HC)
{
printf("HuffmanCode malloc faild!");
exit(-1);
}
//临时空间,用来保存每次求得的赫夫曼编码串
//对于有n个叶子节点的赫夫曼树,各叶子节点的编码长度最长不超过n-1
//外加一个'\0'结束符,因此分配的数组长度最长为n即可
char *code = (char *)malloc(n*sizeof(char));
if(!code)
{
printf("code malloc faild!");
exit(-1);
}
int cur = 2*n-2; //当前遍历到的节点的序号,初始时为根节点序号
int code_len = 0; //定义编码的长度
//构建好赫夫曼树后,把weight用来当做遍历树时每个节点的状态标志
//weight=0表明当前节点的左右孩子都还没有被遍历
//weight=1表示当前节点的左孩子已经被遍历过,右孩子尚未被遍历
//weight=2表示当前节点的左右孩子均被遍历过
int i;
for(i=0;i<cur+1;i++)
{
HT[i].weight = 0;
}
//从根节点开始遍历,最后回到根节点结束
//当cur为根节点的parent时,退出循环
while(cur != -1)
{
//左右孩子均未被遍历,先向左遍历
if(HT[cur].weight == 0)
{
HT[cur].weight = 1; //表明其左孩子已经被遍历过了
if(HT[cur].lchild != -1)
{ //如果当前节点不是叶子节点,则记下编码,并继续向左遍历
code[code_len++] = '0';
cur = HT[cur].lchild;
}
else
{ //如果当前节点是叶子节点,则终止编码,并将其保存起来
code[code_len] = '\0';
HC[cur] = (char *)malloc((code_len+1)*sizeof(char));
if(!HC[cur])
{
printf("HC[cur] malloc faild!");
exit(-1);
}
strcpy(HC[cur],code); //复制编码串
}
}
//左孩子已被遍历,开始向右遍历右孩子
else if(HT[cur].weight == 1)
{
HT[cur].weight = 2; //表明其左右孩子均被遍历过了
if(HT[cur].rchild != -1)
{ //如果当前节点不是叶子节点,则记下编码,并继续向右遍历
code[code_len++] = '1';
cur = HT[cur].rchild;
}
}
//左右孩子均已被遍历,退回到父节点,同时编码长度减1
else
{
HT[cur].weight = 0;
cur = HT[cur].parent;
--code_len;
}
}
free(code);
}
分享到:
相关推荐
利用Huffman树实现对文件的无损压缩与解压,并且对Huffman树的创建也做了详细的说明与讲解,C语言实现的.....值得一看....
本项目将深入探讨如何使用C语言实现Huffman树和Huffman编码。 首先,我们要理解Huffman树(也称为最优二叉树或最小带权路径长度树)。这种特殊的二叉树是由赫尔曼·霍夫曼在1952年提出,其构建过程基于字符出现的...
Huffman编码的生成是通过遍历Huffman树实现的,从根节点开始,沿着左分支走代表'0',沿着右分支走代表'1',到达叶节点时,记录下从根到叶的路径,即为该字符的编码。所有的字符编码都会被记录下来,用于后续的编码和...
压缩以及解压采用huffman原始算法,没有进行任何优化,可能效率不高,时间不快,只希望对初学者有所帮助。 特点:支持文件夹(linux下称目录)的压缩,可以直接打包整个目录(或多个目录)。 压缩后的二进制文件,...
Huffman树,也被称为哈夫曼树或霍夫曼树,是一种特殊的二叉树,用于在数据压缩领域实现高效的编码方法——Huffman编码。这种编码技术是基于频率的,能够为出现频率高的字符分配较短的编码,而为出现频率低的字符分配...
本篇文章将详细介绍如何在C语言中实现Huffman编码,包括Huffman树的构建、编码过程以及解码过程,并提供完整的代码示例。 #### 二、Huffman编码原理 1. **统计字符频率**:首先统计待压缩文本中每个字符出现的频率...
用C++语言实现huffman树的源代码
《构建Huffman树及其编码应用》 Huffman树,又称为最优二叉树或霍夫曼树,是一种特殊的二叉树,广泛应用于数据压缩中,尤其是文本压缩。它的构造原则是基于最小带权路径长度(Minimum Spanning Tree,MST)的概念,...
哈夫曼树(Huffman Tree),也称为最优二叉树,是数据压缩技术中的关键算法之一。它是一种带权路径长度最短的二叉树,用于实现哈夫曼编码(Huffman Encoding)。在这个主题中,我们将深入探讨如何使用C++语言来构建...
哈弗曼树实现 Huffman实现 哈夫曼实现 c++实现 使用方法 getCode:一个map, int> 的对象,该对象表示对ascii文件的统计数据,一个map, pair, int> > 的对象,该对象是编码后各个字符的对应的编码以及该编码的长度 ...
Huffman编码是一种高效的数据压缩方法,它基于字符出现频率构建一棵特殊的二叉树——Huffman树,以此来为每个字符分配唯一的二进制编码。在信息传输或存储时,使用这种编码可以显著减少数据量,因为频繁出现的字符...
Huffman编码是一种高效的数据压缩算法,它基于一种称为Huffman树(或Huffman编码树)的数据结构。在MATLAB环境中实现Huffman编码树,可以让我们更深入地理解该算法的工作原理,并能应用于实际的文件压缩。 首先,...
本实验报告中,"【实验三】Huffman树及Huffman编码的算法实现"可能包含了详细的代码实现,展示了如何使用编程语言(如C++、Java或Python)来实现上述步骤。实验可能会包括测试不同频率分布的字符集,以及对比不同...
哈夫曼树(Huffman Tree),也称为最优二叉树,是数据压缩中常用的一种数据结构。它是一种带权路径长度最短的二叉树,由哈夫曼在1952年提出,用于解决“最小带权路径长度”问题。在哈夫曼树中,频率较高的字符对应的...
哈夫曼树(Huffman Tree),也称为最优二叉树,是数据压缩中的一种关键数据结构,由哈夫曼在1952年提出。它是一种带权路径长度最短的二叉树,用于实现哈夫曼编码,这是一种高效的无损数据压缩方法。在哈夫曼编码中,...
哈夫曼树(Huffman Tree),也称为最优二叉树,是数据压缩中的一种关键算法。在C语言中实现哈夫曼树,主要是为了构建一个能够高效存储和处理字符频率的结构,以便进行数据编码。下面我们将深入探讨哈夫曼树的原理、...
Huffman编码,又称霍夫曼编码,是一种无损数据压缩算法,利用了字符出现频率的不同来构造一棵特殊的二叉树——Huffman树,以此实现高效的编码。本文将详细探讨一个用Java编写的Huffman树图形化界面小程序,以便让...
在文件压缩过程中,我们首先统计文件中每个字符的频率,然后构造Huffman树,将字符替换为对应的Huffman编码,从而实现压缩。 在C语言中实现Huffman编码压缩,需要以下几个步骤: 1. **字符频率统计**:读取文件内容...