当前位置:文档之家› 北邮数据结构实验3哈夫曼编码

北邮数据结构实验3哈夫曼编码

1 数据结构实验报告 实验名称: 实验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 2

{ 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

编码表节点结构: 3

struct HCode//编码表结构体 { char data;//字符 char code[100];//编码内容 }; 示意图为: char data char code[100]

基本结构体记录字符和出现次数: struct node { int num; char data; }; 示意图为: 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 将链表中指针当前所指的结点包含的字符写入编码表中 4

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.如果找到了与当前字符对应的编码表中的字符,将其编码追加到解码串的末尾。 5

4. 重复以上步骤,直到所有待编码串中的字符都编码完毕 5. 输出编码后的字符串 时间复杂度O(n)

(7).解码函数(void Huffman::Decode()) 算法伪代码: 1. 得到指向哈夫曼树的根结点的指针和指向待解码串中的第1个字符的指针 2. 逐个读取待解码串中的字符,若为0,则指向哈夫曼树当前结点的指针指向当前结点的左孩子,若为1,则指向当前结点的右孩子 3. 指向待解码串的指针指向解码串中的下一个字符,直到指向哈夫曼树结点的指针的孩子结点为空 4. 如果哈夫曼树只有一个叶子结点,直接将待解码串中的编码转换为对应的字符 5. 如果指向哈夫曼树结点的指针的孩子结点已经为空,则将叶子结点下标对应的字符追加到解码串中。 6. 输出解码串 时间复杂度O(n)

3. 程序运行结果 1.主函数流程图 6 7 main.cpp #include"huffman.h" void main() { Huffman H; int i; char str1[100]={'\0'}; string d; int count=0;

do { cout<<"请选择功能(输入编译字符串2输出编码表3输出字符串编码及压缩比4解码5退出)"<8

int n; cin>>n; char ch='a'; cin.get(ch); switch(n) { case 1: { cout<<"请输入"

break; case 5: break; default: cout<<"请输入正确序号"

相关主题