哈夫曼编/译码器
一、需求分析
1. 问题阐述
利用哈夫曼编码进行通信可以大大提高信道利用率,缩短信息传输时间,降低传输成本。但是,这要求在发送端通过一个编码系统对待传数据预先编码,在接收端将传来的数据进行译码(复原)。对于双工信道(即可以双向传输信息的信道),每端都需要一个完整的编/译码系统。试为这样的信息收发站写一个哈夫曼码的编/译码系统。
2. 基本要求
一个完整的系统应具有以下功能:
(1)I:初始化(initialization)。从终端读入字符集大小n,以及n个字符和n个权值,建立哈夫曼树,并将它存于文件hfmTree中。
(2)E:编码(Encoding)。利用已建好的哈夫曼树(如不在内容,则从文件hfmTree中读入),对文件ToBeTran中的正文进行编码,然后将结果存入文件CodeFile中。
(3)D:译码(Decoding)。利用已建好的哈夫曼树将文件CodeFile中的代码进行译码,结果存入文件TextFile中。
(4)P:印代码文件(Print)。将文件CodeFile以紧凑格式显示在终端上,每行50个代码。同时将此字符形式的编码文件写入文件CodePrint中。
(5)T:印哈夫曼树(Tree printing)。将已在内存中的哈夫曼树以直观的方式(树或凹入表形式)显示在终端上,同时将此字符形式的哈夫曼树写入文件TreePrint中。
二、概要设计
- 数据存储:
a) 结构体hfmNode :存储哈夫曼树中的结点数据:
b) 二维动态字符数组HuffmanCode:存储所有字符的哈夫曼编码:
c) 整型变量n:存储字符集大小,即字符总数
d) 动态整形数组w:存储所有字符的权重
e) 动态字符数组ch:存储所有字符 - 具体功能:
a) Menu()函数:以菜单形式打印用户界面
b) Select()函数:查找哈夫曼树中权重之和最小的两个结点
c) HuffmanCoding()函数:建立哈夫曼树,并求哈夫曼编码
d) Init()函数:初始化。从终端读入字符集大小n,以及n个字符和n个权值,建立哈夫曼树,并将它存于文件hfmTree中
e) Encoding()函数:编码。利用已建好的哈夫曼树(如不在内容,则从文件hfmTree中读入),对文件ToBeTran中的正文进行编码,然后将结果存入文件CodeFile中
f) Decoding()函数:解码。利用已建好的哈夫曼树将文件CodeFile中的代码进行译码,结果存入文件TextFile中。
g) Printing()函数:打印代码文件。将文件CodeFile以紧凑格式显示在终端上,每行50个代码。同时将此字符形式的编码文件写入文件CodePrint中
h) TreePrinting()函数:将已在内存中的哈夫曼树以直观的方式(树或凹入表形式)显示在终端上,同时将此字符形式的哈夫曼树写入文件TreePrint中。
三、详细设计
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct hfmNode
{
char ch; // 字符
int weight; // 权重
int parent, lchild, rchild; // 指向双亲、孩子结点的指针
} HTNode, *HuffmanTree;
typedef char **HuffmanCode; // 动态分配数组存储哈夫曼编码表
void Menu(); // 菜单
void Select(HuffmanTree HT, int end, int *s1, int *s2); // 查找哈夫曼树中权重和最小的两个结点
void HuffmanCoding(HuffmanTree *HT, HuffmanCode *HC, int n, int *w, char *ch); // 建立哈夫曼树
void Init(HuffmanTree *HT, HuffmanCode *HC, int *n, int *w, char *ch); // 初始化 // 初始化
void Encoding(HuffmanTree *HT, HuffmanCode *HC, int *n, int *w, char *ch); // 编码 // 编码
void Decoding(HuffmanTree *HT, HuffmanCode *HC, int *n, int *w, char *ch); // 译码 // 译码
void Printing(); // 打印代码文件
void TreePrinting(HuffmanTree HT, int root, int type, int level); // 打印哈夫曼树 // 释放动态分配空间
int main(void)
{
int n = 0; // 字符集大小
int *w = NULL; // 存储字符权重的数组
char *ch = NULL; // 存储字符的数组
char operation; // 操作码
HuffmanTree HT; // 哈夫曼树
HuffmanCode HC; // 存储哈夫曼编码的数组
while (1)
{
Menu();
printf("Please input the operation: ");
scanf("%c", &operation);
getchar();
switch (operation)
{
case 'i':
case 'I':
Init(&HT, &HC, &n, w, ch);
break;
case 'e':
case 'E':
Encoding(&HT, &HC, &n, w, ch);
break;
case 'd':
case 'D':
Decoding(&HT, &HC, &n, w, ch);
break;
case 'p':
case 'P':
Printing();
break;
case 't':
case 'T':
TreePrinting(HT, 2 * n - 1, 0, 0);
break;
case 'q':
case 'Q':
exit(0);
break;
default:
break;
}
}
return 0;
}
// 菜单
void Menu()
{
printf("\n-------------------------------\n");
printf("# #\n");
printf("# I: Initialization #\n");
printf("# E: Encoding #\n");
printf("# D: Decoding #\n");
printf("# P: Printing #\n");
printf("# T: Tree Printing #\n")