哈夫曼编码与解码
一、设计思想
首先规定构建哈夫曼树,再去进行哈夫曼的译码,接着设计函数进行字符
串的编码过程,最后进行哈夫曼编码的译码。
定义一个结构体,用于存放构建哈夫曼树所需要的所有变量,开辟一块地
址空间,用于存放数组,数组中每个元素为之前定义的结构体。输入 n 个字符
及其权值。
构建哈夫曼树:在上述存储结构上实现的哈夫曼算法可大致描述为:
1、初始化 。将 ht[0..m-1]中 2n-1 个结点里的三个指针均置为空,权值
置为 0。
2、输入 。 读入 n 个叶子的权值存于向量的前 n 个分量中。它们是初始森
林中 n 个孤立的根结点上的权值。
3、合并 。对森林中的树共进行 n-1 次合并,所产生的新结点依次放入向量
ht 的第 i 个分量中。每次合并分两步:
①在当前森林 ht[0..i-1]的所有结点中,选取权最小和次小的两个根结点[s1]
和 [s2]作为合并对象,这里 0≤s1,s2≤i-1。
② 将根为 ht[s1]和 ht[s2]的两棵树作为左右子树合并为一棵新的树,新树的
根是新结点 ht[i]。具体操作:
将 ht[s1]和 ht[s2]的 parent 置为 i,
将 ht[i]的 lchild 和 rchild 分别置为 s1 和 s2
新结点 ht[i]的权值置为 ht[s1]和 ht[s2]的权值之和。
哈夫曼的编码:约定左子为 0,右子为 1,则可以从根结点到叶子结点的路
径上的字符组成的字符串作为该叶子结点的编码。
当用户输入字母时。就在已经找好编码的编码结构体中去查找该字母。查
到该字母就打印所存的哈夫曼编码。接着就是完成用户输入 0、1 代码时把代码
转成字母的功能。这是从树的头结点向下查找,如果当前用户输入的 0、1 串中
是 0 则就走向该结点的左子。如果是 1 这就走向该结点的右结点,重复上面步
骤。直到发现该结点属于输入了字母的结构体则打印该结构体的字母。重复上
面步骤。直到找完用户输入 0、1 串为止。则就完成了程序所有的译码过程。
二、算法流程图
(1)建立哈夫曼树的算法:
定义各结点类型其中应包含两类数据一是权重域 weight;一是应该包括指
向左右孩子和指向双亲的指针这里分别用 lchild、rchild 和 parent 来表示,因此
可用静态三叉链表来实现。在实际构造中由于是叶子结点来构造新的根结点其
构造过程中仅与叶子结点的权重有关而与其数据域无关,所以构造过程中不用
考虑其数值域,并且在链表中从叶子开始存放,然后不断的将两个最小权值的
子树合并为一个权值为其和的较大的子树,逐步生成各自内部结点直到树根。
图 1 构建哈夫曼树图
(2)编码的算法
将建立的哈夫曼树从每个叶子结点开始沿着双亲回到根结点,每走一步进
行编码得到的一个编码值,由于每个叶子结点的哈夫曼编码是从根结点到相应
的叶子的路径的各个分支的代码组成的 0 和 1 序列,所以先得到了低位编码后
得到高位编码因此可用一维数组从后向前来存放各位编码值,并用 start 来记
- 1 -
开始
输入字符
和权值
对结构体进行
初始化,
录编码的起始位置。
哈夫曼编码与解码
开始
i=0
start=n
i 结点的父结点
Y
根结点
N
子结点为左子
Y
编码为 0
N
编码为 1
start=start-1
把父结点作为当前结点
i
哈夫曼编码与解码
开始
i=0
输入字符以回车结束
C=0
c<=n
Sting[i]=ht[c].dat
j=dc[c].start
N
j<=n
C++
Y
j++
输出代码
结束
图 3 哈夫曼编码
四、哈夫曼译码
当我们输入哈夫曼 01 代码时进行译码过程,输出字符串。
- 3 -
哈夫曼编码与解码
三、源代码
图 4 哈夫曼译码流程图
//数组头文件
//宏定义
//定义哈夫曼编码的结构数组
//定义权值
#include
#include
#include
#define MAX 999
typedef struct{
char data;
int weight;
int parent;
int lchild;
int rchild;
}huffmannode;
typedef struct{
char bits[50];
int start;
}huffmancode ;
void main()
{
//定义保存哈夫曼结构体
//定义储存权值的空间
//定义数组存储空间
huffmannode ht[100];
huffmancode cd[100];
char string[100];
char hcd[100];
int i,j,x,y,s1,s2,m1,m2,n,c,f,k;
- 4 -
哈夫曼编码与解码
//输入字符的个数
printf("please input the n=");
scanf("%d",&n);
printf("\n===============================\n");
for(i=0;i
哈夫曼编码与解码
//记录父结点
y=ht[x].parent;
while (y!=-1)
{
if (ht[y].lchild==x)
cd[i].bits[cd[i].start]='0';
//给字符赋 0 值
else
cd[i].bits[cd[i].start]='1';
//给字符赋 1 值
cd[i].start--;
x=y;
y=ht[y].parent;
}
}
printf("\nout the huffmancode:\n");
for (i=0;i
哈夫曼编码与解码
if(f
哈夫曼编码与解码
图 6 叶子结点编码图
第三步,得到 huffmancode 后我们输入字符进行哈夫曼编码,如图 4。
第五步,的到哈夫曼编码后输入哈夫曼编码进行译码过程。
图 7 字符的编码图
图 8 哈夫曼编码的译码图
五、遇到的问题及解决
- 8 -