北邮数据结构实验3哈夫曼编码
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
数据结构实验报告
实验名称:实验3——哈夫曼编码
学生姓名:
班级:
班内序号:
学号:
日期:2013年11月24日
1.实验要求
利用二叉树结构实现赫夫曼编/解码器。
基本要求:
1、初始化(Init):能够对输入的任意长度的字符串s进行统计,统计每个
字符的频度,并建立赫夫曼树
2、建立编码表(CreateTable):利用已经建好的赫夫曼树进行编码,并将每
个字符的编码输出。
3、编码(Encoding):根据编码表对输入的字符串进行编码,并将编码后的
字符串输出。
4、译码(Decoding):利用已经建好的赫夫曼树对编码后的字符串进行译
码,并输出译码结果。
5、打印(Print):以直观的方式打印赫夫曼树(选作)
6、计算输入的字符串编码前和编码后的长度,并进行分析,讨论赫夫曼
编码的压缩效果。
2. 程序分析
2.1存储结构:
struct HNode
{
char c;//存字符内容
int weight;
int lchild, rchild, parent;
};
struct HCode
{
char data;
char code[100];
}; //字符及其编码结构
class Huffman
{
private:
HNode* huffTree; //Huffman树
HCode* HCodeTable; //Huffman编码表
public:
Huffman(void);
void CreateHTree(int a[], int n); //创建huffman树
void CreateCodeTable(char b[], int n); //创建编码表
void Encode(char *s, string *d); //编码
void Decode(char *s, char *d); //解码
void differ(char *,int n);
char str2[100];//数组中不同的字符组成的串
int dif;//str2[]的大小
~Huffman(void);
};
结点结构为如下所示:
三叉树的节点结构:
struct HNode//哈夫曼树结点的结构体
{ int weight;//结点权值
int parent;//双亲指针
int lchild;//左孩子指针
int rchild;//右孩子指针
char data;//字符
};
示意图为:
int weight int parent int lchild int rchild Char c 编码表节点结构:
struct HCode//编码表结构体
{
char data;//字符
char code[100];//编码内容
};
示意图为:
基本结构体记录字符和出现次数:
struct node
{
int num;
char data;
};
示意图为:
2.关键算法分析
(1).初始化:
伪代码:
1.输入需要编译的文本内容
2.将输入的内容保存到数组str1中
3.统计出现的字符数目,并且保存到变量count中
4.统计出现的不同的字符,存到str2中,将str2的大小存到dif中
时间复杂度O(n!)
(2).创建哈夫曼树
算法伪代码:
1.创建一个长度为2*n-1的三叉链表
2.将存储字符及其权值的链表中的字符逐个写入三叉链表的前n个结点的data域,并将对
应结点的孩子域和双亲域赋为空
3.从三叉链表的第n个结点开始,
3.1从存储字符及其权值的链表中取出两个权值最小的结点x,y,记录其
下标x,y。
3.2将下标为x和y的哈夫曼树的结点的双亲设置为第i个结点
3.3将下标为x的结点设置为i结点的左孩子,将下标为y的结点设置为
i结点的右孩子,i结点的权值为x结点的权值加上y结点的权值,i
结点的双亲设置为空
4.根据哈夫曼树创建编码表
时间复杂度O(n)
(3).创建编码表
算法伪代码:
1.初始化编码表
2.初始化一个指针,从链表的头结点开始,遍历整个链表
2.1 将链表中指针当前所指的结点包含的字符写入编码表中
2.2 得到该结点对应的哈夫曼树的叶子结点及其双亲
2.3 如果哈夫曼树只有一个叶子结点,将其字符对应编码设置为0
2.4 如果不止一个叶子结点,从当前叶子结点开始判断
2.4.1 如果当前叶子结点是其双亲的左孩子,则其对应的编码为0,否则为1
2.4.2 child指针指向叶子结点的双亲,parent指针指向child指针的双亲,重复2.4.1的操作
2.5 将已完成的编码倒序
2.6 取得链表中的下一个字符
3.输出编码表
时间复杂度O(n)
(4)选择两个最小权值的函数
算法伪代码:
1.从下标为i=0的开始遍历。前两次将x,y赋值为序号最小的两个结点的地址序
号。
2.开始进行比较:进行如下分类
对于任何不存在父节点的结点:
若x权值<=y权值
(1)且i权值>=y权值,则无疑i权值最大,为输出x、y为权值较小的两个故而x,y值不便;
(2)其余情况皆为x、i的权值是较小的两个,令y赋值为i,则保证x、y权值是最小的两个。
若y权值<=x权值
(1)且i权值>=x权值,则i权值是最大,x、y不变。
(2)其余情况皆为i、y权值最小,令x赋值为i,保证x、y序号结点的权值最小
3.完成如上循环,直至i=k则推出循环,第k个结点在树的位置已经确定
时间复杂度O(n)
(5). 将字符串倒序的函数(void HuffmanTree::Reverse(char *pch))
算法伪代码:
1.得到字符串的长度
2.初始化两个记录下标的变量,一个为字符串开头字符所在的下标i,另一个为字符串结尾字符所在的下标j
3.将下标为i和j的字符交换
4.i++,j - -
时间复杂度O(n)
(6).编码函数
算法伪代码:
1. 从开头的字符开始,逐一对a中的字符进行编码
2. 在编码表中查找与当前字符对应的字符
3.如果找到了与当前字符对应的编码表中的字符,将其编码追加到解码串的末
尾。