哈夫曼实验报告材料(附代码)
哈夫曼编码实验报告
![哈夫曼编码实验报告](https://img.taocdn.com/s3/m/89dea4bcc5da50e2534d7f2e.png)
六、实验结果演示
七、在编写程序过程中遇到的困难和解决的方法
一、实验容
根据输入的n个带权结点,构造出哈夫曼树,并且把构造结果输出到屏幕。
二、实验说明
哈夫曼数,也称最优二叉树,是指对于一组带有确定权值的叶结点,构造的具有最小带权路径长度的二叉树。
设二叉树具有n个带权值的叶结点,那么从根结点到各个叶结点的路径长度与相应结点权值的乘积之和叫做二叉树的带权路径长度WPL,记作:WPL= 。在给定一组具有确定权值的叶结点,可以构造出不同的带权二叉树。根据哈夫曼树的定义,一棵二叉树要使其WPL值最小,必须使权值越大的叶结点越靠近根结点,而权值越小的叶结点越远离根结点。
Ⅲ.构建哈夫曼树……………………………………………………………6
Ⅳ.对构建好的哈夫曼树进行遍历确定每个结点的编码…………………7
3.输出设置…………………………………………………………7
Ⅰ.输出每个结点的父亲、左孩子、右孩子结点…………………………7
Ⅱ.输出每个结点的哈夫曼编码……………………………………………8
4、重复(2)(3)两步,当F中只剩下一棵二叉树时,这棵二叉树便是所要建立的哈夫曼树。
所以,构造哈夫曼树主要由两个步骤组成:一是选择所有结点中权值最小的两个结点,二是将这些结点加入到二叉树中,构建成哈夫曼树。
1、在所有结点中选出权值最小的两个结点。
Ⅰ、选择权值最小的两个结点并不难,难在如何判断该结点是否已经使用过,若不能正确判断前面构造的哈夫曼树中是否使用过该结点,可能造成结点重复出现在树中,出现错误。根据哈夫曼树构造的特点,当两个结点的权值为最小时就将做为新的二叉树的左(右)子树,而它们的权值之和为它们的根结点,所以可以通过判断该结点是否有父亲结点来判断它是否被使用过。
《哈夫曼编码》实验报告
![《哈夫曼编码》实验报告](https://img.taocdn.com/s3/m/75ffaff209a1284ac850ad02de80d4d8d15a010c.png)
《哈夫曼编码》实验报告《哈夫曼编码》实验报告一、实验目的1、掌握哈夫曼编码原理;2、熟练掌握哈夫曼树的生成方法;3、理解数据编码压缩和译码输出编码的实现。
二、实验要求实现哈夫曼编码和译码的生成算法。
三、实验步骤编写代码如下:#include#include#include#define MAXLEN 100typedef struct{int weight;int lchild;int rchild;int parent;char key;}htnode;typedef htnode hfmt[MAXLEN];int n;void inithfmt(hfmt t){int i;printf("\n");printf("--------------------------------------------------------\n"); printf("**********************输入区**********************\n");printf("\n请输入n=");scanf("%d",&n);getchar();for(i=0;i<2*n-1;i++){t[i].weight=0;t[i].lchild=-1;t[i].rchild=-1;t[i].parent=-1;}printf("\n");}void inputweight(hfmt t){int w;int i;char k;for(i=0;i<n;i++)< bdsfid="112" p=""></n;i++)<>{printf("请输入第%d个字符:",i+1);scanf("%c",&k);getchar();t[i].key=k;printf("请输入第%d个字符的权值:",i+1);scanf("%d",&w);getchar();t[i].weight=w;printf("\n");}}void selectmin(hfmt t,int i,int *p1,int *p2){long min1=999999;long min2=999999;int j;for(j=0;j<=i;j++)if(t[j].parent==-1)if(min1>t[j].weight){min1=t[j].weight;*p1=j;}for(j=0;j<=i;j++)if(t[j].parent==-1)if(min2>t[j].weight && j!=(*p1))//注意 j!=(*p1)) { min2=t[j].weight;*p2=j;}}void creathfmt(hfmt t){int i,p1,p2;inithfmt(t);inputweight(t);for(i=n;i<2*n-1;i++){selectmin(t,i-1,&p1,&p2);t[p1].parent=i;t[p2].parent=i;t[i].lchild=p1;t[i].rchild=p2;t[i].weight=t[p1].weight+t[p2].weight;}}void printhfmt(hfmt t){int i;printf("------------------------------------------------------------------\n");printf("**************哈夫曼编数结构:*********************\n"); printf("\t\t权重\t父母\t左孩子\t右孩子\t字符\t");for(i=0;i<2*n-1;i++){printf("\n");printf("\t\t%d\t%d\t%d\t%d\t%c",t[i].weight,t[i].parent,t[i].lc hild,t [i].rchild,t[i].key);}printf("\n------------------------------------------------------------------\n");printf("\n\n");}void hfmtpath(hfmt t,int i,int j){int a,b;a=i;b=j=t[i].parent;if(t[j].parent!=-1){i=j;hfmtpath(t,i,j);}if(t[b].lchild==a)printf("0");elseprintf("1");}void phfmnode(hfmt t){int i,j,a;printf("\n---------------------------------------------\n"); printf("******************哈夫曼编码**********************"); for(i=0;i<n;i++)< bdsfid="190" p=""></n;i++)<>{j=0;printf("\n");printf("\t\t%c\t",t[i].key,t[i].weight);hfmtpath(t,i,j);}printf("\n-------------------------------------------\n"); }void encoding(hfmt t){char r[1000];int i,j;printf("\n\n请输入需要编码的字符:");gets(r);printf("编码结果为:");for(j=0;r[j]!='\0';j++)for(i=0;i<n;i++)< bdsfid="207" p=""></n;i++)<>if(r[j]==t[i].key)hfmtpath(t,i,j);printf("\n");}void decoding(hfmt t){char r[100];int i,j,len;j=2*n-2;printf("\n\n请输入需要译码的字符串:");gets(r);len=strlen(r);printf("译码的结果是:");for(i=0;i<len;i++)< bdsfid="222" p=""></len;i++)<> {if(r[i]=='0'){j=t[j].lchild;if(t[j].lchild==-1){printf("%c",t[j].key);j=2*n-2;}}else if(r[i]=='1'){j=t[j].rchild;if(t[j].rchild==-1){printf("%c",t[j].key);j=2*n-2;}}printf("\n\n");}int main(){int i,j;hfmt ht;char flag;printf("\n----------------------------------------------\n");printf("*******************编码&&译码&&退出***************");printf("\n【1】编码\t【2】\t译码\t【0】退出");printf("\n您的选择:");flag=getchar();getchar();while(flag!='0'){if(flag=='1')encoding(ht);else if(flag=='2')decoding(ht);elseprintf("您的输入有误,请重新输入。
数据实验报告书-哈夫曼树与哈夫曼编码
![数据实验报告书-哈夫曼树与哈夫曼编码](https://img.taocdn.com/s3/m/8d4260add1f34693daef3eb1.png)
《数据结构》实验报告书实验内容:哈夫曼树与哈夫曼编码201100814***计科111 ***前言计算机编程中加工处理的对象是数据,而数据具有一定的组织结构,所以学习计算机编程仅仅了解计算机语言是不够的,还必须掌握数据的组织、存储和运算的一般方法,这便是数据结构课程中所研究的内容,也是我们编写计算机程序的重要基础,由于它对计算机学科起到承前启后的作用,因此本课程被列为计算机等相关专业最重要的专业基础课;同时数据结构是计算机专业教学的一门核心课程。
计算机各领域都要用到各种数据结构,而且要从事计算机科学与技术工作,尤其是计算机领域的软件开发工作,必须具备较强的数据结构基础。
数据结构课程内容丰富、学习量大,实践性强;隐含在各部分内容中的方法和技术多;算法设计具有动态性和抽象性等特点,看懂听明白与掌握会应用之间有相当大的一段距离。
所以学生必须多实践才能进一步加深对课程的理解,理解和掌握算法设计所需的方法和技术,为整个专业学习打下良好的基础。
一、实验目的1、使学生熟练掌握哈夫曼树的生成算法。
2、熟练掌握哈夫曼编码的方法。
二、实验内容[问题描述]已知n个字符在原文中出现的频率,求它们的哈夫曼编码。
[基本要求]1. 初始化:从键盘读入n个字符,以及它们的权值,建立Huffman树。
(具体算法可参见教材P147的算法 6.12)2. 编码:根据建立的Huffman树,求每个字符的Huffman编码。
对给定的待编码字符序列进行编码。
[选作内容]1. 译码:利用已经建立好的Huffman树,对上面的编码结果译码。
译码的过程是分解电文中的字符串,从根结点出发,按字符’0’和’1’确定找左孩子或右孩子,直至叶结点,便求得该子串相应的字符。
4. 打印 Huffman树。
[测试数据]利用教材P.148 例6-2中的数据调试程序。
可设8种符号分别为A,B,C,D,E,F,G,H。
编/译码序列为“CFBABBFHGH”(也可自己设定数据进行测试)。
数据结构哈夫曼树实验报告
![数据结构哈夫曼树实验报告](https://img.taocdn.com/s3/m/32046dafab00b52acfc789eb172ded630a1c9865.png)
数据结构哈夫曼树实验报告一、实验目的本次实验的主要目的是深入理解和掌握哈夫曼树的数据结构及其相关算法,通过实际编程实现哈夫曼编码和解码的过程,提高对数据结构的应用能力和编程技能。
二、实验环境本次实验使用的编程语言为 Python,开发工具为 PyCharm。
操作系统为 Windows 10。
三、实验原理哈夫曼树(Huffman Tree),又称最优二叉树,是一种带权路径长度最短的二叉树。
其基本思想是通过构建一棵二叉树,使得权值较大的节点离根节点较近,权值较小的节点离根节点较远,从而实现带权路径长度的最小化。
哈夫曼编码是一种基于哈夫曼树的变长编码方式。
对于给定的字符集及其出现的频率,通过构建哈夫曼树,可以为每个字符生成唯一的编码,使得编码后的字符串总长度最短。
在构建哈夫曼树的过程中,首先将每个字符及其出现的频率作为一个独立的节点,然后按照频率从小到大的顺序进行合并,每次合并两个频率最小的节点,生成一个新的节点,其频率为两个子节点频率之和。
重复这个过程,直到所有节点合并为一个根节点,最终得到的二叉树即为哈夫曼树。
四、实验步骤1、定义节点类```pythonclass Node:def __init__(self, char, freq, left=None, right=None):selfchar = charselffreq = freqselfleft = leftselfright = rightdef __lt__(self, other):return selffreq < otherfreq```这个节点类包含了字符、频率以及左右子节点的信息,并实现了小于比较方法,以便在构建哈夫曼树时进行节点的排序。
2、构建哈夫曼树```pythondef build_huffman_tree(freq_dict):nodes = Node(char, freq) for char, freq in freq_dictitems()while len(nodes) > 1:nodessort()left = nodespop(0)right = nodespop(0)merged_freq = leftfreq + rightfreqnew_node = Node(None, merged_freq, left, right)nodesappend(new_node)return nodes0```该函数根据字符频率字典创建节点列表,然后不断合并频率最小的两个节点,直到只剩下一个节点,即哈夫曼树的根节点。
数据结构(C语言版)实验报告(哈夫曼树)
![数据结构(C语言版)实验报告(哈夫曼树)](https://img.taocdn.com/s3/m/0ed1bced941ea76e58fa0438.png)
《数据结构与算法》实验报告一、需求分析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个代码。
同时将此字符形式的编码文件写入文件CodePrin中。
(5)T:印哈夫曼树(Tree printing)。
将已在内存中的哈夫曼树以直观的方式(树或凹入表形式)显示出,同时将此字符形式的哈夫曼树写入文件TreePrint中。
3.测试数据(1)利用教科书例6-2中的数据调试程序。
(2)用下表给出的字符集和频度的实际统计数据建立哈夫曼树,并实现以下报文的编码和译码:“THIS PROGRAM IS MY FAVORITE”。
4,实现提示(1)编码结果以文本方式存储在文件CodeFile中。
(2)用户界面可以设计为“菜单”方式:显示上述功能符号,再加上“Q”表示退出运行Quit。
请用户键入一个选择功能符。
此功能执行完毕后再显示此菜单,直至某次用户选择了“Q”为止。
(3)在程序的一次执行过程中,第一次执行I、D或C命令之后,哈夫曼树已经在内存了,不必再读入。
赫夫曼编码实验报告
![赫夫曼编码实验报告](https://img.taocdn.com/s3/m/98994480db38376baf1ffc4ffe4733687f21fc17.png)
实验五哈夫曼树和哈夫曼树编码学院专业班学号姓名一.实习目的1.掌握哈夫曼树的顺序存储方式;2.掌握建立哈夫曼树的方法;3.掌握由哈夫曼树构造哈夫曼编码的方法。
二.实习内容1.建立哈夫曼树的顺序存储结构;2.编程实现构建一棵哈夫曼树。
3.编程实现由哈夫曼树构造出哈夫曼编码三.实习步骤1. 程序代码#include<malloc.h> // malloc()等#include<limits.h> // INT_MAX等#include<stdio.h> //#include<stdlib.h> //#include<string.h>typedef struct{unsigned int weight;unsigned int parent,lchild,rchild;}HTNode,*HuffmanTree; // 动态分配数组存储赫夫曼树typedef char **HuffmanCode; // 动态分配数组存储赫夫曼编码表int min(HuffmanTree t,int i){ // 返回i个结点中权值最小的树的根结点序号,函数select()调用int j,flag;unsigned int k=UINT_MAX; // 取k为不小于可能的值(无符号整型最大值) for(j=1;j<=i;j++)if(t[j].weight<k&&t[j].parent==0) // t[j]是树的根结点k=t[j].weight,flag=j;t[flag].parent=1; // 给选中的根结点的双亲赋1,避免第2次查找该结点return flag;}void select(HuffmanTree t,int i,int &s1,int &s2){ // 在i个结点中选择2个权值最小的树的根结点序号,s1为其中序号小的那个int j;s1=min(t,i);s2=min(t,i);if(s1>s2){j=s1;s1=s2;s2=j;}}void HuffmanCoding(HuffmanTree &HT,HuffmanCode &HC,int *w,int n) // 算法6.12{ // w存放n个字符的权值(均>0),构造赫夫曼树HT,并求出n个字符的赫夫曼编码HC int m,i,s1,s2,start;unsigned c,f;HuffmanTree p;char *cd;if(n<=1)return;m=2*n-1;HT=(HuffmanTree)malloc((m+1)*sizeof(HTNode)); // 0号单元未用for(p=HT+1,i=1;i<=n;++i,++p,++w){(*p).weight=*w;(*p).parent=0;(*p).lchild=0;(*p).rchild=0;}for(;i<=m;++i,++p)(*p).parent=0;for(i=n+1;i<=m;++i) // 建赫夫曼树{ // 在HT[1~i-1]中选择parent为0且weight最小的两个结点,其序号分别为s1和s2 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;}// 从叶子到根逆向求每个字符的赫夫曼编码HC=(HuffmanCode)malloc((n+1)*sizeof(char*));// 分配n个字符编码的头指针向量([0]不用)cd=(char*)malloc(n*sizeof(char)); // 分配求编码的工作空间cd[n-1]='\0'; // 编码结束符for(i=1;i<=n;i++){ // 逐个字符求赫夫曼编码start=n-1; // 编码结束符位置for(c=i,f=HT[i].parent;f!=0;c=f,f=HT[f].parent)// 从叶子到根逆向求编码if( HT[f].lchild==c)cd[--start]='0';elsecd[--start]='1';HC[i]=(char*)malloc((n-start)*sizeof(char));// 为第i个字符编码分配空间strcpy( HC[i], &cd [start] ); // 从cd复制编码(串)到HC}free(cd); // 释放工作空间}void main(){HuffmanTree HT;HuffmanCode HC;int *w,n,i;printf("请输入权值的个数(>1): ");scanf("%d",&n);w=(int*)malloc(n*sizeof(int));printf("请依次输入%d个权值(整型):\n",n);for(i=0;i<=n-1;i++)scanf("%d",w+i);HuffmanCoding(HT,HC,w,n);printf("huffman树存储结构:\n");for( i=1;i<2*n;i++)printf("%4d%4d%4d%4d\n", HT[i].weight,HT[i].parent,HT[i].lchild,HT[i].rchild);// 输出哈夫曼树的每个结点的权值、父亲结点序号、左孩子和右孩子序号。
哈夫曼树实验报告
![哈夫曼树实验报告](https://img.taocdn.com/s3/m/e51e746176eeaeaad0f33090.png)
数据结构实验报告实验名称:实验三哈夫曼树学生姓名:班级:班内序号:学号:日期:程序分析:2.1 存储结构:二叉树2.2 程序流程:template <class T>class BiTree{public:BiTree(); //构造函数,其前序序列由键盘输入 ~BiTree(void); //析构函数BiNode<T>* Getroot(); //获得指向根结点的指针protected:BiNode<T> *root; //指向根结点的头指针};//声明类BiTree及定义结构BiNodeData:二叉树是由一个根结点和两棵互不相交的左右子树构成二叉树中的结点具有相同数据类型及层次关系哈夫曼树类的数据域,继承节点类型为int的二叉树class HuffmanTree:public BiTree<int>data:HCode* HCodeTable;//编码表int tSize; //编码表中的总字符数二叉树的节点结构template <class T>struct BiNode //二叉树的结点结构{T data; //记录数据T lchild; //左孩子T rchild; //右孩子T parent; //双亲};编码表的节点结构struct HCode{char data; //编码表中的字符char code[100]; //该字符对应的编码};待编码字符串由键盘输入,输入时用链表存储,链表节点为struct Node{char character; //输入的字符unsigned int count;//该字符的权值bool used; //建立树的时候该字符是否使用过Node* next; //保存下一个节点的地址};示意图:2.3 关键算法分析:1.初始化函数(void HuffmanTree::Init(string Input))算法伪代码:1.初始化链表的头结点2.获得输入字符串的第一个字符,并将其插入到链表尾部,n=1(n记录的是链表中字符的个数)3.从字符串第2个字符开始,逐个取出字符串中的字符3.1 将当前取出的字符与链表中已经存在的字符逐个比较,如果当前取出的字符与链表中已经存在的某个字符相同,则链表中该字符的权值加1。
哈夫曼树实验报告(付原c语言程序)
![哈夫曼树实验报告(付原c语言程序)](https://img.taocdn.com/s3/m/b9d69edbd05abe23482fb4daa58da0116c171f08.png)
哈夫曼树实验报告(付原c语言程序)需求分析:从终端读入一串字符,利用建立好的哈夫曼树对其进行编码,储存到文件当中去,然后从文件读入哈夫曼编码,针对每个字母对其进行译码,翻译为原来的信息。
二、概要设计程序分为以下几个模块:1、从终端读入字符集大小,n个字符和n个权值,建立哈夫曼树,写入文件2、对hfmTree进行编码,建立hfm编码表。
hfmTree中去。
3、从文件ToTran读入信息,根据hfm编码表对其进行hfm编码,将编码后的信息写入文件Codefile中去4、对Codefile文件反向译码,结果储存在Textfile5、将建立的hfmTree打印在终端上,并储存于相应的中去。
Treeprint文件中去。
抽象的数据定义如下:哈夫曼树结构typedefstruct//定义哈夫曼树的结构{intweight;intparent;intlchild;intrchild;////////权值双亲左孩子右孩子}htnode,huffmantree[M+1];建立哈夫曼树voidcrthuffmantree(huffmantreeht,intw[],intn)//初始化哈夫曼树{inti,s1,s2,m;for(i=1;i<=n;i++) {ht[i].weight=w[i]; ht[i].parent=0;ht[i].lchild=0;ht[i].rchild=0;}m=2*n-1;for(i=n+1;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++){select(ht,i-1,&s1,&s2);ht[i].weight=ht[s1].weight+ht[s2].weight;ht[s1].parent=i;ht[s2].parent=i;ht[i].lchild=s1;ht[i].rchild=s2;}}typedefchar*huffmancode[N+1];//建立哈夫曼树编码表voidcrthuffmancode(huffmantreeht,huffmancodehc,intn){ char*cd;//新建立一个指针intstart,i,c,p;cd=(char*)malloc(n*sizeof(char))cd[n-1]='\0';//;//分配求一个字符的哈夫曼编码的空间编码结束符for(i=1;i<=n;i++){start=n-1;c=i;p=ht[i].parent;while(p!=0){--start;if(ht[p].lchild==c)cd[start]='0';elsecd[start]='1';c=p;p=ht[p].parent;}hc[i]=(char*)malloc((n-start)*sizeof(char)); strcpy(hc[i],&cd[start]);}free(cd);}select(huffmantreeht,intpos,int*s1,int*s2)//取最小和次小权值{intj,m1,m2;m1=m2=maxint;for(j=1;j<=pos;j++){if(ht[j].weight<m1&&ht[j].parent==0)//定义为双亲为零时才开始求,这样就做到了防止筛选过的重新加入比较列表里{m2=m1;*s2=*s1;*s1=j;m1=ht[j].weight;}elseif(ht[j].weight<m2&&ht[j].parent==0){m2=ht[j].weight;*s2=j;}}}主程序模块intmain(){初始化参数printf("请输入:初始化I;编码E;译码D;印代码文件P;印哈弗曼树T\n");printf("结束请输入Q\n");while(1){//这就是用户输入scanf("%c",&q);if(q=='Q'){break;}if(q=='I'){fpw=fopen("hfmtree.txt","w");ftest=fopen("date.txt","r");printf("请输入密码表,第一位表示密码表大小,之后按空格键开始以紧凑的格式输入编码字母和权值。
哈弗曼编码数据结构实验报告
![哈弗曼编码数据结构实验报告](https://img.taocdn.com/s3/m/e064fcbbc9d376eeaeaad1f34693daef5ef713c6.png)
数据结构实验报告----约瑟夫环一、需求分析:约瑟夫环是程序的一道经典例题,可以使用数据结构的单链表进行编写。
二、概要设计:大体上可以使用单链表通过节点的创建和删除来达到人数出列的效果,可以大大缩短程序量。
三、详细设计:1、首先定义一个单链表,然后分别做创建链表、以及对应的输入数据,删除节点对应的删除数据,以及输出功能。
最后用主函数实现上述功能。
下为程序源代码:#include<stdio.h>#include<malloc.h>typedef struct Lnode //创建一个单链表{int num;int key;struct Lnode *next;}Joseph;struct Lnode *head,*p,*p1;int creatlinklist(int n) //为节点分配内存,创建节点{int i=0;head = (struct Lnode*)malloc(sizeof(struct Lnode));if(!head){return 0;}p=head;for(i = 0;i<n-1;i++){p1=(struct Lnode*)malloc(sizeof(struct Lnode));if(!p1){return 0;}p->next=p1;p=p1;}p->next=head;p1=head;return 0;}int input(int n) //在分配的节点上输入数据{int i=0;int j=0;printf("please input the keys:\n");for(i =1;i<n+1;i++){scanf("%d",&j);p1->num=i;p1->key=j;p1=p1->next;}p1=p;return j;}int output(int m,int n) \\在约瑟夫环的规定上输出数据删除节点{int i=0;int a=0;for(i =0;i <n;i++){for(a=0;a<m-1;a++){p1=p1->next;}p=p1->next;m=p->key;printf("%d\n",p->num);p1->next=p->next;free(p);}return 0;}void main(){int m=0;int n=0;printf("请输入上限值和人数值:\n");scanf("%d%d",&m,&n);creatlinklist(n);input(n);printf("出对的人:\n");output(m,n);}四、调试分析:程序仅能使用一次,并且输入格式没有提示,容易犯错。
哈夫曼树实验报告
![哈夫曼树实验报告](https://img.taocdn.com/s3/m/ca3964231611cc7931b765ce05087632311274d8.png)
哈夫曼树实验报告一、需求分析(1)输入输出形式输入数组的组数n: 整形变量组数(回车)请依次输入n组权值与字符, 中间用空格隔开。
如“2 a”:按右提示格式输入(回车)请输入待编译文本: 随机输入字符(回车)输出: 编译出的代码请输入待编译代码: 随机输入一串代码(回车)(2)输出: 编译出的代码(3)程序功能1. 用C语言实现二叉树的说明2. 输入n个权值, 并生成n个二叉树3. 对n个二叉树逐步生成Huffman树4. 对Huffman树的每个叶子结点生成编码5.用哈夫曼树编码。
6.解码哈夫曼编码。
(4)测试用例设计Example1: 输入325 a15 b60 cabbacc010*******输出010*******abbaccExample2: 输入510 a20 b30 c20 d10 eababcde10000100001101101输出10000100001101101ababcde二、概要设计1.根据给定的n个权值(w1, w2, …, wn)构成n棵二叉树的集合F={T1, T2, …, Tn}, 其中每棵二叉树Ti中只有一个带树为Ti的根结点在F中选取两棵根结点的权值最小的树作为左右子树构造一棵新的二叉树, 且置其根结点的权值为其左右子树权值之和3.在F中删除这两棵树, 同时将新得到的二叉树加入F中4.重复2, 3, 直到F只含一棵树为止三、 5.将给定的字符串通过程序编码成哈夫曼编码, 并打印结果在屏幕上。
四、 6.翻译给定的哈夫曼编码变成可读字符串, 并将结果打印在屏幕上。
五、详细设计四、调试分析(1)编译代码、运行代码所遇到的问题及其解决办法问题1: 编译代码过程中有遇到循环体的循环次数不对, 导致二叉树生成得不对解决办法:通过小数字的演算, 检验循环, 再进行更改(2)算法的时空分析(3)心得体会五、用户使用说明如上图所示, 依次输入组数、权值及全值所对应字符。
再根据用户自身需求输入需编译的文本及代码。
哈夫曼实验报告材料(附代码)
![哈夫曼实验报告材料(附代码)](https://img.taocdn.com/s3/m/c5cfc6742cc58bd63086bd5d.png)
哈弗曼编码/译码器一、程序的功能分析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.主模块的流程及各子模块的主要功能主函数负责提供选项功能,循环调控整个系统。
创建模块实现接收字符、权值、构建哈夫曼树,并保存文件,此功能是后续功能的基础。
编码模块实现利用已编好的哈夫曼树对每个字符进行哈夫曼编码,即对每个字符译出其密文代码,并保存文件。
译码模块实现对用户输入的密文翻译成明文,即用户所需的字符串信息。
输出模块实现对已编好的哈夫曼树以凹入表的的形式输出。
2、模块之间的层次关系1.采用c语言定义的相关数据类型(1)结点的类型定义描述如下:#define N 叶子结点的个数typedef strcut{int weight; /*结点权值*/int parent;int lchild;int rchild;}HNodeType;HNodeType HNode[2*N-1];(2)编码的类型定义描述如下:#define MAXBIT 10typedef struct{int bit[MAXBIT];int start;}HCodeType;HCodeType HCode[N];2.各模块伪算法(1)主函数int main(){do:{界面友好设计;cout<<各个选项功能容;cin>>ch;容错处理;switch(ch){case 1:.....}}while();return 0;}(2)系统初始化模块void create() //系统初始化{for(i=0;i<2*N-1;i++) //数组HNode初始化{};从键盘接收字符;for(i=0;i<N;i++){ cout<<"输入字符"<<endl;cin>>HNode[i].data;}接收权值;构造哈夫曼树;for(i=0;i<N-1;i++){ 找最小和次小两个权值;将找出的两棵子树合并为一棵子数;}将已建好的哈夫曼树存入文件hfmtree.txt中;调用哈夫曼编码子函数;}void HaffmanCode() //对哈夫曼树进行编码{从hfmtree.txt文件中读出哈夫曼树的信息存入存HNodeType a[2*N-1];求每个叶子结点的哈夫曼编码;for(i=0;i<N;i++){从叶节点回溯,回溯到根结点(parent==-1);记录回溯路径;}打印出每个字符对应的密文;将密文信息存入文件codefile.dat中;}(3)编码模块void HfmanCode() //对用户输入的字符串进行编码{提示输入信息;接收用户输入的要编译的字符串;cin>>s;//从文件中读取哈夫曼编码信息infile.open ("F:\\codefile.dat",ios::in|ios::binary); //读文件for(i=0;i<N;i++) //将文件中的数据读出放在temp[i]//从文件中读字节到指定的存储器区域。
哈夫曼编码实验报告
![哈夫曼编码实验报告](https://img.taocdn.com/s3/m/8ab5371bb7360b4c2e3f6440.png)
数据结构实验报告实验名称:实验三——哈夫曼编码学生姓名:牛佳宁班级:2010211107班内序号:27学号:10210213日期:2011年12月10日1.实验要求利用二叉树结构实现赫夫曼编/解码器。
1、读入一串字符,统计字符个数及权值。
2、建立哈夫曼树。
3、根据哈夫曼树建立哈夫曼表。
4、将字符串进行编码。
5、输入一串01数,进行解码。
2. 程序分析2.1 存储结构哈夫曼树为正则二叉树,有n个叶子的哈夫曼树共有2n-1个结点,可以用一个大小为2n-1的数组来储存哈夫曼树的各个结点,如图对应的编码表可用如图所示结构2.2 关键算法分析一、创建哈夫曼树1、根据权值初始化哈夫曼树for(int i=0;i<n;i++){HTree[i].weight=a[i];HTree[i].LChild=-1;HTree[i].RChild=-1;HTree[i].parent=-1;}2、开始建立哈夫曼树,int x,y;for (int i=n;i<2*n-1;;i++){selectMin(x,y,o,i);//从1到i选择两个权值最小的HTree[x].parent=HTree[y].parent=i;HTree[i].weight=HTree[x].weight+HTree[y].weight;HTree[i].LChild=x;HTree[i].parent=-1;}二、建立哈夫曼编码表void Huffman::CreateCodeTable(char b[],int n){HCodeTable=new HCode [n];for (int i=0;i<n;i++){HCodeTable[i].data=b[i];//生成编码表int child=i;int parent=HTree[i].parent;int k=0;while (parent!=-1){if(child==HTree[parent].LChild)HCodeTable[i].code[k]='0';//左孩子标‘0’;elseHCodeTable[i].code[k]='1';//右孩子标‘1’;k++;child=parent;parent=HTree[child].parent;}HCodeTable[i].code[k]='\0';char*b=new char[k];//将编码字符逆置,再初始化一个数组倒着储存编码数组,再将该数组重新赋给编码数组for(int j=0;j<k;j++){b[j]=HCodeTable[i].code[k-1-j];}for(int jj=0;jj<k;jj++){HCodeTable[i].code [jj]=b[jj];}}}三、编码函数:根据编码表进行编码,从编码表中第一个开始遍历,若找到要编码的字符则输出编码,并进行下一个字符的查找void Huffman::Encode(char*s,int n){while(*s!='\0'){for(int i=0;i<n;i++){if(*s==HCodeTable[i].data){cout<<HCodeTable[i].code;s++;}}}cout<<endl;}四、解码:利用哈夫曼树进行解码,编码串左到右依次逐位判断,从根结点开始根据每一位是0还是1,确定是左分支还是右分支,直到到叶子节点为止,从编码表中找到对应字符并输出void Huffman::Decode(char*s,char*d,int n)//s为编码串,{while(*s!='\0'){int parent=2*n-1-1;//根节点在HTree中的下标;while(HTree[parent].LChild!=-1){if(*s=='0')parent=HTree[parent].LChild;elseparent=HTree[parent].RChild;s++;}*d=HCodeTable[parent].data;cout<<*d;d++;}cout<<endl;}五、利用STL中的排序函数选择两个权值最小结点int Huffman::SelectMin(int x,y,o,i)//选择两个最小的{list <int>ilist;for(int j=0;j<i;j++){if(HTree[j].parent=-1)ilist.push_back(HTree[j].weight);}ilist.sort();list<int>::iterator it=ilist.begin();x=*it;y=*++it;return x,y;}六、建立数组不重复的储存字符并且统计出现次数即权值:利用循环链表来实现,每插入一个结点之前先定义节点指针指向第一个结点,边向后移动边比较储存的字符是否相同,若相同则使该节点权值加一,不同则将该节点加入到循环链表中,直到遍历整个字符串,代码如下void Linklist::Construct(char s[])//建立循环链表存放字符串{rear=new Node;rear->next=rear;for(unsigned int i=0;i<strlen(s);i++){if(rear->next==rear)//放入第一个字符{Node *p=new Node;p->data=s[0];p->weight=1;p->next=rear->next ;rear->next=p;rear=p;}else{Node *q=rear->next->next;//q 指向第一个字符while(q!=rear->next )//遍历链表看q 存储的字符是否有与要插入的字符相同的{if(q->data==s[i]){q->weight++;//若有则权值加一break;}elseq=q->next;}if(q==rear->next )//若链表中无与要插入字符相同的字符,则将该字符使用头插法插入{Node *r=new Node;r->data=s[i];r->weight=1;r->next =rear->next ;rear->next =r;rear=r;}} }}时间复杂度计算:select 函数的时间复杂度为O(n),则建立哈夫曼树的时间按复杂度为O(n^2)建立哈夫曼编码表的时间复杂度为O(n)。
哈夫曼树实验实验报告(3篇)
![哈夫曼树实验实验报告(3篇)](https://img.taocdn.com/s3/m/3f3a6e7d6ad97f192279168884868762caaebbcb.png)
第1篇一、实验目的1. 理解哈夫曼树的基本概念和构造方法。
2. 掌握哈夫曼编码和译码的原理及实现过程。
3. 熟练运用哈夫曼树解决实际问题,提高数据压缩效率。
二、实验环境1. 操作系统:Windows 102. 编程语言:C++3. 开发环境:Visual Studio 2019三、实验内容1. 构造哈夫曼树2. 哈夫曼编码3. 哈夫曼译码四、实验步骤1. 数据准备(1)创建一个包含字符及其权值的数组,例如:`{'a', 5, 'b', 9, 'c', 12, 'd', 13, 'e', 16, 'f', 45}`。
(2)根据数组内容,使用C++编写程序,实现以下功能:- 将数组元素插入到最小堆中。
- 构建哈夫曼树。
2. 哈夫曼编码(1)遍历哈夫曼树,记录每个字符的编码。
(2)根据编码规则,将字符和编码存储在映射表中。
(3)将映射表输出到文件中。
3. 哈夫曼译码(1)从文件中读取编码序列。
(2)根据哈夫曼树,逐个解码字符。
(3)将解码后的字符输出到文件中。
五、实验结果1. 哈夫曼树```45/ \16 29/ \ / \13 3 12 4/ \ / / \d c b a f```2. 哈夫曼编码```a: 0b: 100c: 101d: 110e: 111f: 1```3. 编码前后的数据```原始数据:abcdef编码后数据:0100110110111011```六、实验分析1. 哈夫曼树通过构建哈夫曼树,可以将权值较小的字符分配较短的编码,权值较大的字符分配较长的编码,从而提高数据压缩效率。
2. 哈夫曼编码哈夫曼编码是一种前缀编码,可以保证解码过程不会产生歧义。
3. 哈夫曼译码通过哈夫曼树,可以快速地将编码序列解码为原始数据。
七、实验总结1. 通过本次实验,掌握了哈夫曼树的基本概念、构造方法、编码和译码原理。
哈弗曼树实验报告(3篇)
![哈弗曼树实验报告(3篇)](https://img.taocdn.com/s3/m/836c05a22dc58bd63186bceb19e8b8f67c1cef3d.png)
一、实验目的1. 理解并掌握哈弗曼树的构建原理。
2. 学会使用哈弗曼树进行数据编码和解码。
3. 了解哈弗曼编码在数据压缩中的应用。
二、实验原理哈弗曼树(Huffman Tree)是一种带权路径长度最短的二叉树,用于数据压缩。
其基本原理是:将待编码的字符集合按照出现频率从高到低排序,构造一棵二叉树,使得叶子节点代表字符,内部节点代表编码,权值代表字符出现的频率。
通过这棵树,可以生成每个字符的编码,使得编码的平均长度最小。
三、实验环境1. 操作系统:Windows 102. 编程语言:C++3. 开发工具:Visual Studio 2019四、实验步骤1. 构建哈弗曼树(1)创建一个结构体`HuffmanNode`,包含字符、权值、左子树和右子树指针。
```cppstruct HuffmanNode {char data;int weight;HuffmanNode left;HuffmanNode right;};(2)定义一个函数`HuffmanTree()`,用于创建哈弗曼树。
```cppHuffmanNode HuffmanTree(std::vector<char>& chars, std::vector<int>& weights) {// 创建初始二叉树std::vector<HuffmanNode> trees;for (int i = 0; i < chars.size(); ++i) {trees.push_back(new HuffmanNode{chars[i], weights[i], nullptr, nullptr});}// 构建哈弗曼树while (trees.size() > 1) {// 选择两个权值最小的节点auto it1 = std::min_element(trees.begin(), trees.end(),[](HuffmanNode a, HuffmanNode b) {return a->weight < b->weight;});auto it2 = std::next(it1);HuffmanNode parent = new HuffmanNode{0, it1->weight + it2->weight, it1, it2};// 删除两个子节点trees.erase(it1);trees.erase(it2);// 将父节点添加到二叉树集合中trees.push_back(parent);}// 返回哈弗曼树根节点return trees[0];}```2. 生成哈弗曼编码(1)定义一个函数`GenerateCodes()`,用于生成哈弗曼编码。
哈夫曼编码解码实验报告
![哈夫曼编码解码实验报告](https://img.taocdn.com/s3/m/52a3ad48ee06eff9aef807e1.png)
哈夫曼编码解码实验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.实验总结通过本次实验,对二叉树的应用有了相应的了解,掌握了如何构造哈夫曼编码,如何对编码结果进行解码。
数据结构 哈夫曼编码实验报告(2023版)
![数据结构 哈夫曼编码实验报告(2023版)](https://img.taocdn.com/s3/m/1c1fa10c42323968011ca300a6c30c225801f077.png)
数据结构哈夫曼编码实验报告实验目的:本实验旨在了解和实现哈夫曼编码算法,通过将字符转换为对应的哈夫曼编码来实现数据的压缩和解压缩。
一、引言1.1 背景介绍哈夫曼编码是一种基于字符出现频率的编码方法,通过使用不等长编码来表示不同字符,从而实现数据的高效压缩。
该编码方法在通信、存储等领域有着广泛的应用。
1.2 目标本实验的目标是实现哈夫曼编码算法,通过对给定文本进行编码和解码,验证哈夫曼编码的有效性和可靠性。
二、实验过程2.1 数据结构设计在实现哈夫曼编码算法时,我们需要设计合适的数据结构来存储字符和对应的编码。
常用的数据结构包括树和哈希表。
我们将使用二叉树作为数据结构来表示字符的编码。
2.2 构建哈夫曼树哈夫曼树是由给定字符集合构建而成的最优二叉树。
构建哈夫曼树的过程分为两步:首先根据字符出现频率构建叶子节点,然后通过合并叶子节点和父节点构造哈夫曼树。
2.3 哈夫曼编码表根据构建好的哈夫曼树,我们可以对应的哈夫曼编码表。
哈夫曼编码表由字符和对应的编码组成,可以用于字符的编码和解码。
2.4 文本压缩利用的哈夫曼编码表,我们可以对给定的文本进行压缩。
将文本中的字符逐个替换为对应的哈夫曼编码,从而实现数据的压缩。
2.5 文本解压缩对压缩后的数据进行解压缩时,我们需要利用的哈夫曼编码表,将哈夫曼编码逐个替换为对应的字符,从而还原出原始的文本数据。
三、实验结果我们使用不同长度、不同频率的文本进行了实验。
实验结果表明,哈夫曼编码在数据压缩方面有着显著的效果,可以大大减小数据存储和传输的开销。
四、实验总结通过本实验,我们深入理解了哈夫曼编码算法的原理和实现过程,掌握了数据的压缩和解压缩技术。
哈夫曼编码作为一种经典的数据压缩算法,具有重要的理论意义和实际应用价值。
附件:本文档附带哈夫曼编码实验的源代码和实验数据。
法律名词及注释:在本文档中,涉及的法律名词和注释如下:1.哈夫曼编码:一种数据压缩算法,用于将字符转换为可变长度的编码。
哈夫曼编码实验报告
![哈夫曼编码实验报告](https://img.taocdn.com/s3/m/4b34e6a4866fb84ae45c8df1.png)
哈夫曼编码实验报告①问题描述:给定n个字符的权值数组w,根据哈夫曼编码与译码规则,实现一个哈夫曼编/译码系统(利用实验指导书上的27个字符的数据进行实验)。
②利用顺序表存储Huffman树,编码结果的存储方式采用书上的结构。
③Huffman树的构造约定如下:根的权值较小的子树作为左子树,当权值相等时,则先生成的子树是左子树;按照结点的生成次序选择权值较小的两棵子树构造Huffman树;从叶子结点到根结点逆向求出每个字符的Huffman编码,不采用递归方法;从根结点开始实现译码,要求被译码的字符数大于20个字符。
④采用文件方式存储n个权值和待翻译的二进制代码,其余数据均不采用文件存储。
序号字符权值双亲结点左孩子右孩子1 □186 0 0 02 A 64 0 0 03 B 13 0 0 04 C 22 0 0 05 D 32 0 0 06 E 103 0 0 07 F 21 0 0 08 G 15 0 0 09 H 47 0 0 010 I 57 0 0 011 J 1 0 0 012 K 5 0 0 013 L 32 0 0 014 M 20 0 0 015 N 57 0 0 016 O 63 0 0 017 P 15 0 0 018 Q 1 0 0 019 R 48 0 0 020 S 51 0 0 021 T 80 0 0 022 U 23 0 0 023 V 8 0 0 024 W 18 0 0 025 X 1 0 0 026 Y 16 0 0 027 Z 1 0 0 0实验过程与结果完整代码:(实验环境codeblock)关闭程序,重新开始,此时选择读取文件方式构建哈夫曼树,文件hafuman.txt中存储着各叶子节点权值,对应字符和待编译的二进制编码,读取文件截图如下,其他操作6.7.8及结果同上。
哈夫曼树和哈夫曼编码——实验报告
![哈夫曼树和哈夫曼编码——实验报告](https://img.taocdn.com/s3/m/b3dc23b548d7c1c709a14589.png)
实验报告学生姓名 学号专业 年级、班级课程名称 实验项目 排队系统的模拟 实验类型✓ 综合实验时间 年 月 日实验指导老师 实验评分1、实验项目名称哈夫曼树和哈夫曼编码2、实验目的及要求掌握哈夫曼树和哈夫曼编码的实现3、实验内容及步骤(1)新建一个工程——Win32 Console Application,为工程取名——创建一个简单的程序【S】(2)进入类视图,添加类——鼠标右键,点击New Class——输入类的名称,点击确定。
(3)将对应代码放入对应文件——5-13代码放入 hfTree.h文件;5-14、5.15代码放入hfTree.cpp文件;5-16代码放入幂函数文件ex 007.cpp。
(//后绿色的字是在分析代码)(4)组建、编译,运行结果4、实验结果及分析5-13 哈夫曼树类的定义代码分析template <class Type>//模板类class hfTree{private:struct Node//数组中的元素类型:一个结点{ Type data;//结点值int weight;//结点的权值int parent,left,right;//父结点以及左右儿子的下标地址};Node *elem;//定义一个数组,elem是数组的起始位置,哈夫曼树被保存在一个数组中int length;//数组的规模长度public:struct hfCode{//保存赫夫曼编码的类型Type data;//待编码的字符string code;//对应的哈夫曼编码};hfTree(const Type*x,const int*w,int size);//构造函数,构造函数接收一组待编码的字符以及对应的权值,构造一棵哈夫曼树void getCode(hfCode result[]);//返回哈夫曼编码的函数~hfTree(){delete []elem;}//析构函数,释放存储空间};5-14 哈夫曼树的构造函数代码分析template <class Type>hfTree<Type>::hfTree(const Type*v,const int *w,int size)//哈夫曼树的构造函数,有3个参数,一组待编码的符号,符号对应的权值,前面两个数组的数组规模{ const int MAX_INT=32767;int min1,min2;//最小树、次小树的权值int x,y;//最小树、次小树的下标length=2*size;//保存哈夫曼树的数组规模是符号数组、权值数组的两倍elem=new Node[length];//申请一个保存哈夫曼树的数组for(int i=size;i<length;++i)//for循环为数组赋初值{ elem[i].weight=w[i-size];//将待编码的符号对应的权值放到数组的后半部分elem[i].data=v[i-size];//将待编码的符号放到数组的后半部分 elem[i].parent=elem[i].left=elem[i].right=0;//将符号的父结点以及左右儿子都设为0,表明它们都是只有根结点的树}for(i=size-1;i>0;--i)//for循环完成size-1次的归并{ min1=min2=MAX_INT;x=y=0;// min1,min2分别保存两棵权值最小的数的权值,x、y分别表示这两棵树的树根在数组中的下标for(int j=i+1;j<length;++j)//找出父结点为0,且权值最小和次小的两棵树,等待归并的两棵树if(elem[j].parent==0)if(elem[j].weight<min1){min2=min1;min1=elem[j].weight;x=y;y=j;}else if(elem[j].weight<min2){min2=elem[j].weight;x=j;}elem[i].weight=min1+min2;//归并这两棵树,形成新树i,i这棵树的权值=min1+min2(分别保存挑选出的两棵权值最小的树的权值) elem[i].left=x;elem[i].right=y;elem[i].parent=0;//将挑选出来的两个结点作为左、右子树,构建一棵新树,i为根结点elem[x].parent=i;elem[y].parent=i;//i是挑选出来的两个结点的父结点}}5-15 哈夫曼的getCode函数代码分析template <class Type>void hfTree<Type>::getCode(hfCode result[])//哈夫曼树的getCode函数,返回的是一个数组,数组元素类型是hfCode,每一个元素包含待编码的符号和它对应的编码,编码是一个比特串,用字符串类型表示{ int size=length/2;//符号数组规模=哈夫曼数组规模/2int p,s;//s是追溯过程中正在处理结点的下标,p是s的父结点下标for(int i=size;i<length;++i)//读取每一个符号{result[i-size].data=elem[i].data; // result数组中第一个元素符号是哈夫曼数组elem中间的元素符号,因为哈夫曼数组elem包含了元素符号数组和元素符号权值数组,而符号数组规模=权值数组规模,所以哈夫曼数组elem数组是它们的两倍。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
哈弗曼编码/译码器一、程序的功能分析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.主模块的流程及各子模块的主要功能主函数负责提供选项功能,循环调控整个系统。
创建模块实现接收字符、权值、构建哈夫曼树,并保存文件,此功能是后续功能的基础。
编码模块实现利用已编好的哈夫曼树对每个字符进行哈夫曼编码,即对每个字符译出其密文代码,并保存文件。
译码模块实现对用户输入的密文翻译成明文,即用户所需的字符串信息。
输出模块实现对已编好的哈夫曼树以凹入表的的形式输出。
2、模块之间的层次关系四、详细设计1.采用c语言定义的相关数据类型(1)结点的类型定义描述如下:#define N 叶子结点的个数typedef strcut{int weight; /*结点权值*/int parent;int lchild;int rchild;}HNodeType;HNodeType HNode[2*N-1];(2)编码的类型定义描述如下:#define MAXBIT 10typedef struct{int bit[MAXBIT];int start;}HCodeType;HCodeType HCode[N];2.各模块伪算法(1)主函数int main(){do:{界面友好设计;cout<<各个选项功能内容;cin>>ch;容错处理;switch(ch){case 1:.....}}while();return 0;}(2)系统初始化模块void create() //系统初始化{for(i=0;i<2*N-1;i++) //数组HNode初始化{};从键盘接收字符;for(i=0;i<N;i++){ cout<<"输入字符"<<endl;cin>>HNode[i].data;}接收权值;构造哈夫曼树;for(i=0;i<N-1;i++){ 找最小和次小两个权值;将找出的两棵子树合并为一棵子数;}将已建好的哈夫曼树存入文件hfmtree.txt中;调用哈夫曼编码子函数;}void HaffmanCode() //对哈夫曼树进行编码{从hfmtree.txt文件中读出哈夫曼树的信息存入内存HNodeType a[2*N-1];求每个叶子结点的哈夫曼编码;for(i=0;i<N;i++){从叶节点回溯,回溯到根结点(parent==-1);记录回溯路径;}打印出每个字符对应的密文;将密文信息存入文件codefile.dat中;}(3)编码模块void HfmanCode() //对用户输入的字符串进行编码{提示输入信息;接收用户输入的要编译的字符串;cin>>s;//从文件中读取哈夫曼编码信息infile.open ("F:\\codefile.dat",ios::in|ios::binary); //读文件for(i=0;i<N;i++) //将文件中的数据读出放在temp[i]内//从文件中读字节到指定的存储器区域。
infile.read ((char*)&temp[i],sizeof(temp[i]));循环实现将用户输入的字符串转换成对应的密文,并保存;将保存结果存入密文文件;}(4(5五、调试分析1.调试过程中遇到的问题和对问题的解决方法对文件的读写操作不熟悉,调试时,将已写入的文件不能读出,以至于后续操作无法实现,对此,我有翻看C++程序设计课本,了解关于文件操作的具体内容,明白二进制文件和文本文件的读写方式是有很大区别的,不可混淆操作。
另外,对于程序的输出阶段开始时出现了问题,递归调用没有分析清楚,递归思想是层次分明,逐层深入。
2.算法的时间复杂度(1)创建模块O(N^3)(2)编码模块O(N)(3)译码模块O(n)其中n为用户输入的密文位数(4)打印模块O(N)六、使用说明及测试结果用户根据提示信息,初次使用本系统时要首先选择创建选项来初始化系统,根据提示信息输入信息,存入文件,使得后续功能顺利实现。
非初次使用时,用户可根据自己的需求来选择功能选项,根据提示信息输入、获得所需信息。
测试: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.自行选定一段英文文本,统计给出的字符集,实际统计字符的频度,建立哈夫曼树,构造哈夫曼编码,并实现其编码和译码。
4.可实现多个编码文件共存以及容错处理七、程序代码#include<iostream.h>#include<iomanip.h>#include<fstream.h>#include<string.h>#define N 7 //叶子结点的个数#define MAXBIT 50 //编码位数#define Maxvalue 100 //定义最大权值整数常量//结点的类型定义描述如下:typedef struct{char data;int weight; /*结点权值*/ int parent;int lchild;int rchild;}HNodeType;HNodeType HNode[2*N-1];//编码类型描述如下:typedef struct{int bit[MAXBIT];int start;char s;}HCodeType;HCodeType HCode[N];//密文格式类型typedef struct{int code[MAXBIT];int num;}CD;void create();void HaffmanCode();void print();void print_t(HNodeType temp[],HNodeType T,int h);void translate();void HfmanCode();char name[50][30];//用来记录用户输入的密文文件int filenum=0;int textnum=0;int main(){char ch;int h=1;HNodeType *pNode;pNode=HNode;do{cout<<setw(60)<<" "<<endl;cout<<setw(60)<<"--------- 欢迎进入系统!--------------"<<endl;cout<<setw(50)<<"1:初始化编译系统"<<endl<<setw(40)<<"2:编码"<<endl<<setw(40)<<"3:译码"<<endl<<setw(48)<<"4:打印哈弗曼树"<<endl<<setw(40)<<"5:退出"<<endl;cout<<setw(60)<<"--------------------------------------"<<endl;cout<<" 请选择(0~5):";cin>>ch;while(!(ch<='5'&&ch>='0')) /*输入不在0到5之间无效*/{cout<<" 数据输入错误,请重新选择(0~7):";cin>>ch;}switch(ch){case '1': create(); break; //系统初始化,构造哈夫曼树case '2': HfmanCode(); break; //对哈夫曼树进行编码case '3': translate(); break; //译码case '4': print(); //将哈夫曼树以凹入表的形式输出case '5': break;}}while(ch!='5');return 0;}void create() //模块一,系统初始化{fstream outfile;int i,j;int m1,m2,x1,x2;for(i=0;i<2*N-1;i++) //数组HNode初始化{HNode[i].data='\0';HNode[i].weight=0;HNode[i].parent=-1;HNode[i].lchild=-1;HNode[i].rchild=-1;}cout<<"分别输入"<<N<<"个叶子结点的字符。
"<<endl; //从键盘接收叶子节点的权值for(i=0;i<N;i++){cout<<"输入字符"<<endl;cin>>HNode[i].data;}cout<<"分别输入"<<N<<"个与字符对应的权值。