北邮数据结构实验—Huffman编码解码器.docx
数据结构实验实验报告Huffman赫夫曼编码及应用
实验报告课程名称:数据结构实验名称:赫夫曼编码及应用院(系):计算机与通信工程学院专业班级:计算机科学与技术姓名:学号:指导教师:2020 年 5 月12 日一、实验目的掌握赫夫曼树和赫夫曼编码的基本思想和算法的程序实现。
二、实验内容及要求1、任务描述a.提取原始文件中的数据(包括中文、英文或其他字符),根据数据出现的频率为权重,b.构建Huffman编码表;c.根据Huffman编码表对原始文件进行加密,得到加密文件并保存到硬盘上;d.将加密文件进行解密,得到解码文件并保存点硬盘上;e.比对原始文件和解码文件的一致性,得出是否一致的结论。
2、主要数据类型与变量a.对Huffman树采用双亲孩子表示法,便于在加密与解密时的操作。
typedef struct Huffman* HuffmanTree;struct Huffman{unsigned int weight; //权值unsigned int p, l, r;//双亲,左右孩子};b.对文本中出现的所有字符用链表进行存储。
typedef struct statistics* List;struct statistics {char str; //存储此字符int Frequency; //出现的频率(次数)string FinalNum; //Huffman编码struct statistics* Next;};3、算法或程序模块对读取到的文本进行逐字符遍历,统计每个字符出现的次数,并记录在创建的链表中。
借助Huffman树结构,生成结构数组,先存储在文本中出现的所有字符以及它们出现的频率(即权值),当作树的叶子节点。
再根据叶子节点生成它们的双亲节点,同样存入Huffman树中。
在完成对Huffman树的创建与存储之后,根据树节点的双亲节点域以及孩子节点域,生成每个字符的Huffman编码,并存入该字符所在链表节点的FinalNum域。
北邮信通院数据结构实验报告三哈夫曼编码器.pptx
-1
2.2 关键算法分析 (1)计算出现字符的权值
利用 ASCII 码统计出现字符的次数,再将未出现的字符进行筛选,将出现的字符及頻 数存储在数组 a[]中。
void Huffman::Init() {
int nNum[256]= {0}; //记录每一个字符出现的次数 int ch = cin.get();
第2页
北京邮电大学信息与通信工程学 院
2
-1
-1
-1
5
-1
-1
-1
6
-1
-1
-1
7
-1
-1
-1
9
-1
-1
-1
weight lchild rchild parent
2
-1
-1
5
5
-1
-1
5
6
-1
-1
6
7
-1
-1
6
9
-1
-1
7
7
0
1
7
第3页
北京邮电大学信息与通信工程学 院
13
2
3
8
16
5
4
8
29
6
7
2、建立编码表(CreateTable):利用已经建好的赫夫曼树进行编码,并将每 个字符的编码输出。
3、编码(Encoding):根据编码表对输入的字符串进行编码,并将编码后的 字符串输出。
4、译码(Decoding):利用已经建好的赫夫曼树对编码后的字符串进行译 码,并输出译码结果。
5、打印(Print):以直观的方式打印赫夫曼树(选作) 6、计算输入的字符串编码前和编码后的长度,并进行分析,讨论赫夫
北邮数据结构实验—Huffman编码解码器
数据结构实验报告实验名称:____Huffman编码/解码器_____学生姓名:__________________班级:__________________班内序号:__________________学号:__________________日期:___________________1.实验要求利用二叉树结构实现哈夫曼编/解码器。
基本要求:1.初始化(Init):能够对输入的任意长度的字符串s进行统计,统计每个字符的频度,并建立哈夫曼树2.建立编码表(CreateTable):利用已经建好的哈夫曼树进行编码,并将每个字符的编码输出。
3.编码(Encoding):根据编码表对输入的字符串进行编码,并将编码后的字符串输出。
4.译码(Decoding):利用已经建好的哈夫曼树对编码后的字符串进行译码,并输出译码结果。
5.计算输入的字符串编码前和编码后的长度,并进行分析,讨论赫夫曼编码的压缩效果。
2. 程序分析存储结构静态三叉链表程序流程 (或程序结构、或类关系图等表明程序构成的内容,一般为流程图等)流程图伪代码1.输入进行编码的字符串2.遍历字符串,并为叶子节点权重赋值3.依次对各字符进行哈弗曼编码,自下往上,若是双亲节点左孩子则编码前插入‘0’,若是双亲节点右孩子则编码钱插入‘1’。
4.显示各字符的哈弗曼编码。
5.对字符串进行编码,挨个遍历字符,找到相应的编码,复制到总的编码里,最后输出字符串的编码。
6.对字符串的哈弗曼码进行译码。
自上往下,若是‘0’,则递归到左孩子,若是‘1’,则递归到右孩子,知道叶子节点,输出该叶子节点代表字符,再继续遍历。
7.分析内存占用情况。
若用ASCII编码,每个字符占1个字节,即8bit,该情况下占用内存就是(字符长度)*8。
若用哈弗曼编码,占用内存是各(字符频度)*(每个字符占用位数)之和。
关键算法分析该程序关键算法即哈弗曼编码,语句如下:void CHTree::huffmancode(){int i;if(n<=1)return;m=2*n-1;for(i=1;i<=n;i++)arent=0;ht[i].lchild=0;ht[i].rchild=0;}for(;i<=m;i++) eight=0;ht[i].parent=0;ht[i].lchild=0;ht[i].rchild=0;}for(i=n+1;i<=m;++i)arent设为-1s2=select(i-1);ht[s1].parent=i;ht[s2].parent=i;ht[i].lchild=s1;ht[i].rchild=s2;ht[i].weight=ht[s1].weight+ht[s2].weight;}int c,f;for(i=1;i<=n;++i) {for(c=i,f=ht[i].parent;f!=0;c=f,f=ht[f].parent)child==c){str[i].insert(0,"0",0,1);} nsert(0,"1",0,1);} 序运行结果分析首先,要求用户输入进行编码的字符串,遍历字符串,并为叶子节点权重赋值。
北邮数据结构实验报告
北邮数据结构实验报告北京邮电大学信息与通信工程学院2009级数据结构实验报告实验名称:实验三哈夫曼编/解码器的实现学生姓名:陈聪捷日期:2010年11月28日1.实验要求一、实验目的:了解哈夫曼树的思想和相关概念;二、实验内容:利用二叉树结构实现哈夫曼编/解码器1.初始化:能够对输入的任意长度的字符串s进行统计,统计每个字符的频度,并建立哈夫曼树。
2.建立编码表:利用已经建好的哈夫曼树进行编码,并将每个字符的编码输出。
3.编码:根据编码表对输入的字符串进行编码,并将编码后的字符串输出。
4.译码:利用已经建好的哈夫曼树对编码后的字符串进行译码,并输出译码结果。
5.打印:以直观的方式打印哈夫曼树。
6.计算输入的字符串编码前和编码后的长度,并进行分析,讨论哈夫曼编码的压缩效果。
7.用户界面可以设计成“菜单”方式,能进行交互,根据输入的字符串中每个字符出现的次数统计频度,对没有出现的字符一律不用编码。
2.程序分析2.1存储结构二叉树templateclassBiTree{public:BiTree();//构造函数,其前序序列由键盘输入~BiTree(void);//析构函数BiNode*Getroot();//获得指向根结点的指针protected:BiNode*root;//指向根结点的头指针};//声明类BiTree及定义结构BiNodeData:二叉树是由一个根结点和两棵互不相交的左右子树构成data:HCode*HCodeTable;//编码表inttSize;//编码表中的总字符数二叉树的节点结构templatestructBiNode//二叉树的结点结构{Tdata;//记录数据Tlchild;//左孩子Trchild;//右孩子Tparent;//双亲};编码表的节点结构structHCode{chardata;//编码表中的字符charcode[100];//该字符对应的编码};待编码字符串由键盘输入,输入时用链表存储,链表节点为structNode{charcharacter;//输入的字符unsignedintcount;//该字符的权值boolused;//建立树的时候该字符是否使用过Node*next;//保存下一个节点的地址};示意图:2.2关键算法分析1.初始化函数(voidHuffmanTree::Init(stringInput))算法伪代码:1.初始化链表的头结点2.获得输入字符串的第一个字符,并将其插入到链表尾部,n=1(n 记录的是链表中字符的个数)3.从字符串第2个字符开始,逐个取出字符串中的字符3.1将当前取出的字符与链表中已经存在的字符逐个比较,如果当前取出的字符与链表中已经存在的某个字符相同,则链表中该字符的权值加1。
Huffman编解码实验报告
Huffman编解码实验报告⽂本⽂件的⼆进制预统计Huffman编解码⼀、实验⽬的(1) 熟悉Huffman编解码算法;(2) 理解Huffman编码的最佳性。
⼆、实验内容1、编程思想霍夫曼(Huffman)编码是1952年为⽂本⽂件⽽建⽴,是⼀种统计编码。
属于⽆损压缩编码。
霍夫曼编码的码长是变化的,对于出现频率⾼的信息,编码的长度较短;⽽对于出现频率低的信息,编码长度较长。
这样,处理全部信息的总码长⼀定⼩于实际信息的符号长度。
计算机编程实现时,⾸先统计带编码的⽂本⽂件中各个字符出现的概率,然后将概率作为节点的权值构建huffman树。
编码时从叶⼦节点出发,如果这个节点在左⼦树上,则编码0,否则编码1,直到根节点为⽌,所得到的01序列即为该叶⼦节点的编码。
所有叶⼦节点的编码构成⼀个码本。
有两种译码⽅法:(1)按位读⼊码字,从已建好的Huffman树的根节点开始,若码字为“0”,则跳到左⼦树,若为“1”则跳到右⼦树,直到叶⼦结点为⽌,输出叶⼦接点所表⽰的符号。
(2)由于Huffman编码是唯⼀码,还有另⼀种译码⽅法,每读⼊⼀位编码就去码本中去匹配相应的码字,若匹配不成功,则继续读⼊下⼀个编码,直到匹配成功为⽌。
显然前⼀种⽅法⽐较简便,本程序采⽤便是该⽅法。
2、程序流程图3、编程实现本实验采⽤⽤C 语⾔程序语⾔,VC++ 6.0编程环境。
(1)数据结构构造存放符号及其权值的存储结构如下 typedef struct {unsigned char symbol; //符号的ASCII 码值 int sweight; //权值}syml_weit;syml_weit *sw;构造huffman 树存储结构如下:typedef struct {int weit; //权值int lchd; //左孩⼦地址 int rchd; //右孩⼦地址 int part; //双亲地址 }hufmtree;hufmtree *htree;(2)函数本程序共包含5个函数:⼀个主函数:void main(), 4个⼦函数:void CountWeight(unsigned char *DataBuf,int FileLen); void BuildTree();void HufmCode(unsigned char *DataBuf,int FileLen); void HufmDCode(unsigned char *CDataBuf,int CDataLen); 其功能分别CountWeight----计算⽂本⽂件中各符号的权值; BuildTree-------构建Huffman 树,形成码本; HufmCode---------对⽂本⽂件进⾏编码; HufmDCode-------进⾏译码。
北邮信通院数据结构实验报告三哈夫曼编码器.docx
北京邮电大学电信工程学院数据结构实验报告实验名称:实验三树——哈夫曼编/解码器学生姓名:班级:班内序号:学号:日期: 2014 年 12 月 11 日1.实验要求利用二叉树结构实现赫夫曼编/解码器。
基本要求:1、初始化 (Init) :能够对输入的任意长度的字符串s 进行统计,统计每个字符的频度,并建立赫夫曼树2、建立编码表 (CreateTable):利用已经建好的赫夫曼树进行编码,并将每个字符的编码输出。
3、编码 (Encoding):根据编码表对输入的字符串进行编码,并将编码后的字符串输出。
4、译码 (Decoding):利用已经建好的赫夫曼树对编码后的字符串进行译码,并输出译码结果。
5、打印 (Print):以直观的方式打印赫夫曼树(选作)6、计算输入的字符串编码前和编码后的长度,并进行分析,讨论赫夫曼编码的压缩效果。
测试数据:I love data Structure, I love Computer。
I will try my best to study data Structure.提示:1、用户界面可以设计为“菜单”方式:能够进行交互。
2、根据输入的字符串中每个字符出现的次数统计频度,对没有出现的字符一律不用编码。
-2.程序分析2.1 存储结构Huffman 树给定一组具有确定权值的叶子结点,可以构造出不同的二叉树,其中带权路径长度最小的二叉树称为Huffman树,也叫做最优二叉树。
weight lchild rchild parent2-1-1-15-1-1-16-1-1-17-1-1-19-1-1-1weight lchild rchild parent 2-1-15 5-1-15 6-1-16 7-1-16 9-1-17 701713238165482967-12.2 关键算法分析(1)计算出现字符的权值利用 ASCII 码统计出现字符的次数,再将未出现的字符进行筛选,将出现的字符及頻数存储在数组a[] 中。
huffman编码及截断huffman编码、解码实习报告(pdf版)
下面先介绍下 tree,树在 matlab 中的构造,在 matlab 中用 tree(MN,s1,s2,s3……) 这个系统函数来构造二叉树。声明一个 tree(6,x)结构的树型结点,一个结点包括有 6 个变 量存储单元。 其中 tree(1,x)记录该结点的编号; tree(2,x)记录该结点的概率值; tree(3,x) 记录该结点的父结点编号; tree(4,x)记录该结点是左结点还是右结点(其中左结点为 “0” , 右结点为“1”);tree(5,x)记录该结点是否为根结点标志(该结点为根结点记为“1”,否 则决为“0”)。tree(6,x)记录该结点的字符,x 的个数为 pro 中字符的个数,其余值人为 赋零。 由截断 Huffman 编码要求(2),我们需要对字符进行一个定长码的顺序编码,所以需 要编写函数 SequenceTree=Sequence(pro)来得到一棵顺序编码的二叉树,其中 pro 为截断 Huffman 编码要求中剩余的字符组成的新 pro 概率分布矩阵 (按概率值先大后小的顺序排序)
Entropy=0; for j=1:n1; Entropy=Entropy-pro(1,j)*log2(pro(1,j)); End
计算平均码长前需要先得到每个字符的码长, 因此需要先编写得到每个字符码长的数组 (代码略,详见第四部分:编程代码),接着由下得到平均码长
AverageCodeLength=sum(CodeLength.*pro(1,:)) 再根据冗余度的计算公式可得 Redundancy= AverageCodeLength/ Entropy-1;
北邮-数据结构-哈夫曼树报告Word版
数据结构实验报告实验名称:哈夫曼树学生姓名:袁普班级:2013211125班班内序号:14号学号:2013210681日期:2014年12月实验目的和内容利用二叉树结构实现哈夫曼编/解码器。
基本要求:1、初始化(Init):能够对输入的任意长度的字符串 s进行统计,统计每个字符的频度,并建立哈夫曼树2、建立编码表(CreateTable):利用已经建好的哈夫曼树进行编码,并将每个字符的编码输出。
3、编码(Encoding):根据编码表对输入的字符串进行编码,并将编码后的字符串输出。
4、译码(Decoding):利用已经建好的哈夫曼树对编码后的字符串进行译码,并输出译码结果。
5、打印(Print):以直观的方式打印哈夫曼树(选作)6、计算输入的字符串编码前和编码后的长度,并进行分析,讨论赫夫曼编码的压缩效果。
7、可采用二进制编码方式(选作)测试数据:I love data Structure, I love Computer。
I will try my best to studydata Structure.提示:1、用户界面可以设计为“菜单”方式:能够进行交互。
2、根据输入的字符串中每个字符出现的次数统计频度,对没有出现的字符一律不用编码2. 程序分析2.1 存储结构用struct结构类型来实现存储树的结点类型struct HNode{int weight; //权值int parent; //父节点int lchild; //左孩子int rchild; //右孩子};struct HCode //实现编码的结构类型{char data; //被编码的字符char code[100]; //字符对应的哈夫曼编码};2.2 程序流程2.3 关键算法分析算法1:void Huffman::Count()[1] 算法功能:对出现字符的和出现字符的统计,构建权值结点,初始化编码表[2] 算法基本思想:对输入字符一个一个的统计,并统计出现次数,构建权值数组,[3] 算法空间、时间复杂度分析:空间复杂度O(1),要遍历一遍字符串,时间复杂度O(n)[4] 代码逻辑:leaf=0; //初始化叶子节点个数int i,j=0;int s[128]={0}; 用于存储出现的字符for(i=0;str[i]!='\0';i++) 遍历输入的字符串s[(int)str[i]]++; 统计每个字符出现次数for(i=0;i<128;i++)if(s[i]!=0){data[j]=(char)i; 给编码表的字符赋值weight[j]=s[i]; 构建权值数组j++;}leaf=j; //叶子节点个数即字符个数for(i=0;i<leaf;i++)cout<<data[i]<<"的权值为:"<<weight[i]<<endl;算法2:void Init();[1] 算法功能:构建哈弗曼树[2] 算法基本思想:根据哈夫曼树构建要求,选取权值最小的两个结点结合,新结点加入数组,再继续选取最小的两个结点继续构建。
北邮数据结构实验哈夫曼编码解码
#include<iostream>
#include<string>
using namespace std;
const int NUM=128;
const int M=1000;
int frequency[NUM]={0}; //统计各输入字符频率
void Huffman::CteatCodeTable(char letters[],int frequency[]) //生成编码表
{
Hcodetable=new Hcode[leaf];
for(int i=0,m=0;i<128;i++)
{
if(frequency[i]!=0)
temp[i]=HTree[i].weight;
HTree[i].Lchild=Min1;
HTree[i].Rchild=Min2;
HTree[i].parent=-1;
}
delete temp;
}
///////////////////////////////////////////////////////////////////////////////////////////
void Encode(char *s,char*d); //编码函数
void Decode(char *s,char*d); //解码函数
void Reverse(char a[]); //编码倒置函数
void Huffman::Reverse(char a[])
{
int m=0;
while(a[m]!='\0')
huffman实验报告
一、问题描述1. 实验题目:huffman编解码2. 基本要求:初始化(I nitialization)。
从终端读入字符集大小n,以及n个字符和n个权值,建立Huffman 树,并将它存入hfmTree 中。
编码(E ncoding)。
利用已经建好的Huffman树(如果不在内存,则应从文件hfmTree 中读取),对文件ToBeTran中的正文进行编码,然后将结果存入文件CodeFile中。
解码(D ecoding)。
利用已经建立好的Huffman树将文件CodeFile中的代码进行解码,结果存入TextFile中。
打印代码文件(Print)。
将文件CodeFile以紧凑的格式显示在终端上,每行 50 个代码。
同时将此字符形式的编码文件写入文件CodePrint中。
打印Huffman树(T ree Printing)。
将已经在内存中的Huffman树以直观的形式(树或者凹入的形式)显示在终端上,同时将此字符形式的Huffman 树写入文件TreePrint中。
3. 测试数据:用下表给出的字符集和频度的实际统计数据建立Huffman树,并对以下报文进行编字符集大小 n,n个字符和 n个权值均从终端读入,初始化后的huffman树存储在hfmTree文件中,待编码文件为ToBeTran,编码结果以文本的方式存储在文件CodeFile中,解码文件存在TextFile中,打印的编码和赫夫曼树分别存储在CodePrint和TreePrint文件中。
用户界面可以设计为“菜单”方式:显示上述功能符号,再加上一个退出功能“Q”,表示退出(quit)。
用户键入一个选择功能符,此功能执行完毕后再显示此菜单,直至某次用户选择了Q为止。
二、需求分析1. 本程序可以根据输入字符集和频度建立huffman树并且对给定文本进行编解码,还可以直接读入建立好的huffman树再对给定文本编解码,打印编码、解码结果、表格形式及树形的huffman树。
哈夫曼编码与解码实验报告
数据结构课程设计报告题目:哈夫曼编码与解码学生姓名:侯清源学号: 1021111118班级: 102111111指导教师:张军2012年6月1日目录需求分析说明总体设计详细设计实现部分程序测试部分实验总结附图:开发环境和工程文件介绍1,需求分析说明A,通信线路中实现信息的最大传送,利用变长编码的方式,可以有效充分利用带宽,实现信息传送前的压缩。
B,在文件保存时,利用哈夫曼编码的方式,压缩文件。
可以实现硬盘存储最大的信息量。
C,实验目的:1,.学会使用哈夫曼进行对文本文件的编码与译码。
2,通过对哈夫曼的编码与译码,能够理解通信领域中的数据传输的压缩原理。
3,通过对哈夫曼的编码/译码器的研究与分析,能够彻底的理解软件设计的一般步骤和方法,灵活地运用各种数据结构进行操作,熟练地把所学地数据结构应用地软件开发当中,提高软件设计水平,增强程序设计能力。
D,实现功能压缩:实现对用户输入的字符串压缩,并在终端显示相应字符对应的频率,编码,编码长度,平均编码长度,字符个数。
并显示字符串编码后的二进制文件。
解压:实现对压缩后的二进制文件解压,还原为原来的字符串。
并显示在终端。
和用户输入的字符串比较。
2,总体设计2,1 开发环境介绍编译器:gcc 4.6.3编辑器:vim 7.0附插件:ctags、taglist、autocomplpop。
打开syntax enable、syntax on、set number。
操作系统:Ubuntu 12.04 LTS硬件环境:Processor:Intel(R) Core™ i5-2430 CPU @2.40GHzV endor:AcerTravelMate 4750G Business LaptopMemory:4G2.2系统框架系统结构流程算法思想描述(文字和图)1,首先,根据用户输入的字符串得到字符频率。
根据频率得到频率数据,对该频率数组由栈顶到栈低由小到大排列,同时将从小到大顺序存入优先队列2,构造哈弗曼树,过程如下:从栈中取出两个最小频率。
哈夫曼编码解码实验报告
哈夫曼编码解码实验1.实验要求掌握二叉树的相关概念掌握构造哈夫曼树,进行哈夫曼编码。
对编码内容通过哈夫曼树进行解码。
2.实验内容通过二叉树构造哈夫曼树,并用哈夫曼树对读取的txt文件进行哈夫曼编码。
编码完成后通过哈夫曼树进行解码。
#include<stdio.h>#include<string.h>#define MAX 100//定义哈夫曼树的存储结构typedef struct{char data;int weight;int parent;int lch;int rch;}HuffNode;//定义哈夫曼编码的存储结构typedef struct{char bit[MAX];int start;}HuffCode;HuffNode ht[2*MAX];HuffCode hcd[MAX];int Coun[127]={0};int n;char s1[200000];char text[5000];//构造哈夫曼树void HuffmanTree(){int i,j,k,left,right,min1,min2;//printf("输入叶子的节点数:");//scanf("%d",&n);printf("字符数量=%d\n",n);for(i=1;i<=2*n-1;i++){ht[i].parent=ht[i].lch=ht[i].rch=0;}j=0;for(i=1;i<=n;i++){/*getchar();printf("输入第%d个叶子节点的值:",i);scanf("%c",&ht[i].data);printf("输入该节点的权值:");scanf("%d",&ht[i].weight);*/for(;j<127;j++){if(Coun[j]!=0){ht[i].data=j;//printf("%c",ht[i].data);ht[i].weight=Coun[j];//printf("%d",ht[i].weight);break;}}j++;}printf("\n");for(i=1;i<=n;i++){printf("%c",ht[i].data);}printf("\n");for(i=n+1;i<=2*n-1;i++){//在前n个结点中选取权值最小的两个结点构成一颗二叉树min1=min2=10000;//为min1和min2设置一个比所有权值都大的值left=right=0;for(k=1;k<=i-1;k++){if(ht[k].parent==0)//若是根结点//令min1和min2为最小的两个权值,left和right 为权值最小的两个结点位置if(ht[k].weight<min1){min2=min1;right=left;min1=ht[k].weight;left=k;}else if (ht[k].weight<min2){min2=ht[k].weight;right=k;}}ht[left].parent=i;ht[right].parent=i;ht[i].weight=ht[left].weight+ht[right].weight;ht[i].lch=left;ht[i].rch =right;}}//构造哈夫曼编码void HuffmanCode(){int i,c,k,f;HuffCode cd;for(i=1;i<=n;i++){cd.start=n;c=i;f=ht[i].parent;while(f!=0){if(ht[f].lch==c)cd.bit[cd.start]='0';elsecd.bit[cd.start]='1';cd.start--;c=f;f=ht[f].parent;}hcd[i]=cd;}printf("输出哈夫曼编码:\n");for(i=1;i<=n;i++){printf("%c:",ht[i].data);for(k=hcd[i].start+1;k<=n;k++)printf("%c",hcd[i].bit[k]);printf("\n");}}//对字母进行编码void Code()//将字符与相应的哈夫曼编码进行匹配,输出编码结果{int i=0,j,k,h=0;while(text[i]!='\0'){for(j=1;j<=n;j++){if(text[i]==ht[j].data){for(k=hcd[j].start+1;k<=n;k++){s1[h]=hcd[j].bit[k];h++;}break;}}i++;}//printf("编码\n");//puts(s1);//printf("\n");}//解码void HuffmanDecode(){printf("解码\n");int len,i,f;char C;//char S[MAXCODE];//scanf("%s",S);//使用gets()直接跳过len=strlen(s1);printf("s1:%d\n",len);f=2*n-1;for(i=0;i<len;i++){if(s1[i]=='0'){f=ht[f].lch;if(ht[f].lch==0&&ht[f].rch==0){C=ht[f].data;printf("%c",C);f=2*n-1;}}else if(s1[i]=='1'){f=ht[f].rch;if(ht[f].lch==0&&ht[f].rch==0){C=ht[f].data;printf("%c",C);f=2*n-1;}}}printf("\n");}//统计字母个数及其权值void Count(){int i,j,m;n=0;i=0;//printf("请仅输入小写字母\n");//例程本省存在一个BUG,只输入一个字母不能进行编码(并未解决)//scanf("%s",s);while(text[i]!='\0')//使用ASCII码表进行统计{m=text[i];//printf("%d\n",m);Coun[m]++;i++;}for(j=0;j<127;j++){if(Coun[j]!=0)n++;}}//mark Codevoid main(){int l=0;FILE *fp;fp=fopen("text.txt","r");if(fp==NULL){printf("文件打开失败\n");while(1);}while(!feof(fp)){text[l] = fgetc(fp);l++;}printf("输入文本\n");printf("%s\n",text);fclose(fp);Count();HuffmanTree();HuffmanCode();Code();HuffmanDecode();}文本文件文本输入进行哈夫曼编码对文本进行编码输出解码结果3.实验总结通过本次实验,对二叉树的应用有了相应的了解,掌握了如何构造哈夫曼编码,如何对编码结果进行解码。
北邮数据结构实验报告三题目2-哈夫曼树
11.实验要求利用二叉树结构实现哈夫曼编/ 解码器(1). 初始化:能够对输入的任意长度的字符串s 进行统计,统计每个字符的频度,并建立哈夫曼树。
(2). 建立编码表:利用已经建好的哈夫曼树进行编码,并将每个字符的编码输出。
(3). 编码:根据编码表对输入的字符串进行编码,并将编码后的字符串输出。
(4). 译码:利用已经建好的哈夫曼树对编码后的字符串进行译码,并输出译码结果。
(5). 打印:以直观的方式打印哈夫曼树。
(6). 计算输入的字符串编码前和编码后的长度,并进行分析,讨论哈夫曼编码的压缩效果。
(7). 用户界面可以设计成“菜单”方式,能进行交互,根据输入的字符串中每个字符出现的次数统计频度,对没有出现的字符一律不用编码。
2.程序分析2.1存储结构二叉树:示意图:root2.21{2.3 关键算法分析1. 定义哈夫曼树的模板类#include <iostream>#include <string.h> using namespace std; structLNode {char ch;int weight;char code[20];LNode* next; };struct TNode{int weight; //int Lchild; //int Rchild; //int Parent; // };class Huffman 结点权值左孩子指针右孩子指针双亲指针// 链表的节点, 用来统计字符频率,并编码// 字符// 权值// 字符编码// 指向下一个节点// 哈弗曼树结点的结构体1 public:Huffman(); ~Huffman(); void CreateTable(); void PrintTable(); void Encoding(); void Decoding(); void Comrate();// 构造函数,输入、统计字符,创建哈弗曼树、码表// 释放链表空间、哈弗曼树的节点// 建立编码表,并将信息存入链表// 输出码表// 哈弗曼编码// 译码void SelectMin(int &x,int &y,int begin,int end);void reverse(char ch[]); voidcontrol();private: // 选取权值最小的两个数,创建哈弗曼树// 将码值倒置,用来编码// 对菜单交互等提示操作TNode* troot;LNode* lroot; void List(char a[]); void HTree(); int Letter; char astr[1000]; char bstr[1000]; // 在统计字符频率是构建链表的根节点// 统计字符的权值建立的单链表// 哈弗曼树建立// 共有不同字符总数// 用户输入的一串字符// 将字符串的码值保存Huffman::Huffman(){lroot=new LNode;bstr[0]='\0';lroot->next=NULL;Letter=0; // 初始化字符总数为1 cout<<" 请输入一串字符,以回车键结束"<<endl;cin.getline(astr,1000,'\n');if(strlen(astr)==0) throw 1;else{List(astr); // 用链表存储每个字符HTree();CreateTable();Encoding();}};Huffman::~Huffman(){delete troot;LNode* p=lroot;while(p=lroot->next)1{{ lroot=p->next; delete p; p=lroot;}delete p; };2. 建立哈夫曼树void Huffman::HTree(){LNode* p=lroot; int a=0;troot=new TNode[2*Letter-1]; //2n-1 while (p=p->next){troot[a].weight=p->weight; troot[a].Parent=-1; troot[a].Lchild=-1; troot[a].Rchild=-1; a++;};for (int i=Letter;i<2*Letter-1;i++)troot[i].Parent=-1; int x,y,begin=0;for (int j=Letter;j<2*Letter-1;j++) while (troot[begin].Parent!=-1)begin++;个结点// 建立叶子节点// 是两个最小值的角标SelectMin(x,y,begin,j);troot[j].weight=troot[x].weight+troot[y].weight;troot[j].Lchild=x;troot[j].Rchild=y;troot[j].Parent=-1;troot[x].Parent=j;troot[y].Parent=j;}};3.统计字符的频率void Huffman::List(char a[]){LNode *p=lroot;int i=0;while(a[i]!='\0'){{while (p&&p->ch!=a[i]) // 查找链表中没有该字符或者找到该字符p=p->next;if (!p) // 如果没有该字符,创建节点。
数据结构课程设计报告(HuffMan编码器)
《数据结构》课程设计报告题目:HuffMan编码器目录一.问题描述二.基本要求(需求分析)三.•概要设计(设计思想、实现方法、模块设计)四.•详细设计(数据结构设计、算法设计、算法分析)五.测试数据及测试结果六.课程设计小结(心得体会、存在问题、改进措施)一.问题描述利用哈夫曼编码进行通信可以大大提高信道利用率,缩短信息传输时间,降低传输成本。
但是,这要求在发送端通过一个编码系统对待传数据预先编码,在接收端将传来的数据进行译码(复原)。
对于双工信道(即可以双向传输信息的信道),每端都需要一个完整的编/译码系统。
试为这样的信息收发站写一个哈夫曼码的编/译码系统。
二.基本要求(需求分析)一个完整的系统应具有以下功能:(1)I:初始化(Initialization)。
从终端读入字符集大小n,以及n个字符和n个权值,建立哈夫曼树,并将它存于文件hfmTree中。
(2)E:编码(Encoding)。
利用已建好的哈夫曼树(如不在内存,则从文件hfmTree中读入),对文件ToBeTran中的正文进行编码,然后将结果存入文件CodeFile中。
(3)D:译码(Decoding)。
利用已建好的哈夫曼树将文件CodeFile中的代码进行译码,结果存入文件TextFile中。
(4)P:印代码文件(Print)。
将文件CodeFile以紧凑格式显示在终端上,每行50个代码。
同时将此字符形式的编码文件写入文件CodePrin中。
(5)T:印哈夫曼树(Tree printing)。
将已在内存中的哈夫曼树以直观的方式(树或凹入表形式)显示在终端上,同时将此字符形式的哈夫曼树写入文件TreePrint中。
[测试数据]用下表给出的字符集和频度的实际统计数据建立哈夫曼树,并实现以下报文的编码和译码:“THIS PROGRAM IS MY FA VORITE”。
字符空格 A B C D E F G H I J K L M频度186 64 13 22 32 103 21 15 47 57 1 5 32 20字符N O P Q R S T U V W X Y Z频度57 63 15 1 48 51 80 23 8 18 1 16 1[实现提示](1)编码结果以文本方式存储在文件CodeFile中。
北邮数据结构 实验报告四——哈夫曼树
数据结构实验报告实验名称:实验4——题目4——哈夫曼树学生姓名:班级:班内序号:学号:日期:2017年1月6日1.实验要求利用二叉树结构实现哈夫曼编/解码器。
基本要求:1、初始化(Init):能够对输入的任意长度的字符串s进行统计,统计每个字符的频度,并建立赫夫曼树2、建立编码表(CreateTable):利用已经建好的赫夫曼树进行编码,并将每个字符的编码输出。
3、编码(Encoding):根据编码表对输入的字符串进行编码,并将编码后的字符串输出。
4、译码(Decoding):利用已经建好的赫夫曼树对编码后的字符串进行译码,并输出译码结果。
5、打印(Print):以直观的方式打印赫夫曼树(选作)6、计算输入的字符串编码前和编码后的长度,并进行分析,讨论赫夫曼编码的压缩效果。
2. 程序分析2.1 存储结构本实验的存储结构为哈夫曼树与哈夫曼编码表哈夫曼树:存储结构:struct HNode//哈夫曼树的结点结构{int weight;//结点权值int parent;//双亲指针int LChild;//左孩子指针int RChild;//右孩子指针};哈夫曼编码表:struct HCode//编码表的结点结构{char data;//字符char code[10];//编码int k;//码长};存储结构:2.2 关键算法分析一、初始化:步骤:1、设立数组,记录每一个字符出现的次数与字符对应的ASCII码2、以字符不是回车或换行遍历输入的字符数组3、将存储出现次数大于0的字符存储进叶子节点数组4、相对应的,存储叶子结点的数据域字符出现的次数。
时间复杂度:O(n)空间复杂度:O(n)二、创建哈夫曼树步骤:1、创建2n-1个数节点2、将权值数组依次赋值进0到n-1的权值节点中3、从0到i-1(最开始等于n-1)选择两个权值最小的节点x、y,将其连接为i节点的左右孩子,改变x、y的双亲指针为i节点4、I++,循环步骤4直到2n-1时间复杂度:O(n^2)空间复杂度 O(n)三、创建哈夫曼编码表步骤:1、创建n个编码表节点2、依次将叶子节点的字符放入编码表节点数据域中3、对每个编码表对应的树结点,向根节点开始回溯(为父节点的左孩子编码值为0,右孩子为1,不断上移,直到根节点)4、进行倒置时间复杂度O(n)空间复杂度 O(n)四、编码步骤:1、新建编码数组2、从源码第一个字符开始在编码表中寻找到相应字符后将编码复制进编码数组3、计算压缩比时间复杂度O(n+e) n为源码 e为编码数组长度空间复杂度O(n)五、解码步骤:1、从根节点开始,按照编码串寻找(0为左子树,1为右子树)2、直到该节点无子树,将该节点(也就是叶子节点)字符放入解码串中3、重复步骤1、2直到编码串结束时间复杂度O(n) n为编码串长度空间复杂度O(e) e为原串长度六、打印哈夫曼树步骤:1、从根节点开始第m层前方空m个格2、叶子结点先输出数据域再在下一行输出权值3、重复输出,递归调用,直到叶子。
哈夫曼实验报告(附代码)
哈夫曼实验报告(附代码)以下是为大家整理的哈夫曼实验报告(附代码)的相关范文,本文关键词为哈夫曼,实验,报告,代码,,您可以从右上方搜索框检索更多相关文章,如果您觉得有用,请继续关注我们并推荐给您的好友,您可以在综合文库中查看更多范文。
哈弗曼编码/译码器一、程序的功能分析1.构造哈夫曼树及哈夫曼编码:从终端读入字符集大小n、n 个字符以及n个对应的权值,建立哈夫曼树;利用已经建好的哈夫曼树求每个叶结点的哈夫曼编码,并保存。
2.编码:利用已构造的哈夫曼编码对“明文”文件中的正文进行编码,然后将结果存入“密文”文件中。
3.译码:将“密文”文件中的0、1代码序列进行译码。
(读文件) 4.打印“密文”文件:将文件以紧凑格式显示在终端上,每行30个代码;同时,将此字符形式的编码文件保存。
5.打印哈夫曼树及哈夫曼编码:将已在内存中的哈夫曼树以凹入表形式显示在终端上,同时将每个字符的哈夫曼编码显示出来;并保存到文件。
二、基本要求分析1、输入输出的要求按提示内容从键盘输入命令,系统根据用户输入的需求在保证界面友好的前提下输出用户所需信息,并按要求保存文件,以便保存备份信息。
2、测试数据(1).令叶子结点个数n为4,权值集合为{1,3,5,7},字符集合为{A,b,c,D},且字符集与权值集合一一对应。
(2).令叶子结点个数n为7,权值集合为{12,6,8,18,3,20,2},字符集合为{A,b,c,D,e,F,g},且字符集与权值集合一一对应。
(3).请自行选定一段英文文本,统计给出的字符集,实际统计字符的频度,建立哈夫曼树,构造哈夫曼编码,并实现其编码和译码。
三、概要设计1.主模块的流程及各子模块的主要功能主函数负责提供选项功能,循环调控整个系统。
创建模块实现接收字符、权值、构建哈夫曼树,并保存文件,此功能是后续功能的基础。
编码模块实现利用已编好的哈夫曼树对每个字符进行哈夫曼编码,即对每个字符译出其密文代码,并保存文件。
数据结构哈夫曼编译码器
数据结构课设哈夫曼编译码器学号:姓名:提交日期:成绩:一、实验名称哈夫曼编/译码器的实现二、实验要求【问题描述】利用哈夫曼编码进行通信可以大大提高信道利用率,缩短信息传输时间,降低传输成本。
但是,这要求在发送端通过一个编码系统对待传来数据预先编码,在接收端将传来的数据进行译码(复原)。
对于双工信道(即可以双向传输信息的信道),每端都需要一个完整的编/译码系统。
试为这样的信息收发站写一个哈夫曼码的编/译码系统。
【基本要求】一个完整的系统应具有以下功能:(1)I:初始化(Initialization)。
从终端读入字符集大小n , 以及n个字符和n个权值,建立哈夫曼树,并将它存于文件hfmTree中。
(2)E:编码(Encoding)。
利用已建好的哈夫曼树(如不在内存,则从文件hfmTree中读人),对文件ToBeTran中的正文进行编码,然后将结果存入文件CodeFile中。
(3)D: 译码(Decoding)。
利用已建好的哈夫曼树将文件 CodeFile 中的代码进行译码,结果存入文件TextFile中。
(4)P:打印代码文件(Print)。
将文件CodeFile以紧凑格式显示在终端上,每行 50 个代码。
同时将此字符形式的编码文件写入文件 CodePrin 中。
(5)T:打印哈夫曼树(Tree printing)。
将已在内存中的哈夫曼树以直观的方式(树或凹入表形式)显示在终端上,同时将此字符形式的哈夫曼树写入文件TreePrint中。
【测试数据】(1)利用教科书例 6-2 中的数据调试程序。
(2)用下表给出的字符集和频度的实际统计数据建立哈夫曼树 , 并实现以下报文的编码和译码:"THIS PROGRAM IS MY FAVORITE"。
三、 需求分析Huffman 编码是一种可变长编码方式,是由美国数学家David Huffman 创立的,是二叉树的一种特殊转化形式。
编码的原理是:将使用次数多的代码转换成长度较短的代码,而使用次数少的可以使用较长的编码,并且保持编码的唯一可解性。
Huffman编码实验报告
Huffman编码实验报告⼀、实验⽬的1.掌握树的操作实现算法。
2.掌握⼆叉树的建⽴,遍历,输出等算法。
3.掌握哈夫曼树的构造算法。
⼆、实验要求:(1)实验前编写源程序、准备测试数据。
(2)在Turbo C下完成程序的编辑、编译、运⾏,获得程序结果。
如果结果有误,应找出原因,并设法更正之。
三、实验内容编程实现任给n个权值,构造出哈夫曼树,并对各个字符编码。
#include#define MAXBIT 100#define MAXVALUE 10000#define MAXLEAF 30#define MAXNODE MAXLEAF*2 -1typedef struct{int bit[MAXBIT];int start;} HCodeType; /* 编码结构体*/typedef struct{int weight; /*权重*/int parent; /*⽗节点*/int lchild; /*左孩⼦*/int rchild; /*右孩⼦*/} HNodeType; /* 结点结构体*//* 构造⼀颗哈夫曼树*/void HuffmanTree (HNodeType HuffNode[MAXNODE], int n){ /* i、j:循环变量,m1、m2:构造哈夫曼树不同过程中两个最⼩权值结点的权值,x1、x2:构造哈夫曼树不同过程中两个最⼩权值结点在数组中的序号。
*/int i, j, m1, m2, x1, x2;/* 初始化存放哈夫曼树数组HuffNode[] 中的结点*/for (i=0; i<2*n-1; i++){ HuffNode[i].weight = 0; /*权重初始化为0*/HuffNode[i].parent =-1; /*节点初始化为-1*/HuffNode[i].lchild =-1;HuffNode[i].lchild =-1;} /* end for *//* 输⼊n 个叶⼦结点的权值*/for (i=0; i{ printf ("Please input weight of leaf node %d: \n", i);/*窗⼝弹出输⼊命令,输⼊权重值*/scanf ("%d", &HuffNode[i].weight);} /* end for *//* 循环构造Huffman 树*/for (i=0; i{ m1=m2=MAXVALUE; /* m1、m2中存放两个⽆⽗结点且结点权值最⼩的两个结点*/ x1=x2=0;/* 找出所有结点中权值最⼩、⽆⽗结点的两个结点并合并之为⼀颗⼆叉树*/ for (j=0; j {if (HuffNode[j].weight < m1 && HuffNode[j].parent==-1)/*判断节点的权重及是否有⽗节点*/{ m2=m1; /*将m1,x1的值赋给m2,x2*/x2=x1;m1=HuffNode[j].weight;/*当前节点的权重赋给m1*/x1=j;/*当前节点序号赋给x1*/}else if (HuffNode[j].weight < m2 && HuffNode[j].parent==-1)/*判断节点的权重及是否有⽗节点*/{ m2=HuffNode[j].weight;/*当前节点的权重赋给m2*/x2=j;/*当前节点序号赋给x2*/}} /* end for *//* 设置找到的两个⼦结点x1、x2 的⽗结点信息*/HuffNode[x1].parent = n+i;/*设置⽗节点的序号*/HuffNode[x2].parent = n+i;HuffNode[n+i].weight = HuffNode[x1].weight + HuffNode[x2].weight;/*设置⽗节点的权值*/HuffNode[n+i].lchild = x1;/*设置⽗节点对应的左右孩⼦*/HuffNode[n+i].rchild = x2;printf ("x1.weight and x2.weight in round %d: %d, %d\n", i+1,HuffNode[x1].weight, HuffNode[x2].weight); /* ⽤于测试*/printf ("\n");} /* end for */} /* end HuffmanTree */int main(void){ HNodeType HuffNode[MAXNODE]; /* 定义⼀个结点结构体数组*/HCodeType HuffCode[MAXLEAF], cd; /* 定义⼀个编码结构体数组,同时定义⼀个临时变量来存放求解编码时的信息*/ int i, j, c, p, n;printf ("Please input n:\n");/*窗⼝弹出输⼊命令,输⼊权值*/scanf ("%d", &n);HuffmanTree (HuffNode, n);/*调⽤构造哈夫曼树的函数*/for (i=0; i < n; i++){ cd.start = n-1;c = i;p = HuffNode[c].parent;while (p != -1) /* ⽗结点存在*/{ if (HuffNode[p].lchild == c)/*处理左孩⼦节点*/cd.bit[cd.start] = 1;else /*处理右孩⼦节点*/cd.bit[cd.start] = 0;cd.start--; /* 求编码的低⼀位*/c=p;p=HuffNode[c].parent; /* 设置下⼀循环条件*/ } /* end while *//* 保存求出的每个叶结点的哈夫曼编码和编码的起始位*/ for (j=cd.start+1; j{ HuffCode[i].bit[j] = cd.bit[j];}HuffCode[i].start = cd.start;} /* end for *//* 输出已保存好的所有存在编码的哈夫曼编码*/for (i=0; i{printf ("%d 's Huffman code is: ", i);for (j=HuffCode[i].start+1; j < n; j++){printf ("%d", HuffCode[i].bit[j]);}printf ("\n");}return 0;}四、实验数据记录及分析运⾏程序,依据提⽰输⼊权值,然后依次输⼊各个值得权重,即可得到哈夫曼编码后的⼆进制码字。
数据结构实验报告 huffman编码和解码算法
(规格为A4纸或A3纸折叠)佛山科学技术学院(用四号宋体)实验报告(用小二号黑体)课程名称数据结构实验实验项目用Huffman树进行编码和解码算法专业班级姓名学号指导教师成绩日期(用小四号宋体)一、目的和要求1、通过本实验,熟悉二叉树、Huffman树的基本概念,掌握二叉树的存储结构及各种算法。
2、熟悉用Huffman树进行电文的加密与解密算法。
二、实验原理Huffman树是一种特殊的二叉树,其叶结点的编码是一种前缀码,同时,通过统计字符的频度,能够达到编码电文的最小化。
三、实验步骤1、统计电文中字符的出现频率。
2. 用统计频率建立Hffman树。
3.生成前缀码;4.建立huffman树的解码算法.5.用随机输入的电文完成编码与解码过程。
四、源程序#include <stdio.h>#include <stdlib.h>#include <string.h>#define MAX 100struct HTNode{char a;int weight;int parent,lchild,rchild;}*HT; //动态分配数组存储赫夫曼树char **HC;int n=0,m=0;char *write()//存储输入的电文{char *p,*q;printf("请输入电文(结束输入请按enter):\n");p=(char *)malloc(MAX*sizeof(char));//申请存储输入的电文的空间if(!p) exit(0);q=p;scanf("%c",q);while(*q!='\n'){//******录入电文,每录入一个字符同时给电文长度计数器n加一*******//*****************遇到换行符时结束录入***************n=n+1;if(n>=MAX)//判断已申请的空间是否足够录入,不足则追加空间{p=(char *)realloc(q,(MAX+10)*sizeof(char));if(!p) exit(0);}q++;scanf("%c",q);}return(p);}void weight(char *p)//求电文中各字符的概率,并将该概率当作各字符的权值{char *q,*q1,temp;struct HTNode *q2;int i,j,t;q1=q=(char *)malloc(n*sizeof(char));for(;*p!='\n';p++,q1++) *q1=*p;//将电文存放到q1指向的空间中q1=q;for(i=0;i<n-1;i++){//*****对电文中的字符进行排序,使得相同的字符地址连续,方便统计***** t=i;for(j=i+1;j<n;j++)if(*(q1+t)>*(q1+j)) t=j;temp=*(q1+i);*(q1+i)=*(q1+t);*(q1+t)=temp;}temp=*q1;//标记当前为何种字符m=1;for(i=1;i<n;i++)//统计电文中出现过不同的字符的个数{q1++;if(temp!=*q1){m++;//字符种类计数器加一temp=*q1;}}q1=q;HT=(struct HTNode *)malloc(2*m*sizeof(struct HTNode));/*申请赫夫曼树HT的空间,其中0号单元不用*/q2=HT+1;//*****************初始化赫夫曼树HT*********************for(i=1;i<=n;){t=0;for(q2->a=*q1;*q1==q2->a;q1++){t++;i++;}q2->weight=(int)(t*100/n);q2->lchild=0;q2->parent=0;q2->rchild=0;q2++;}for(i=m+1;i<=2*m-1;i++,q2++){q2->lchild=0;q2->parent=0;q2->rchild=0;q2->weight=0;}free(q);}void Select(int t,int *s1,int *s2){/************在HT[1,t]选择parent为0且weight最小的两个结点,其序号分别为s1和s2。
北邮信通院数据结构实验报告三哈夫曼编码器
数据结构实验报告实验名称:实验三树——哈夫曼编/解码器学生:班级:班序号:学号:日期:2014年12月11日1.实验要求利用二叉树结构实现赫夫曼编/解码器。
基本要求:1、初始化(Init):能够对输入的任意长度的字符串s进行统计,统计每个字符的频度,并建立赫夫曼树2、建立编码表(CreateTable):利用已经建好的赫夫曼树进行编码,并将每个字符的编码输出。
3、编码(Encoding):根据编码表对输入的字符串进行编码,并将编码后的字符串输出。
4、译码(Decoding):利用已经建好的赫夫曼树对编码后的字符串进行译码,并输出译码结果。
5、打印(Print):以直观的方式打印赫夫曼树(选作)6、计算输入的字符串编码前和编码后的长度,并进行分析,讨论赫夫曼编码的压缩效果。
测试数据:I love data Structure, I love Computer。
I will try my best to study data Structure.提示:1、用户界面可以设计为“菜单”方式:能够进行交互。
2、根据输入的字符串中每个字符出现的次数统计频度,对没有出现的字符一律不用编码。
2. 程序分析2.1 存储结构Huffman树给定一组具有确定权值的叶子结点,可以构造出不同的二叉树,其中带权路径长度最小的二叉树称为Huffman树,也叫做最优二叉树。
weight lchild rchild parent 2-1-1-15-1-1-16-1-1-17-1-1-19-1-1-1weight lchild rchild parent2-1-155-1-156-1-167-1-169-1-17701713238165482967-12.2 关键算法分析(1)计算出现字符的权值利用ASCII码统计出现字符的次数,再将未出现的字符进行筛选,将出现的字符及頻数存储在数组a[]中。
void Huffman::Init(){int nNum[256]= {0}; //记录每一个字符出现的次数int ch = cin.get();int i=0;while((ch!='\r') && (ch!='\n')){nNum[ch]++; //统计字符出现的次数str[i++] = ch; //记录原始字符串ch = cin.get(); //读取下一个字符}str[i]='\0';n = 0;for ( i=0;i<256;i++){if (nNum[i]>0) //若nNum[i]==0,字符未出现{l[n] = (char)i;a[n] = nNum[i];n++;}}}时间复杂度为O(1);(2)创建哈夫曼树:算法过程:Huffman树采用顺序存储---数组;数组的前n个结点存储叶子结点,然后是分支结点,最后是根结点;首先初始化叶子结点元素—循环实现;以循环结构,实现分支结点的合成,合成规则按照huffman树构成规则进行。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
北京邮电大学电信工程学院数据结构实验报告实验名称: ____Huffman 编码 /解码器 _____学生姓名: __________________班级: __________________班内序号: __________________学号: __________________日期: ___________________-1.实验要求利用二叉树结构实现哈夫曼编/ 解码器。
基本要求:1.初始化 (Init) :能够对输入的任意长度的字符串s 进行统计,统计每个字符的频度,并建立哈夫曼树2.建立编码表 (CreateTable):利用已经建好的哈夫曼树进行编码,并将每个字符的编码输出。
3.编码 (Encoding) :根据编码表对输入的字符串进行编码,并将编码后的字符串输出。
4.译码 (Decoding) :利用已经建好的哈夫曼树对编码后的字符串进行译码,并输出译码结果。
5.计算输入的字符串编码前和编码后的长度,并进行分析,讨论赫夫曼编码的压缩效果。
2. 程序分析2.1 存储结构静态三叉链表Weight Lchild Rchild parent2.2 程序流程(或程序结构、或类关系图等表明程序构成的内容,一般为流程图等 )2.2.1.流程图开始输入进行编码的字符串统计各个字符的频度,并对各叶子节点的权重赋值初始化各节点的Lchild , Rchild 和 parent进行哈弗曼编码是否最后一个字符是输出各字符编码对字符串进行编码找到当前字符编码,复制到总编码中是否最后一个字符是输出各字符串编码对哈弗曼码进行译码输出译码结果是否判断双亲节点否-该节点是否为根节点否若为左孩子若为右孩子编码前插入0编码前插入1-输出占用情况结束2.2.1.伪代码1.输入进行编码的字符串2.遍历字符串,并为叶子节点权重赋值3.依次对各字符进行哈弗曼编码,自下往上,若是双亲节点左孩子则编码前插入‘0’,若是双亲节点右孩子则编码钱插入‘1’。
4.显示各字符的哈弗曼编码。
5.对字符串进行编码,挨个遍历字符,找到相应的编码,复制到总的编码里,最后输出字符串的编码。
6.对字符串的哈弗曼码进行译码。
自上往下,若是‘0’,则递归到左孩子,若是‘1’,则递归到右孩子,知道叶子节点,输出该叶子节点代表字符,再继续遍历。
7.分析内存占用情况。
若用ASCII 编码,每个字符占 1 个字节,即8bit ,该情况下占用内存就是(字符长度)*8 。
若用哈弗曼编码,占用内存是各(字符频度)* (每个字符占用位数)之和。
2.3 关键算法分析该程序关键算法即哈弗曼编码,语句如下:void CHTree::huffmancode(){int i;if(n<=1)return;m=2*n-1;for(i=1;i<=n;i++)//叶子节点的初始化{ ht[i].parent=0;ht[i].lchild=0;ht[i].rchild=0;}for(;i<=m;i++) //非叶子节点的初始化{ht[i].weight=0;ht[i].parent=0;ht[i].lchild=0;ht[i].rchild=0;}-for(i=n+1;i<=m;++i)//构造哈夫曼树{s1=select(i-1);// 函数在 ht[1] 到 ht[i-1] 中选择 parent 为 0 且 weight 最小的结点,并将结点序号返 s,并将 ht[s1].parent 设为 -1s2=select(i-1);ht[s1].parent=i;ht[s2].parent=i;ht[i].lchild=s1;ht[i].rchild=s2;ht[i].weight=ht[s1].weight+ht[s2].weight;}int c,f;for(i=1;i<=n;++i) {for(c=i,f=ht[i].parent;f!=0;c=f,f=ht[f].parent)//逆向求叶子结点的哈夫曼编码if(ht[f].lchild==c){str[i].insert(0,"0",0,1);} //在字符串str[i] 的第 0 位置插入字符“ 0”else{str[i].insert(0,"1",0,1);} //在字符串str[i] 的第 0 位置插入字符“1”}}分析:这段语句实现的功能是根据统计出来的各字符的频度,建立哈弗曼。
建立哈弗曼树的过程如程序所展示,每次选取权重最小且无双亲节点的节点组合,并将其权重之和赋给其双亲节点,加入到总结中进行下次判断。
哈弗曼树建立完全以后,开始对各字符进行编码,从下往上,以叶子节点为起始点,若它是双亲节点的左孩子,其编码前插入‘0’,若是右孩子则插入‘ 1’。
再判断双亲节点使其双亲节点的左孩子还是右孩子,以此类推直到根节点。
依次对每个字符进行上述过程编码。
算法复杂度:最好情况为只有根结点和叶子节点:O( n)最坏情况为满二叉树情况:O( n*logn/2 )-3.程序运行结果分析首先,要求用户输入进行编码的字符串,遍历字符串,并为叶子节点权重赋值。
然后,依次对各字符进行哈弗曼编码,自下往上,若是双亲节点左孩子则编码前插入‘0’,若是双亲节点右孩子则编码钱插入‘ 1’。
屏幕上显示各字符的哈弗曼编码。
接下来对字符串进行编码,挨个遍历字符,找到相应的编码,复制到总的编码里,最后输出字符串的编码。
对字符串的哈弗曼码进行译码。
自上往下,若是‘0’,则递归到左孩子,若是‘1’,则递归到右孩子,知道叶子节点,输出该叶子节点代表字符,再继续遍历。
最后分析内存占用情况。
若用ASCII 编码,每个字符占 1 个字节,即8bit,该情况下占用内存就是(字符长度)*8 。
若用哈弗曼编码,占用内存是各(字符频度)*(每个字符占用位数)之和。
3.总结4.1 实验的难点和关键点本实验的难点和关键点是进行哈弗曼的编码与译码。
编码之前先要遍历字符串,并统计各字符出现的频度。
这里就要区分目前的字符是否出现过,若出现过则字符权重加一,若没有出现则在结构体数组的当前末尾添加该元素。
统计完频度以后开始编码。
根据哈弗曼树的特点,每次选取结点里权重最小,且双亲不为0 的节点结合,依次添加直至根节点。
编码过程是从下往上。
对于某字符所在叶子节点,若是双亲节点左孩子则编码前插入‘0’,若是双亲节点右孩子则编码钱插入‘ 1’。
直到双亲节点移动到根节点,所得到的编码即为该字符的编码。
译码过程是编码的逆过程。
依次读取哈弗曼码,自上往下,若是‘0’,则递归到左孩-子,若是‘ 1’,则递归到右孩子,知道叶子节点,输出该叶子节点代表字符,再继续遍历。
4.2 心得体会通过哈弗曼树的程序编写,更加深入了解了树这种数据结构的特点,并且熟悉了这种数据结构的应用。
同时,也对哈弗曼编码的优越性能有了根本的解释。
附:程序代码#include<iostream>#include<string>using namespace std;#define max 1000// 哈夫曼数存储的最大叶子节点数int judge;// 初始化过程中用于判断字符是否出现过struct HTNode{char c;int weight;int lchild,rchild,parent;};class CHTree{public:CHTree(){ht=NULL;} ;void Init();void huffmancode();int select(int i);void Display();void canculate();void encoding();void decoding();private:HTNode* ht;int m;int n;// 叶子结点数int s1;int s2;string a;// 存储输入的字符串string code;// 存储对字符串的编码string str[max];// 存储叶子结点的哈夫曼编码};void CHTree::Init()-{int i=1;// 用于记录叶子节点个数int j=0;int x=0,ru;cout<<" 请输入进行编码的字符串:"<<endl;cin>>a;int l=a.length();ht=(HTNode*)malloc((max)*sizeof(HTNode));//分配 MAXSIZE个叶子结点的存储空间while(x<l) // 统计字符出现的次数{judge=1;for(j=0;j<i;j++){if(ht[j].c==a[x]){//如果字符a[x]已经出现过,则记录,权值加1ht[j].weight++;judge=0;break;}}if(judge){// 若字符没有出现过,字符入列,且权值设为1 n=i;//记录叶子节点数ht[i].weight=1;ht[i].c=a[x];i++; }x++;}}int CHTree::select(int i)// 函数在 ht[1] 到 ht[i] 中选择 parent 为 0 且 weight 最小的结点,并将结点序号返回{int j=1;int k=1;int s;while(ht[j].parent!=0){j++;s=j;}k=j+1;while(k<=i){while(ht[k].parent!=0) k++;if(k>i)return s;if(ht[j].weight>ht[k].weight){ht[j].parent=0;// 如果第二次和第二次以后循环中发现有比ht[j] 权值还小的,将欢迎下载8-s=j;ht[j].parent=-1;// 如果 ht[j] 是权值较小的,将ht[j] 的 parent 记为 -1,}else{s=j;ht[j].parent=-1;}k++;}return s; }void CHTree::huffmancode(){int i;if(n<=1)return;m=2*n-1;for(i=1;i<=n;i++)//叶子节点的初始化{ ht[i].parent=0;ht[i].lchild=0;ht[i].rchild=0;}for(;i<=m;i++) //非叶子节点的初始化{ht[i].weight=0;ht[i].parent=0;ht[i].lchild=0;ht[i].rchild=0;}for(i=n+1;i<=m;++i)//构造哈夫曼树{s1=select(i-1);// 函数在 ht[1] 到 ht[i-1] 中选择 parent 为 0 且 weight 最小的结点,并将结点序号返 s,并将 ht[s1].parent 设为 -1s2=select(i-1);ht[s1].parent=i;ht[s2].parent=i;ht[i].lchild=s1;ht[i].rchild=s2;ht[i].weight=ht[s1].weight+ht[s2].weight;}int c,f;for(i=1;i<=n;++i) {for(c=i,f=ht[i].parent;f!=0;c=f,f=ht[f].parent)//逆向求叶子结点的哈夫曼编码if(ht[f].lchild==c){str[i].insert(0,"0",0,1);} //在字符串str[i] 的第 0 位置插入字符“ 0”else{str[i].insert(0,"1",0,1);} //在字符串str[i] 的第 0 位置插入字符“1”}-void CHTree::Display(){cout<<"huffman 编码如下: \n";cout<<" 字符 "<<'\t'<<" 权值 "<<'\t'<<" 哈夫曼编码 "<<endl;for(int i=1;i<=n;i++){cout<<ht[i].c<<'\t'<<ht[i].weight<<'\t'<<str[i]<<endl;}}void CHTree::canculate(){int m=0;for(int i=1;i<=n;i++){m+=(ht[i].weight)*(str[i].length());//该字符所占位数为频度和每个字符huffman 码长度乘积}cout<<"\n\n内存分析:\n"<<"原始编码所占内存数为"<<8*sizeof(char)*(a.length())<<"bit"<<endl;cout<<"huffman 编码所占内存数为"<<m<<"bit"<<endl;}void CHTree::encoding(){for(int i=0;i<a.length();i++){//循环变量i用于遍历输入字符串的字符for(int j=1;j<=n;j++){//循环变量j用于寻找huffman编码中与该字符的相匹配的字符编码if(a[i]==ht[j].c)code+=str[j];}}cout<<"\n\n 字符编码为 "<<code<<endl;}void CHTree::decoding(){int i=0;int m=code.length();cout<<"\n\n 对编码译码后所得字符:";while(i<m){int parent=2*n-1;// 根结点在 HTree 中的下表while(ht[parent].rchild!=0||ht[parent].lchild!=0)// 自根结点向叶子节点匹配编码,叶子节点左右孩子均为0,此时输出字符{if(code[i]=='0')parent=ht[parent].lchild;elseparent=ht[parent].rchild;i++;}cout<<ht[parent].c;}-}void main(){CHTree h;h.Init(); // 初始化,统计输入字符的频度,赋值各叶子节点的权重h.huffmancode();// 建立 huffman 树h.Display();// 显示各字符对应的huffman 码h.encoding();// 对输入的字符进行编码h.decoding();// 对以上编码进行解码h.canculate();// 计算分析编码前与编码后的所占内存system("pause");}。