赫夫曼树
赫夫曼编码是首个试用的编码方案。属于无损压缩的编码方案。在数据通信中,赫夫曼编码可以根据字符出现频率,构造出一种不等长的二进制,使编码后的电文长度最短,且不产生二义性。
树的带权路径长度WPL
weighteed path length是树中所有节点的带权路径长度之和。WPL 值越小,说明构造出来的二叉树性能越优。赫夫曼树为最优 WPL 二叉树
赫夫曼编码
1. 定长编码:一种二进制信息的信道编码,类似ASCII编码,一次变换的输入信息位数固定不变。
2. 变长编码:单个编码的长度不一致,可以根据整体出现频率来调节。
3. 前缀码:就是没有任何码字是其他码字的前缀。一个优点就是,前缀码可以方便变长编码的组合,不会引起歧义。赫夫曼编码就是最优的前缀码二叉树。
程序思路:首先根据每个字符出现的次数(权值),创建一个具有优先级的队列。(出现次数越少排在越前,次数越多排在越后)。然后根据赫夫曼树的构造方法,选择两个权值最小的结点的权值和构造一个新结点S,将S按照大小插入队列中。至队列只剩一个元素时(该元素为根结点),赫夫曼树构造完毕。根据遍历赫夫曼树的结果,左子树用0表示,右子树用1表示,为每个叶子结点生成一个表格,表格中的字符串就是存放的编码。遍历至没有左子树和右子树的时候,就加*\0*。最后设计编码过程和解码过程。编码时遍历需要压缩的文件,找到对应的字符,从赫夫曼表中打印出编码。解码时根据赫夫曼编码,遇到0向左子树走,遇到1向右子树走,最后把字符显示出来。
代码片段
htTree * buildTree(char *inputString)
{
//整型指针,记录每个ASCII出现频率
int * probability = int(*)malloc(sizeof(int)*256);
//初始化
for(int i=0;i<256;i++)
{
probability[i]=0;
}
//统计待编码的字符串各个字符出现次数,传入的字符转换为ASCII值,在probability数组中对应位置自加
for(int j=0;inputString[j]!='\0';j++)
{
probability[(unsigned char) inputString[j]]++;
}
//pQueue为队列的头指针
pQueue * huffmanQueue;
//为队列头指针分配空间
initPQueue(&huffmanQueue);
//初始化队列 填充队列
for(int k=0;k<256;k++)
{
if(probability[k]!=0)
{
//分配一个树的结点
htNode *aux = (htNode *)malloc(sizeof(htNode));
aux->left=NULL;
aux->right=NULL;
aux->symbol = (char) k;
addPQueue(&huffmanQueue,aux,probability[k]);
}
}
}
//addPQueue
void addPQueue(pQueue **queue,TYPE val,unsigned int priority)
{
if((*queue)->size == MAX_SZ)
{
printf("\nQueue is full.\n");
return;
}
pQueueNode *aux = (pQueueNode *)malloc(sizeof(pQueueNode));
aux->priority = priority;
aux->val= val;
//如果是空的队列 则不用比较 直接插入
if((*queue)->size == 0||(*queue)->first == NULL)
{
aux->next=NULL;
(*queue)->first=aux;
(*queue)->size=1;
return;
}
//如果不是空队列 则比较后再插入 情况一权值小于第一个结点
else
{
if(priority<=(*queue)->first->priority)
{
aux->next=(*queue)->first;
(*queue)->first=aux;
(*queue)->size++;
return;
}
//情况二 使用迭代比较
else
{
pQueueNode *iterator=(*queue)->first;
while(iterator->next!=NULL)
{
if(priority<=iterator->next->priority)
{
aux->next=iterator-next;
}
}
}
}
}
//初始化队列
#include "queue.h"
#include <stdio.h>
#include <stdlib.h>
void initPQueue(pQueue **queue)
{
(*queue)=(pQueue *)malloc(sizeof(pQueue));
(*queue)->first=NULL:
(*queue)->size=0;
return;
}