哈夫曼编码与译码报告

合集下载

哈夫曼编码译码实验报告

哈夫曼编码译码实验报告

哈夫曼编码译码实验报告哈夫曼编码译码实验报告一、引言哈夫曼编码是一种用来对数据进行压缩的算法,它能够根据数据的频率分布来分配不同长度的编码,从而实现对数据的高效压缩。

本次实验旨在通过实际操作,深入理解哈夫曼编码的原理和实现方式,并通过编码和解码过程来验证其有效性。

二、实验目的1. 掌握哈夫曼编码的原理和算法;2. 学会使用编程语言实现哈夫曼编码和解码;3. 验证哈夫曼编码在数据压缩中的实际效果。

三、实验过程1. 数据准备在实验开始前,首先需要准备一段文本数据作为实验材料。

为了更好地展示哈夫曼编码的效果,我们选择了一篇新闻报道作为实验文本。

这篇报道涵盖了多个领域的信息,包括科技、经济、体育等,具有一定的复杂性。

2. 哈夫曼编码实现根据哈夫曼编码的原理,我们首先需要统计文本中每个字符的频率。

为了方便处理,我们将每个字符与其频率构建成一个字符-频率的映射表。

然后,我们根据频率构建哈夫曼树,将频率较低的字符作为叶子节点,频率较高的字符作为内部节点。

最后,根据哈夫曼树构建编码表,将每个字符映射到对应的二进制编码。

3. 哈夫曼解码实现在哈夫曼解码过程中,我们需要根据编码表将二进制编码转换回字符。

为了实现高效解码,我们可以将编码表转换为一个二叉树,其中每个叶子节点对应一个字符。

通过遍历二叉树,我们可以根据输入的二进制编码逐步还原出原始文本。

4. 编码和解码效果验证为了验证哈夫曼编码的有效性,我们需要对编码和解码的结果进行比较。

通过计算编码后的二进制数据长度和原始文本长度的比值,我们可以得到压缩率,进一步评估哈夫曼编码的效果。

四、实验结果经过实验,我们得到了以下结果:1. 哈夫曼编码表根据实验文本统计得到的字符-频率映射表,我们构建了哈夫曼树,并生成了相应的编码表。

编码表中每个字符对应的编码长度不同,频率较高的字符编码长度较短,频率较低的字符编码长度较长。

2. 编码结果将实验文本使用哈夫曼编码进行压缩后,得到了一串二进制数据。

信息论霍夫曼编码译码实验报告

信息论霍夫曼编码译码实验报告

实验一一、实验背景*哈夫曼编码(Huffman Coding)是一种编码方式,哈夫曼编码是可变字长编码(VLC)的一种。

Huffman于1952年提出一种编码方法,该方法完全依据字符出现概率来构造异字头的平均长度最短的码字,有时称之为最佳编码,一般叫作Huffman编码。

二、实验要求*利用程序实现哈夫曼编码,以加深对哈夫曼编码的理解,并锻炼编程能力。

三、代码分析#include<stdio.h>#define n 3 //叶子数目#define m (2*n-1) //结点总数#define maxval 10000.0 //maxval是float类型的最大值#define maxsize 100 //哈夫曼编码的最大位数typedef struct //定义霍夫曼树结构体{char ch; //消息float weight; //所占权重int lchild,rchild,parent; //定义左孩子、右孩子}hufmtree;typedef struct //定义霍夫曼编码结构体{char bits[n]; //位串int start; //编码在位串中的起始位置char ch; //字符}codetype;void huffman(hufmtree tree[]); //建立哈夫曼树void huffmancode(codetype code[],hufmtree tree[]); //根据哈夫曼树求出哈夫曼编码void decode(hufmtree tree[]); //依次读入电文,根据哈夫曼树译码void main(){printf(" ——哈夫曼编码——\n");printf("信源共有%d个符号\n",n);hufmtree tree[m]; //m个结点,即有m个树形结构codetype code[n]; //信源有n个消息,则需要n个编码int i,j; //循环变量huffman(tree); //建立哈夫曼树huffmancode(code,tree); //根据哈夫曼树求出哈夫曼编码printf("【输出每个字符的哈夫曼编码】\n");for(i=0;i<n;i++){printf("%c: ",code[i].ch);for(j=code[i].start;j<n;j++)printf("%c ",code[i].bits[j]);//“消息:该消息的编码”printf("\n");}printf("【读入电文,并进行译码】\n");decode(tree); //依次读入电文,根据哈夫曼树译码}void huffman(hufmtree tree[]) //建立哈夫曼树{int i,j,p1,p2; //p1,p2分别记住每次合并时权值最小和次小的两个根结点的下标float small1,small2,f;char c;for(i=0;i<m;i++) //初始化{tree[i].parent=0;tree[i].lchild=-1;tree[i].rchild=-1;tree[i].weight=0.0;}printf("【依次读入前%d个结点的字符及权值(中间用空格隔开)】\n",n);for(i=0;i<n;i++) //读入前n个结点的字符及权值{printf("输入第%d个字符为和权值",i+1);scanf("%c %f",&c,&f);getchar(); //吸收回车符tree[i].ch=c;tree[i].weight=f; //将接收到的结点的字符及权值存入它对应的结构体数据中}for(i=n;i<m;i++) //进行n-1次合并,产生n-1个新结点{p1=0;p2=0;small1=maxval;small2=maxval; //maxval是float类型的最大值for(j=0;j<i;j++) //选出两个权值最小的根结点{if(tree[j].parent==0) //还未找到父结点的if(tree[j].weight<small1) //如果有比最小的还小的{small2=small1; //改变最小权、次小权及对应的位置small1=tree[j].weight;p2=p1;p1=j;}else if(tree[j].weight<small2) //如果有比最小的大,但比第二小的小的{small2=tree[j].weight; //改变次小权及位置p2=j;}}//找出的两个结点是新节点i的两个孩子tree[p1].parent=i;tree[p2].parent=i;tree[i].lchild=p1; //最小权根结点是新结点的左孩子tree[i].rchild=p2; //次小权根结点是新结点的右孩子tree[i].weight=tree[p1].weight+tree[p2].weight;}} //huffman//codetype code[]为求出的哈夫曼编码//hufmtree tree[]为已知的哈夫曼树void huffmancode(codetype code[],hufmtree tree[]) //根据哈夫曼树求出哈夫曼编码{int i,c,p;codetype cd; //缓冲变量for(i=0;i<n;i++){cd.start=n; //编码在位串中的起始位置cd.ch=tree[i].ch;c=i; //从叶结点出发向上回溯,第i个叶结点p=tree[i].parent; //tree[p]是tree[i]的父结点while(p!=0){cd.start--;if(tree[p].lchild==c)cd.bits[cd.start]='0'; //tree[i]是左子树,生成代码'0' elsecd.bits[cd.start]='1'; //tree[i]是右子树,生成代码'1' c=p; //c记录此时的父结点p=tree[p].parent; //p记录新的父结点,即原来的父结点的父结点,向上溯回}code[i]=cd; //第i+1个字符的编码存入code[i] }} //huffmancodevoid decode(hufmtree tree[])//依次读入电文,根据哈夫曼树译码{int i,j=0;char b[maxsize];i=m-1; //从根结点开始往下搜索printf("输入发送的编码:");gets(b);printf("译码后的字符为");while(b[j]!='\0'){if(b[j]=='0')i=tree[i].lchild; //走向左子树elsei=tree[i].rchild; //走向右子树if(tree[i].lchild==-1) //如果回到叶结点,则把该结点的消息符号输出{printf("%c",tree[i].ch);i=m-1; //回到根结点}j++;}printf("\n");if(tree[i].lchild!=-1&&b[j]=='\0') //电文读完,但尚未到叶子结点printf("\nERROR\n"); //输入电文有错}//decode四、实验补充说明解码时,以回车键结束输入电文。

数据结构哈夫曼树编码及译码的实现实验报告

数据结构哈夫曼树编码及译码的实现实验报告

实验:哈夫曼树编码及译码的实现一.实验题目给定字符集的HUFFMANN编码与解码,这里的字符集及其字符频数自己定义,要求输出个字符集的哈夫曼编码及给定的字符串的哈夫曼码及译码结果。

二.实验原理首先规定构建哈夫曼树,然后进行哈夫曼树的编码,接着设计函数进行字符串的编码过程,最后进行哈夫曼编码的译码。

首先定义一个结构体,这个结构体定义时尽可能的大,用来存放左右的变量,再定义一个地址空间,用于存放数组,数组中每个元素为之前定义的结构体。

输入n个字符及其权值。

构建哈夫曼树:在上述存储结构上实现的哈夫曼算法可大致描述为:1.首先将地址空间初始化,将ht[0…n-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]的权值之和。

4.哈夫曼的编码:约定左子为0,右子为1,则可以从根结点到叶子结点的路径上的字符组成的字符串作为该叶子结点的编码。

当用户输入字母时。

就在已经找好编码的编码结构体中去查找该字母。

查到该字母就打印所存的哈夫曼编码。

接着就是完成用户输入0、1代码时把代码转成字母的功能。

这是从树的头结点向下查找,如果当前用户输入的0、1串中是0则就走向该结点的左子。

如果是1这就走向该结点的右结点,重复上面步骤。

哈夫曼编译码的设计与实现实验报告

哈夫曼编译码的设计与实现实验报告

哈夫曼编/译码的设计与实现实验报告问题描述利用哈夫曼编码进行通信可以大大提高信道利用率,缩短信息传输时间,降低传输成本。

但是,这要求在发送端通过一个编码系统对待传数据预先编码,在接收端将传来的数据进行译码(复原)。

对于双工信道(即可以双向传输信息的信道),每端都需要一个完整的编/译码系统。

试为这样的信息收发编写一个哈夫曼码的编/译码系统。

基本要求(1)接收原始数据:从终端读入字符集大小n,以及n个字符和n个权值,建立哈夫曼树,并将它存于文件hfmtree.dat中。

(2)编码:利用已建好的哈夫曼树(如不在内存,则从文件hfmtree.dat中读入),对文件中的正文进行编码,然后将结果存入文件codefile.dat中。

(3)译码:利用已建好的哈夫曼树将文件codefile.dat中的代码进行译码,结果存入文件textfile.dat中。

(4)打印编码规则:即字符与编码的一一对应关系。

运行与调试(1)利用教科书中的数据调试程序。

(2)用下表给出的字符集和频度的实际统计数据建立哈夫曼树,并实现以下报文的编码和译码:“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实验小结通过这次实验,让我对于树的应用多了认识,在读取文件时,遇到的一些困难,不过在和同学交流的过程中,解决了这个问题,我觉的自己对于树及文件的应用又有了一些进步。

通过这次实验,感觉收获很大。

源程序// 哈夫曼编译码的设计与实现.cpp : 定义控制台应用程序的入口点。

//#include "stdafx.h"#include<iostream>#include<fstream>#include<string>#define Maxvalue 10000#define MAXBIT 200using namespace std;struct node{char letter;string num;};typedef struct{char letter;int weight; //结点权值int parent;int lchild;int rchild;}HnodeType;typedef struct{int bit[MAXBIT];int start;}HcodeType;HnodeType *HaffmanTree(int n){HnodeType *HuffNode;HuffNode=new HnodeType[2*n-1];int i,j;int m1,m2,x1,x2;for(i=0;i<2*n-1;i++) //数组HuffNode[]初始化{HuffNode[i].weight=0;HuffNode[i].parent=-1;HuffNode[i].lchild=-1;HuffNode[i].rchild=-1;}cout<<"请输入每个叶子结点的字母和权值(形如A5):"<<endl;for(i=0;i<n;i++)cin>>HuffNode[i].letter>>HuffNode[i].weight; //输入n个叶子结点的权值for(i=0;i<n-1;i++) //构造哈夫曼树{m1=m2=Maxvalue;x1=x2=0;for(j=0;j<n+i;j++) //选取最和次小两个权值{if(HuffNode[j].parent==-1&&HuffNode[j].weight<m1){m2=m1;x2=x1;m1=HuffNode[j].weight;x1=j;}else{if(HuffNode[j].parent==-1&&HuffNode[j].weight<m2){m2=HuffNode[j].weight;x2=j;}}}//将找出的两棵子树合并为一棵子树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;}cout<<" weight"<<" lchild"<<" rchild"<<" parent"<<endl; for(i=0;i<2*n-1;i++)cout<<i<<"--"<<" "<<HuffNode[i].weight<<" "<<HuffNode[i].lchild<<" "<<HuffNode[i].rchild<<" "<<HuffNode[i].parent<<endl;ofstream outFile("hfmtree.dat",ios::out);if(!outFile)cerr<<"文件打开失败!"<<endl;else{outFile<<" weight"<<" lchild"<<" rchild"<<"parent"<<endl;for(i=0;i<2*n-1;i++)outFile<<i<<"--"<<" "<<HuffNode[i].weight<<""<<HuffNode[i].lchild<<" "<<HuffNode[i].rchild<<""<<HuffNode[i].parent<<endl;outFile.close();}return HuffNode;}void HaffmanCode(HnodeType *HuffNode,int n){HcodeType *HuffCode,cd;HuffCode=new HcodeType[2*n-1];int c,p,i,j;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]=0;elsecd.bit[cd.start]=1;cd.start--;c=p;p=HuffNode[c].parent;}for(j=cd.start+1;j<n;j++)HuffCode[i].bit[j]=cd.bit[j];HuffCode[i].start=cd.start;}for(i=0;i<n;i++){cout<<HuffNode[i].letter;for(j=HuffCode[i].start+1;j<n;j++)cout<<HuffCode[i].bit[j];cout<<endl;}ofstream outFile1("codefile.dat",ios::out|ios::binary);if(!outFile1)cerr<<"文件打开失败!"<<endl;else{for(i=0;i<n;i++){outFile1<<HuffNode[i].letter;for(j=HuffCode[i].start+1;j<n;j++)outFile1<<HuffCode[i].bit[j];outFile1<<endl;}outFile1.close();}}int _tmain(int argc, _TCHAR* argv[]){HnodeType *HuffNode;int n,i;cout<<"请输入叶子结点个数:";cin>>n;if(cin.fail()){cout<<"输入有误!"<<endl;return 0;}HuffNode=HaffmanTree(n);HaffmanCode(HuffNode,n);int num;cout<<"请输入要加密的字母串的长度(空格也要计算在内):";cin>>num;char *l1;char l;node l2[27];l1=new char[num];cout<<"请输入要加密的字母串(请用大写,如有空格请用“-”代替):";for(int n=0;n<num;n++)cin>>l1[n];ofstream outFile2("bianma.dat",ios::out|ios::binary);if(!outFile2)cerr<<"文件打开失败!"<<endl;else{for(i=0;i<num;i++)outFile2<<l1[i];outFile2.close();}ifstream inFile1("codefile.dat",ios::in|ios::binary);ifstream inFile2("bianma.dat",ios::in|ios::binary);cerr<<"读取文件失败!"<<endl;if(!inFile2)cerr<<"读取文件失败!"<<endl;else{while(inFile2.peek ()!=EOF){inFile2>>l;for(i=0;i<2*n-1;i++){inFile1>>l2[i].letter;inFile1>>l2[i].num;}for(i=0;i<n;i++){if(l2[i].letter==l)cout<<l2[i].num<<" ";}}inFile1.close();inFile2.close();}delete []l1;cout<<endl;int a;cout<<"请输入要进行译码的串的个数:";cin>>a;string *s;s=new string[a];cout<<"请输入要解码的串(每输入一个串,请按一次【Enter】键):"<<endl; for(i=0;i<a;i++)cin>>s[i];ofstream outFile4("yima.dat",ios::out);if(!outFile4)cerr<<"文件打开失败!"<<endl;else{for(i=0;i<a;i++)outFile4<<s[i]<<endl;outFile4.close();}ifstream inFile3("codefile.dat",ios::in|ios::binary);cerr<<"读取文件失败!"<<endl;else{for(i=0;i<2*n-1;i++){inFile3>>l2[i].letter;inFile3>>l2[i].num;}ifstream inFile4("yima.dat",ios::in);if(!inFile4)cerr<<"读取文件失败!"<<endl;else{for(int j=0;j<a;j++)inFile4>>s[j];}for(int j=0;j<a;j++){for(i=0;i<n;i++){if(l2[i].num==s[j])cout<<l2[i].letter;}}inFile3.close();}return 0;}。

哈夫曼树编码译码实验报告

哈夫曼树编码译码实验报告

数据结构课程设计设计题目:哈夫曼树编码译码课题名称院系学号姓名哈夫曼树编码译码年级专业成绩1、课题设计目的:在当今信息爆炸时代,如何采用有效的数据压缩技术节省数据文件的存储空间和计算机网络的传送时间已越来越引起人们的重视,哈夫曼编码正是一种应用广泛且非常有效的数据压缩技术。

哈夫曼编码是一种编码方式,以哈夫曼树—即最优二叉树,带权路径长度最小的二叉树,时常应用于数据压缩。

哈弗曼编码使用一张特殊的编码表将源字符(例如某文件中的一个符号)进行编码。

这张编码表的特殊之处在于,它是根据每一个源字符浮现的估算概率而建立起来的。

课题设计目的与设计意义2、课题设计意义:哈夫曼编码的应用很广泛,利用哈夫曼树求得的用于通信的二进制编码称为哈夫曼编码。

树中从根到每一个叶子都有一条路径,对路径上的各分支约定:指向左子树的分支表示“0”码,指向右子树的分支表示“1”码,取每条路径上的“0”或者“1”的序列作为和各个叶子对应的字符的编码,这就是哈夫曼编码。

哈弗曼译码输入字符串可以把它编译成二进制代码,输入二进制代码时可以编译成字符串。

指导教师:年月日第一章需求分析 (1)第二章设计要求 (1)第三章概要设计 (2)(1)其主要流程图如图 1-1 所示。

(3)(2)设计包含的几个方面 (4)第四章详细设计 (4)(1)①哈夫曼树的存储结构描述为: (4)(2)哈弗曼编码 (5)(3)哈弗曼译码 (7)(4)主函数 (8)(5)显示部份源程序: (8)第五章调试结果 (10)第六章心得体味 (12)第七章参考文献 (12)附录: (12)在当今信息爆炸时代,如何采用有效的数据压缩技术节省数据文件的存储空间和计算机网络的传送时间已越来越引起人们的重视,哈夫曼编码正是一种应用广泛且非常有效的数据压缩技术。

哈夫曼编码是一种编码方式,以哈夫曼树—即最优二叉树,带权路径长度最小的二叉树,时常应用于数据压缩。

哈弗曼编码使用一张特殊的编码表将源字符 (例如某文件中的一个符号) 进行编码。

哈夫曼编码译码器实验报告

哈夫曼编码译码器实验报告

哈夫曼编码译码器实验报告实验名称:哈夫曼编码译码器实验一、实验目的:1.了解哈夫曼编码的原理和应用。

2.实现一个哈夫曼编码的编码和译码器。

3.掌握哈夫曼编码的编码和译码过程。

二、实验原理:哈夫曼编码是一种常用的可变长度编码,用于将字符映射到二进制编码。

根据字符出现的频率,建立一个哈夫曼树,出现频率高的字符编码短,出现频率低的字符编码长。

编码过程中,根据已建立的哈夫曼树,将字符替换为对应的二进制编码。

译码过程中,根据已建立的哈夫曼树,将二进制编码替换为对应的字符。

三、实验步骤:1.构建一个哈夫曼树,根据字符出现的频率排序。

频率高的字符在左子树,频率低的字符在右子树。

2.根据建立的哈夫曼树,生成字符对应的编码表,包括字符和对应的二进制编码。

3.输入一个字符串,根据编码表将字符串编码为二进制序列。

4.输入一个二进制序列,根据编码表将二进制序列译码为字符串。

5.比较编码前后字符串的内容,确保译码正确性。

四、实验结果:1.构建哈夫曼树:-字符出现频率:A(2),B(5),C(1),D(3),E(1) -构建的哈夫曼树如下:12/\/\69/\/\3345/\/\/\/\ABCDE2.生成编码表:-A:00-B:01-C:100-D:101-E:1103.编码过程:4.译码过程:5.比较编码前后字符串的内容,结果正确。

五、实验总结:通过本次实验,我了解了哈夫曼编码的原理和应用,并且实现了一个简单的哈夫曼编码的编码和译码器。

在实验过程中,我充分运用了数据结构中的树的知识,构建了一个哈夫曼树,并生成了编码表。

通过编码和译码过程,我进一步巩固了对树的遍历和节点查找的理解。

实验结果表明,本次哈夫曼编码的编码和译码过程正确无误。

在实验的过程中,我发现哈夫曼编码对于频率较高的字符具有较短的编码,从而实现了对字符串的高效压缩。

同时,哈夫曼编码还可以应用于数据传输和存储中,提高数据的传输效率和存储空间的利用率。

通过本次实验,我不仅掌握了哈夫曼编码的编码和译码过程,还深入了解了其实现原理和应用场景,加深了对数据结构和算法的理解和应用能力。

哈夫曼实验报告

哈夫曼实验报告

一、实验目的1. 理解哈夫曼编码的基本原理和重要性。

2. 掌握哈夫曼树的构建方法。

3. 熟悉哈夫曼编码和译码的实现过程。

4. 分析哈夫曼编码在数据压缩中的应用效果。

二、实验原理哈夫曼编码是一种基于字符频率的编码方法,它利用字符出现的频率来构造一棵最优二叉树(哈夫曼树),并根据该树生成字符的编码。

在哈夫曼树中,频率越高的字符对应的编码越短,频率越低的字符对应的编码越长。

这样,对于出现频率较高的字符,编码后的数据长度更短,从而实现数据压缩。

三、实验内容1. 构建哈夫曼树:- 统计待编码数据中每个字符出现的频率。

- 根据字符频率构建哈夫曼树,其中频率高的字符作为叶子节点,频率低的字符作为内部节点。

- 重复上述步骤,直到树中只剩下一个节点,即为哈夫曼树的根节点。

2. 生成哈夫曼编码:- 从哈夫曼树的根节点开始,对每个节点进行遍历,根据遍历方向(左子树为0,右子树为1)为字符分配编码。

- 将生成的编码存储在编码表中。

3. 编码和译码:- 使用生成的编码表对原始数据进行编码,将编码后的数据存储在文件中。

- 从文件中读取编码后的数据,根据编码表进行译码,恢复原始数据。

四、实验步骤1. 编写代码实现哈夫曼树的构建:- 定义节点结构体,包含字符、频率、左子树、右子树等属性。

- 实现构建哈夫曼树的核心算法,包括节点合并、插入等操作。

2. 实现编码和译码功能:- 根据哈夫曼树生成编码表。

- 编写编码函数,根据编码表对数据进行编码。

- 编写译码函数,根据编码表对数据进行译码。

3. 测试实验效果:- 选择一段文本数据,使用实验代码进行编码和译码。

- 比较编码前后数据的长度,分析哈夫曼编码的压缩效果。

五、实验结果与分析1. 哈夫曼树构建:- 成功构建了哈夫曼树,树中节点按照字符频率从高到低排列。

2. 哈夫曼编码:- 成功生成编码表,字符与编码的对应关系符合哈夫曼编码原理。

3. 编码与译码:- 成功实现编码和译码功能,编码后的数据长度明显缩短,译码结果与原始数据完全一致。

哈夫曼编码译码报告

哈夫曼编码译码报告

烟台大学计算机与控制工程学院课程设计(数据结构与OOP)设计题目:班级姓名学号指导教师成绩年月日目录1 题目 (3)1.1 问题描述 (3)1.2 基本要求 (3)1.3 进一步完成 (3)2 内容 (3)2.1 基本需求 (3)2.2. 我的设计 (4)3 算法设计 (4)3.1 数据的存储结构 (4)3.1.1 存放哈夫曼树的存储结构: (4)3.1.2 存放哈夫曼编码的存储结构: (4)3.1.3 存放哈夫曼树每个节点位置的存储结构: (5)3.2 生成哈弗曼树的算法 (5)3.3 生成哈弗曼编码的算法 (6)3.4 译码的算法 (8)3.5 打印哈弗曼树的算法 (9)3.6 其他算法 (10)4 程序正确性验证 (10)4.1 输入数据的控制 (10)4.2 打印哈弗曼树 (11)4.3 哈弗曼编码 (11)4.4 哈弗曼译码 (12)5 遇到的问题 (12)6 课程设计的主要收获 (12)7 对今后课程设计的建议 (12)1 题目1.1 问题描述设计一个利用哈夫曼算法的编码和译码系统,重复地显示并处理项目,直到选择退出为止。

1.2 基本要求1) 将权值数据存放在数据文件(文件名为data.txt,位于执行程序的当前目中2) 分别采用动态和静态存储结构3) 初始化:键盘输入字符集大小n、n个字符和n个权值,建立哈夫曼树4) 编码:利用建好的哈夫曼树生成哈夫曼编码5) 输出编码6) 设字符集及频度如下表:字符空格 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 11.3 进一步完成1) 译码功能2) 显示哈夫曼树3) 界面设计的优化2 内容2.1 基本需求编写一个哈夫曼编码/译码器,次编码/译码器有两大主要功能:一是对一段文本进行编码,比如在利用电报机发送信息时,需要将文字“ABACCDA”转换成类似“00110111001”这样的二进制组成的字符串;二是对一段密文进行译码,比如在接收电报后,需要对“0101110100101”这样的二进制密文通过某种标准译码成看得懂的文字信息。

哈夫曼编码译码器实验报告

哈夫曼编码译码器实验报告

中北大学数据结构课程设计说明书学生姓名:郝晨栋学号:1021010933学院: 软件学院专业: 软件开发与测试题目: 哈夫曼编码/译码器指导教师康珺2011年12月20日目录1 问题描述.............................................................. 错误!未定义书签。

2 需求分析.............................................................. 错误!未定义书签。

3 概要设计 (1)3.1抽象数据类型定义 (1)3.2总体框图以及功能描述 (2)4 详细设计 (2)4.1数据类型的定义 (2)4.2主要模块的算法描述 (3)5 测试分析 (4)6 课程设计总结 (6)附录(源程序清单) (7)1 问题描述1.设计一个利用哈夫曼算法的编码和译码系统,重复地显示并处理以下项目,直到选择退出为止。

(1) 将权值数据存放在数据文件(文件名为data.txt,位于当前目录中);(2) 分别采用动态和静态存储结构; 初始化:键盘输入字符集大小n、n个字符和n个权值,建立哈夫曼树;(3) 编码:利用建好的哈夫曼树生成哈夫曼编码;输出编码;设计要求:(1) 符合课题要求,实现相应功能;(2) 要求界面友好美观,操作方便易行;(3) 注意程序的实用性、安全性。

2 需求分析编写此软件是为了实现一个利用哈夫曼算法的编码和译码系统。

比如,再利用电报进行通讯时,需要将文字转换成由二进制的字符组成的字符串。

比如需传送的电文为“A B A C C D A”假设将A,B,C,D分别编码为00、01、10、11.则上述电文遍为00010010101100,总长度为14位。

但是在传送过程中,总希望长度能够尽可能的短,于是我们想采用长度不等的编码。

但是这种编码必须遵循:任何一个字符的编码都不是另一个字符编码的前缀。

哈夫曼实验报告(附代码)

哈夫曼实验报告(附代码)

哈夫曼实验报告(附代码)以下是为大家整理的哈夫曼实验报告(附代码)的相关范文,本文关键词为哈夫曼,实验,报告,代码,,您可以从右上方搜索框检索更多相关文章,如果您觉得有用,请继续关注我们并推荐给您的好友,您可以在综合文库中查看更多范文。

哈弗曼编码/译码器一、程序的功能分析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.主模块的流程及各子模块的主要功能主函数负责提供选项功能,循环调控整个系统。

创建模块实现接收字符、权值、构建哈夫曼树,并保存文件,此功能是后续功能的基础。

编码模块实现利用已编好的哈夫曼树对每个字符进行哈夫曼编码,即对每个字符译出其密文代码,并保存文件。

哈夫曼编码译码器实验报告

哈夫曼编码译码器实验报告

问题解析与解题方法问题分析:设计一个哈夫曼编码、译码系统。

对一个ASCII编码的文本文件中的字符进行哈夫曼编码,生成编码文件;反过来,可将编码文件译码还原为一个文本文件。

(1)从文件中读入任意一篇英文短文(文件为ASCII编码,扩展名为txt);(2)统计并输出不同字符在文章中出现的频率(空格、换行、标点等也按字符处理);(3)根据字符频率构造哈夫曼树,并给出每个字符的哈夫曼编码;(4)将文本文件利用哈夫曼树进行编码,存储成压缩文件(编码文件后缀名.huf)(5)用哈夫曼编码来存储文件,并和输入文本文件大小进行比较,计算文件压缩率;(6)进行译码,将huf文件译码为ASCII编码的txt文件,与原txt文件进行比较。

根据上述过程可以知道该编码译码器的关键在于字符统计和哈夫曼树的创建以及解码。

哈夫曼树的理论创建过程如下:一、构成初始集合对给定的n个权值{W1,W2,W3,...,Wi,...,Wn}构成n棵二叉树的初始集合F={T1,T2,T3,...,Ti,...,Tn},其中每棵二叉树Ti中只有一个权值为Wi的根结点,它的左右子树均为空。

二、选取左右子树在F中选取两棵根结点权值最小的树作为新构造的二叉树的左右子树,新二叉树的根结点的权值为其左右子树的根结点的权值之和。

三、删除左右子树从F中删除这两棵树,并把这棵新的二叉树同样以升序排列加入到集合F中。

四、重复二和三两步,重复二和三两步,直到集合F中只有一棵二叉树为止。

因此,有如下分析:1.我们需要一个功能函数对ASCII码的初始化并需要一个数组来保存它们;2.定义代表森林的数组,在创建哈夫曼树的过程当中保存被选中的字符,即给定报文中出现的字符,模拟哈夫曼树选取和删除左右子树的过程;3.自底而上地创建哈夫曼树,保存根的地址和每个叶节点的地址,即字符的地址,然后自底而上检索,首尾对换调整为哈夫曼树实现哈弗曼编码;4.从哈弗曼编码文件当中读入字符,根据当前字符为0或者1的状况访问左子树或者右孩子,实现解码;5.使用文件读写操作哈夫曼编码和解码结果的写入;解题方法:结构体、数组、类的定义:1.定义结构体类型的signode 作为哈夫曼树的节点,定义结构体类型的hufnode 作为哈夫曼编码对照表的节点,定义HFM类实现对哈夫曼树的创建,利用其成员函数完成哈夫曼编码译码的工作。

编码译码实验报告

编码译码实验报告

一、实验目的1. 理解编码译码的基本原理和方法。

2. 掌握哈夫曼编码和译码的实现过程。

3. 通过实验,提高编程能力和数据结构应用能力。

二、实验环境1. 操作系统:Windows 102. 编程语言:C++3. 开发工具:Visual Studio 2019三、实验内容1. 哈夫曼编码与译码(1)哈夫曼编码的原理哈夫曼编码是一种变长编码,通过为不同频率的字符分配不同的编码长度,达到压缩数据的目的。

哈夫曼编码的核心是构建一棵哈夫曼树,树中每个叶子节点对应一个字符,非叶子节点对应两个子节点的编码。

(2)哈夫曼编码的实现首先,根据输入的字符及其频率,构建哈夫曼树。

然后,从根节点开始,对每个叶子节点进行编码,编码规则为从根节点到叶子节点的路径,左子节点编码为“0”,右子节点编码为“1”。

(3)哈夫曼译码的实现根据哈夫曼编码的编码规则,将编码后的数据还原成原始字符。

从编码数据的第一个比特开始,根据编码规则,逐步还原出原始字符。

2. 字符串编码与译码(1)字符串编码的原理字符串编码是将字符串中的字符转换成二进制表示,以达到压缩数据的目的。

常见的字符串编码方法有ASCII编码、UTF-8编码等。

(2)字符串编码的实现以ASCII编码为例,将字符串中的每个字符转换为对应的ASCII码,然后将其转换为二进制表示。

(3)字符串译码的实现将编码后的二进制数据转换回对应的ASCII码,再将ASCII码转换成字符。

四、实验步骤1. 创建一个新的C++项目,命名为“编码译码实验”。

2. 在项目中创建两个源文件:main.cpp和编码译码.cpp。

3. 在main.cpp中编写代码,实现以下功能:(1)从文件中读取字符串,进行哈夫曼编码。

(2)将编码后的数据写入文件。

(3)从文件中读取编码后的数据,进行哈夫曼译码。

(4)将译码后的字符串输出到屏幕。

4. 在编码译码.cpp中编写代码,实现以下功能:(1)构建哈夫曼树。

(2)实现哈夫曼编码和译码算法。

哈夫曼编码译码实训报告

哈夫曼编码译码实训报告

一、实训目的本次实训旨在通过实际操作,使学生掌握哈夫曼编码的基本原理和方法,熟悉哈夫曼树的构建过程,并能够熟练地进行哈夫曼编码和译码操作。

通过实训,提升学生对数据压缩技术的理解和应用能力。

二、实训内容1. 哈夫曼树构建- 收集给定字符串中每个字符的出现频率。

- 根据字符频率构建哈夫曼树,其中频率高的字符对应较大的权重。

- 使用优先队列(最小堆)实现哈夫曼树的构建。

2. 哈夫曼编码- 遍历哈夫曼树,为每个叶子节点分配唯一的编码,左分支为0,右分支为1。

- 根据分配的编码生成字符编码表。

3. 哈夫曼译码- 使用生成的编码表,将编码字符串转换回原始字符串。

三、实训步骤1. 数据准备- 选择一段英文或中文文本作为输入数据。

2. 构建哈夫曼树- 统计输入数据中每个字符的出现频率。

- 使用优先队列构建哈夫曼树。

3. 生成哈夫曼编码- 遍历哈夫曼树,为每个叶子节点分配编码。

- 生成字符编码表。

4. 编码数据- 使用哈夫曼编码表对输入数据进行编码。

5. 译码数据- 使用哈夫曼编码表对编码后的数据进行译码。

6. 结果分析- 比较编码前后数据的大小,分析哈夫曼编码的压缩效果。

四、实训结果1. 哈夫曼树构建- 成功构建了给定字符串的哈夫曼树。

2. 哈夫曼编码- 成功生成了每个字符的哈夫曼编码。

3. 哈夫曼译码- 成功将编码后的数据译码回原始字符串。

4. 压缩效果分析- 通过对比编码前后数据的大小,验证了哈夫曼编码的压缩效果。

五、实训总结1. 哈夫曼编码原理- 哈夫曼编码是一种基于字符频率的变长编码方法,能够有效降低数据传输的冗余度。

2. 哈夫曼树构建- 哈夫曼树的构建是哈夫曼编码的关键步骤,通过优先队列(最小堆)实现。

3. 哈夫曼编码与译码- 哈夫曼编码和译码过程相对简单,但需要正确处理编码表和字符编码。

4. 实训收获- 通过本次实训,掌握了哈夫曼编码的基本原理和方法,熟悉了哈夫曼树的构建过程,并能够熟练地进行哈夫曼编码和译码操作。

哈夫曼编码实验报告

哈夫曼编码实验报告

实验报告与总结一、实验目的1、掌握哈夫曼编码原理;2、熟练掌握哈夫曼树的生成方法;3、理解数据编码压缩和译码输出编码的实现。

二、实验要求实现哈夫曼编码和译码的生成算法。

三、实验内容先统计要压缩编码的文件中的字符字母出现的次数,按字符字母和空格出现的概率对其进行哈夫曼编码,然后读入要编码的文件,编码后存入另一个文件;接着再调出编码后的文件,并对其进行译码输出,最后存入另一个文件中。

五、实验原理1、哈夫曼树的定义:假设有n个权值,试构造一颗有n个叶子节点的二叉树,每个叶子带权值为wi,其中树带权路径最小的二叉树成为哈夫曼树或者最优二叉树;2、哈夫曼树的构造:weight为输入的频率数组,把其中的值赋给依次建立的HT Node对象中的data属性,即每一个HT Node对应一个输入的频率。

然后根据data属性按从小到大顺序排序,每次从data取出两个最小和此次小的HT Node,将他们的data相加,构造出新的HTNode作为他们的父节点,指针parent,leftchild,rightchild赋相应值。

在把这个新的节点插入最小堆。

按此步骤可以构造构造出一棵哈夫曼树。

通过已经构造出的哈夫曼树,自底向上,由频率节点开始向上寻找parent,直到parent 为树的顶点为止。

这样,根据每次向上搜索后,原节点为父节点的左孩子还是右孩子,来记录1或0,这样,每个频率都会有一个01编码与之唯一对应,并且任何编码没有前部分是同其他完整编码一样的。

六、实验流程①初始化,统计文本文件中各字符的个数作为权值,生成哈夫曼树;②根据符号概率的大小按由大到小顺序对符号进行排序;③把概率最小的两个符号组成一个节点;④重复步骤(2)(3),直到概率和为1;⑤从根节点开始到相应于每个符号的“树叶”,概率大的标“0”,概率小的标“1”;⑥从根节点开始,对符号进行编码;⑦译码时流程逆向进行,从文件中读出哈夫曼树,并利用哈夫曼树将编码序列解码。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

一、设计思想程序要求:利用哈夫曼树对字符串进行编码,要求每个字符有自己唯一的编码。

将得到的一串字串译成0、1编码后存到一个文件夹中,然后再从这个文件夹中读出这串编码进行解码。

实现方法:输入一串字符,要求字符的区间为大写的26个英文字母,将获得的串字符用计算权值的函数(jsquanzhi())进行字符统计,统计出现的字符种数以及每种字符出现的次数,将该种字符出现的次数作为它的权值。

将出现的字符的权值和该字符依次分别赋给两个结构体HT和HC,利用HT(节点)权值的大小建立哈夫曼树,首先用选择函数select()函数选择两个权值最小的字符作为叶子节点,创建一个新的节点作为这两个叶节点的父节点,被选中的节点给他的HT[i].parent赋值是他下次不再被选中,父节点的权值为,子节点的权值之和。

然后将该将父节点放入筛选区中,再进行选择(被选过的不再被使用),直到所有的节点都被使用,这样一个哈夫曼树就被建立了。

根据每个字符在哈夫曼书中的位置来编译每个字符的0、1密文代码,从叶节点判断该叶节点是其父节点的左右字左字为‘0’,右子为‘1’,在判断父节点是上级父节点的左右子直至根节点,将生成的0、1字符串按所表示的字符倒序存入HC相应的字符的bins[]数组。

重新一个一个字符的读取输入的字符串,按照字符出现的顺序将它转为0、1代码并存到一个txt文件夹中去。

解码时从文件夹中,一个一个字符的读出那串0、1代码赋给一个临时字符串cd[],用该字符串与每个字符的HC[i].bins密文比较,直到与一个字符的密文相同时,译出该字符,将字符存放在临时字符数组tempstr[]中,清空临时字符串继续读取0、1代码进行翻译,直至文件密文结束为止。

于是就得到了原先被加密的那串字符串。

二、算法流程图三、源代码// hafuman.cpp : 定义控制台应用程序的入口点。

//#include "stdafx.h"#include "stdlib.h"#include "string.h"#include "stdio.h"#define n 100 //叶节点的个数小等于n#define m 2*n-1 //总结点的个数为m=2*n-1int num; //定义一个全局变量用于存放字符种类个数typedef struct //结构体用于存放树节点包括节点的父节点、左子、右子以及权值{ int weight;int parent,lchild,rchild;}HTNode;typedef HTNode HafumanTree[m+1]; //重命名HTNodetypedef struct //结构体由于存放每个字符的密文和长度{char ch;char bits[10];int len;}CodeNode;typedef CodeNode HafumanCode[n+1]; //重命名CodeNodeint _tmain(int argc, _TCHAR* argv[]){int quan[27]; //声明一个数组用以存放26字符的权值char getstr[300],str[27];//声明两个字符串数组一个用于存输入一个由于存放输入中含有的字符char *s; //声明一个char型指针用于指向字符HafumanTree HT; //声明m+1个树节点HafumanCode HC; //声明n+1个codeint jisuanquan(char *s,int quan[],char str[]); //声明需要调用的函数void gjhafumantree(HafumanTree HT,HafumanCode HC,int quan[],char str[]);void Hafumanencode(HafumanTree HT,HafumanCode HC);void coding(HafumanCode HC,char *str);char *decode(HafumanCode HC);printf("请输入要加密的字符串:\n");gets(getstr); //获得输入的字符串num=jisuanquan(getstr,quan,str); //统计字符串中含有字符种类个数//printf("%d\n",num);gjhafumantree(HT,HC,quan,str); //根据字符权值构建哈夫曼树Hafumanencode(HT,HC); //根据哈夫曼树确定每个字符的code coding(HC,getstr); //将字符串译码存入文件夹s=decode(HC); //将暗文解码printf("解密为:\n");printf("%s\n",s);system("pause");return 0;}//函数int jisuanquan(char *s,int quan[],char str[]) //计算字符串中字符权值{char *p;int i,j,k,quantemp[27];for(i=1;i<27;i++) //将所有字符的权值赋成0 {quantemp[i]=0;}for(p=s;*p!='\0';p++) //判断字符串是否结束{if(*p>='A'&&*p<='Z') //判断字符是否为26字母{k=*p-64; //看是26个字符中的哪个字符quantemp[k]++; //字符权值加1}}j=0;for(i=1,j=0;i<27;i++){if(quantemp[i]!=0){j++; //用于统计字符种类个数str[j]=i+64; //str按字母表顺序存储出现过的字符quan[j]=quantemp[i];}}return j;}void select(HafumanTree HT,int k,int *s1,int*s2) //选择权值最小的两个{int i,j;int min1=9999; //声明一个int类型的数值min1,赋个较大的输给它for(i=1;i<=k;i++) //选择权值最小的一个节点(且该节点无父节点){if((HT[i].weight<min1)&&(HT[i].parent==0)){j=i;min1=HT[i].weight;}}*s1=j;min1=9999;for(i=1;i<=k;i++){if((HT[i].weight<min1)&&(HT[i].parent==0)&&(i!=*s1))//选择权值最小的一个节点(且该节点无父节点){j=i;min1=HT[i].weight;}}*s2=j;}void gjhafumantree(HafumanTree HT,HafumanCode HC,int quan[],char str[]) //构建哈夫曼树{int i,s1,s2;for(i=1;i<2*num-1;i++) //将所有的节点赋空{HT[i].lchild=0;HT[i].rchild=0;HT[i].parent=0;HT[i].weight=0;}for(i=1;i<=num;i++) //将num个字符的权值赋给num叶节点{HT[i].weight=quan[i];}for(i=1;i<=num;i++) //将num个字符赋给codenode{HC[i].ch=str[i];}i=1;while(i<=num){ printf("===%c===%d===\n",HC[i].ch,quan[i]);i++;} //输出每个字符的及其权值for(i=num+1;i<=2*num-1;i++){select(HT,i-1,&s1,&s2); //选择两个权值最小的叶节点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;//父节点的权值为子节点相加(父节点继续放入选择区)}}void Hafumanencode(HafumanTree HT,HafumanCode HC){int c,p,i;char cd[n]; //临时数组用于记录字符在哈夫曼树的位置int start;cd[num]='\0'; //给cd赋个结束符for(i=1;i<=num;i++){start=num;c=i;while((p=HT[c].parent)>0) //根据节点是其父节点的左右子来记录它的位置{cd[--start]=(HT[p].lchild==c)?'0':'1';c=p; //将父节点转为子节点}strcpy(HC[i].bits,&cd[start]); //将得到的0、1字串存入结构体HCprintf("%c:%s\n",HC[i].ch,HC[i].bits);HC[i].len=num-start; //求每个字符0、1编码长度}}void coding(HafumanCode HC,char *str) //根据哈夫曼树确定每个字符的0、1代码code{int i,j;FILE *fp; //声明一个文件夹指针fp=fopen("codefile.txt","w"); //打开文件夹codefileprintf("密文为:\n");while(*str) //字符串未结束时{for(i=1;i<=num;i++){if(HC[i].ch==*str) //判断字符是否在Codenode中存在{for(j=0;j<HC[i].len;j++) //将codenode中该字符的1、0代码存入文件夹{fputc(HC[i].bits[j],fp);}printf("%s",HC[i].bits);break;}}str++; //字符后移}printf("\n");fclose(fp);}char *decode(HafumanCode HC){FILE *fp;char tempstr[9999];char *p;static char cd[n+1]; //char型数组用于存放从文件夹中读取的1、0代码int i,j,k=0,jsjs;fp=fopen("codefile.txt","r");while(!feof(fp)) //当文件夹读取没有结束{jsjs=0; //判读一个字符是否译码结束for(i=0;(i<num)&&(jsjs==0)&&(!feof(fp));i++) //当一个字符未译完并且文件未读取结束{ cd[i]=' ';cd[i+1]='\0'; //让cd[]赋成空格cd[i]=fgetc(fp); //读取文件夹中的一个字符for(j=1;j<=num;j++){ if(strcmp(HC[j].bits,cd)==0) //看cd[]的字符串是否等于Codenode中的某个密文{tempstr[k]=HC[j].ch;jsjs=1;printf("=%s=",HC[j].bits);k++;break;}//将译出的字符赋给临时字符串tempstr[],标记一个字符译码结束jsjs赋1,跳出循环}}}tempstr[k]='\0'; //赋给临时字符串一个结束标志p=tempstr; //char型指针指向临时字符串return p;}四、运行结果图5 哈夫曼编码与译码运行结果图五、遇到的问题及解决这部分我主要遇到了如下两个问题,其内容与解决方法如下所列:●当我写完程序,输入一段字符串让程序进行译码和解码是出现了一个问题,译出的结果不是想要的结果,但结果又有一定规律,就是结果中的字符都在明文中出现过,可是字符数量明显比明文中的要少很多。

相关文档
最新文档