实验6:哈夫曼树及哈夫曼编码的算法实现 - 副本
- 格式:doc
- 大小:55.00 KB
- 文档页数:4
《数据结构》实验报告书实验内容:哈夫曼树与哈夫曼编码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”(也可自己设定数据进行测试)。
实验五哈夫曼树和哈夫曼树编码学院专业班学号姓名一.实习目的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);// 输出哈夫曼树的每个结点的权值、父亲结点序号、左孩子和右孩子序号。
实验:哈夫曼树编码及译码的实现一.实验题目给定字符集的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这就走向该结点的右结点,重复上面步骤。
c语言哈夫曼树哈夫曼编码哈夫曼树(Huffman Tree)和哈夫曼编码(Huffman Coding)是由戴维·哈夫曼在1952年为数据压缩应用而发明的。
哈夫曼编码是一种前缀编码,即任何字符的编码都不是另一个字符的编码的前缀。
在编码学中,哈夫曼编码是一种可变长度编码,其中较常见或较频繁的字符使用较短的编码,而较少见或较不频繁的字符使用较长的编码。
这种编码是由哈夫曼树生成的,哈夫曼树是一种特殊的二叉树,其每个节点的权重等于其左子树和右子树的权重之和。
在C语言中实现哈夫曼树和哈夫曼编码可能涉及以下步骤:1、定义哈夫曼树的节点结构。
每个节点可能包括字符,权重(或频率),以及左孩子和右孩子的指针。
ctypedef struct huffman_node {char character;unsigned int frequency;struct huffman_node *left, *right;} huffman_node;2、创建哈夫曼树。
首先,你需要计算每个字符的频率,然后根据这些频率创建一个哈夫曼树。
这个过程可能涉及使用优先队列(最小堆)来找出频率最小的两个节点,然后将它们合并为一个新的节点,新节点的频率是这两个节点的频率之和。
然后,将新节点放回队列中,重复这个过程直到队列中只剩下一个节点,这个节点就是你的哈夫曼树的根节点。
3、使用哈夫曼树生成哈夫曼编码。
从根节点开始,对于每个字符,左子树代表0,右子树代表1。
你可以遍历哈夫曼树,为每个字符生成其对应的哈夫曼编码。
4、实现解码。
给定一个哈夫曼编码,你可以通过遍历哈夫曼树来解码它。
对于每个位,如果是0,你跟随左子树,如果是1,你跟随右子树。
当你到达一个叶节点时,你就找到了对应的字符。
以上只是一个大致的步骤,具体的实现可能会根据你的需求和具体情况有所不同。
实验三树的应用一.实验题目:树的应用——哈夫曼编码二.实验内容:利用哈夫曼编码进行通信可以大大提高信道的利用率,缩短信息传输的时间,降低传输成本。
根据哈夫曼编码的原理,编写一个程序,在用户输入结点权值的基础上求哈夫曼编码。
要求:从键盘输入若干字符及每个字符出现的频率,将字符出现的频率作为结点的权值,建立哈夫曼树,然后对各个字符进行哈夫曼编码,最后打印输出字符及对应的哈夫曼编码。
三、程序源代码:#include <iostream.h>#include <fstream.h>#include <string.h>#include <stdlib.h>typedef struct{char data;int weight;int parent,lchild,rchild;}HTNode,*HuffmanTree;typedef char * * HuffmanCode;void Select(HuffmanTree &HT,int n,int m){HuffmanTree p=HT;int tmp;for(int j=n+1;j<=m;j++){int tag1,tag2,s1,s2;tag1=tag2=32767;for(int x=1;x<=j-1;x++){ if(p[x].parent==0&&p[x].weight<tag1){ tag1=p[x].weight;s1=x;}}for(int y=1;y<=j-1;y++){ if(p[y].parent==0&&y!=s1&&p[y].weight<tag2){ tag2=p[y].weight;s2=y;}}if(s1>s2) //将选出的两个节点中的序号较小的始终赋给s1{ tmp=s1; s1=s2; s2=tmp;}p[s1].parent=j;p[s2].parent=j;p[j].lchild=s1;p[j].rchild=s2;p[j].weight=p[s1].weight+p[s2].weight;}}void HuffmanCoding(HuffmanTree &HT,int n,char *w1,int*w2){int m=2*n-1;if(n<=1) return;HT=(HuffmanTree)malloc((m+1)*sizeof(HTNode));HuffmanTree p=HT;for(int i=1;i<=n;i++){ p[i].data=w1[i-1];p[i].weight=w2[i];p[i].parent=p[i].lchild=p[i].rchild=0;}for(;i<=m;i++){ p[i].weight=p[i].parent=p[i].lchild=p[i].rchild=0; }Select(HT,n,m);ofstream outfile; //生成hfmTree文件outfile.open("hfmTree.txt",ios::out);for (i=1;i<=m;i++){outfile<<HT[i].weight<<"\t"<<HT[i].parent<<"\t"<<HT[i].lchild<<"\t"<<HT[i].rchild<<"\t"<<endl;}outfile.close();cout<<"初始化结果已保存在hfmTree文件中\n";}void ToBeTree() //将正文写入文件ToBeTree中{ofstream outfile;outfile.open("ToBeTree.txt",ios::out);outfile<<"THIS PROGRAM IS MYFA VORITE";outfile.close();}void Encoding(HuffmanTree &HT,int n) //编码{HuffmanCode HC;HC=(HuffmanCode)malloc((n+1)*sizeof(char *));char *cd;cd=(char *)malloc(n*sizeof(char));cd[n-1]='\0';for(int k=1;k<=n;k++){ int start=n-1;for(int c=k,f=HT[k].parent;f!=0;c=f,f=HT[f].parent){ if(HT[f].lchild==c) cd[--start]='0';else cd[--start]='1';}HC[k]=(char *)malloc((n-start)*sizeof(char));strcpy(HC[k],&cd[start]);}cout<<"输出哈夫曼编码:"<<endl;for(int h=1;h<=n;h++) //输出编码{ cout<<HT[h].data<<":";cout<<HC[h];cout<<" ";if (h%8==0) cout<<endl;}cout<<endl<<"输出正文编码:"<<endl;ToBeTree();//读取TOBETREE文件里的正文,并进行编码fstream infile;infile.open("ToBeTree.txt",ios::in);char s[80];while(!infile.eof()){infile.getline(s,sizeof(s));}infile.close();fstream outfile;outfile.open("CodeFile.txt",ios::out);int count=0;for (h=0;s[h]!='\0';h++){ for(k=1;k<=n;k++)if (s[h]==HT[k].data){ cout<<HC[k];cout<<" ";count++;outfile<<HC[k];break;}if (count%9==0) cout<<endl; //每输出7个换行}outfile.close();cout<<"\n编码结果已保存在文件CodeFile中.";cout<<endl;}void Decoding(HuffmanTree &HT,int n) //译码{int f=2*n-1;fstream infile;infile.open("CodeFile.txt",ios::in);char s[1000];while(!infile.eof()){infile.getline(s,sizeof(s));}infile.close();int i=0;int j=0;fstream outfile;outfile.open("TextFile.txt",ios::out);while(s[i]!='\0'){ f=2*n-1;while(HT[f].lchild!=0)//以f对应的节点的左孩子的值==0作为结束{if (s[j]=='0') f=HT[f].lchild;else f=HT[f].rchild;j++;}i=j;cout<<HT[f].data;outfile<<HT[f].data;}outfile.close();cout<<"\n译码结果已保存在文件TextFile中.";cout<<endl;}void Print() //印代码文件{ int count=0;fstream infile;infile.open("CodeFile.txt",ios::in);char s[1000];while(!infile.eof()){infile.getline(s,sizeof(s));for(int i=0;s[i]!='\0';i++){ cout<<s[i];count++;if (count%50==0) cout<<endl; //在终端上每行显示50个代码}}infile.close();cout<<endl;}char menu() //菜单函数{ cout<<"功能菜单如下:"<<endl;cout<<"* * * * * * * * * * * * * * * * * * * * *"<<endl;cout<<" I:初始化(Initialization) "<<endl;cout<<" E:编码(Encoding) "<<endl;cout<<" D:译码(Decoding) "<<endl;cout<<" P:印代码文件(Print) "<<endl;cout<<" Q:退出(Exit) "<<endl;cout<<"* * * * * * * * * * * * * * * * * * * * *"<<endl;cout<<"请输入功能字符:";char ch;cin>>ch;return ch;}void main(){ int n;int Array[100];char cArray[100];HuffmanTree HT;cout<<"输入n个字符:";cin.getline(cArray,100);n=strlen(cArray);cout<<"一共"<<n<<"个字符.\n";cout<<"依次输入各个字符的权值:"<<endl;for (int i=1;i<=n;i++) cin>>Array[i];int tag;char x=menu();while(1){ switch (x){case 'I':HuffmanCoding(HT,n,cArray,Array);break;case 'E':Encoding(HT,n);break;case 'D':Decoding(HT,n);break;case 'P':Print();break;case 'Q':tag=0;cout<<"结束"<<endl;break;default:cout<<"你输入错误!"<<endl;}if(tag==0) break;cout<<"y(继续) or n(退出)"<<endl;char ch;cin>>ch;if (ch=='y'){ cout<<"请输入功能字符:";char c;cin>>c;x=c;}else exit(1);}}测试数据:用下表给出的字符集和频度的实际统计数据建立哈夫曼树,并实现以下报文的译码和编码:"THIS PROGRAM IS MY FAVORITE".字符空格 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. 理解哈夫曼树的概念及其在数据结构中的应用。
2. 掌握哈夫曼树的构建方法。
3. 学习哈夫曼编码的原理及其在数据压缩中的应用。
4. 提高编程能力,实现哈夫曼树和哈夫曼编码的相关功能。
二、实验原理哈夫曼树(Huffman Tree)是一种带权路径长度最短的二叉树,又称为最优二叉树。
其构建方法如下:1. 将所有待编码的字符按照其出现的频率排序,频率低的排在前面。
2. 选择两个频率最低的字符,构造一棵新的二叉树,这两个字符分别作为左右子节点。
3. 计算新二叉树的频率,将新二叉树插入到排序后的字符列表中。
4. 重复步骤2和3,直到只剩下一个节点,这个节点即为哈夫曼树的根节点。
哈夫曼编码是一种基于哈夫曼树的编码方法,其原理如下:1. 从哈夫曼树的根节点开始,向左子树走表示0,向右子树走表示1。
2. 每个叶子节点对应一个字符,记录从根节点到叶子节点的路径,即为该字符的哈夫曼编码。
三、实验内容1. 实现哈夫曼树的构建。
2. 实现哈夫曼编码和译码功能。
3. 测试实验结果。
四、实验步骤1. 创建一个字符数组,包含待编码的字符。
2. 创建一个数组,用于存储每个字符的频率。
3. 对字符和频率进行排序。
4. 构建哈夫曼树,根据排序后的字符和频率,按照哈夫曼树的构建方法,将字符和频率插入到哈夫曼树中。
5. 实现哈夫曼编码功能,遍历哈夫曼树,记录从根节点到叶子节点的路径,即为每个字符的哈夫曼编码。
6. 实现哈夫曼译码功能,根据哈夫曼编码,从根节点开始,按照0和1的路径,找到对应的叶子节点,即为解码后的字符。
7. 测试实验结果,验证哈夫曼编码和译码的正确性。
五、实验结果与分析1. 构建哈夫曼树根据实验数据,构建的哈夫曼树如下:```A/ \B C/ \ / \D E F G```其中,A、B、C、D、E、F、G分别代表待编码的字符。
2. 哈夫曼编码根据哈夫曼树,得到以下字符的哈夫曼编码:- A: 00- B: 01- C: 10- D: 11- E: 100- F: 101- G: 1103. 哈夫曼译码根据哈夫曼编码,对以下编码进行译码:- 00101110111译码结果为:BACGACG4. 实验结果分析通过实验,验证了哈夫曼树和哈夫曼编码的正确性。
哈夫曼树及哈夫曼编码的算法实现c语言1.引言1.1 概述哈夫曼树及哈夫曼编码是数据压缩和编码中常用的重要算法。
哈夫曼树由大卫·哈夫曼于1952年提出,用于根据字符出现的频率构建一种最优的前缀编码方式。
而哈夫曼编码则是根据哈夫曼树构建的编码表将字符进行编码的过程。
在现代通信和计算机领域,数据传输和存储中往往需要大量的空间。
为了有效利用有限的资源,减少数据的存储和传输成本,数据压缩成为一个重要的技术。
而哈夫曼树及哈夫曼编码正是数据压缩中常用的技术之一。
哈夫曼树的概念及原理是基于字符的频率和概率进行构建的。
在哈夫曼树中,字符出现频率越高的节点越接近根节点,出现频率越低的节点离根节点越远。
这种构建方式保证了哈夫曼树的最优性,即最小化编码的总长度。
哈夫曼编码的算法实现是根据哈夫曼树构建的编码表进行的。
编码表中,每个字符都与一段二进制编码相对应。
在进行数据压缩和解压缩时,通过查表的方式将字符转化为相应的二进制编码,或将二进制编码解析为原始字符。
本文旨在介绍哈夫曼树及哈夫曼编码的概念和原理,并通过C语言实现算法。
通过深入理解哈夫曼树及哈夫曼编码的实现过程,可以更好地理解数据压缩和编码的原理,为后续的研究和应用提供基础。
接下来,我们将首先介绍哈夫曼树的概念和原理,然后详细讲解哈夫曼编码的算法实现。
最后,我们将总结哈夫曼树及哈夫曼编码的重要性,并提出对哈夫曼树和哈夫曼编码进一步研究的方向。
让我们一起深入探索哈夫曼树及哈夫曼编码的奥秘吧!1.2 文章结构文章结构部分的内容可以包括以下内容:文章结构部分主要介绍了本文的组织结构和各个章节的内容概述,以帮助读者更好地理解全文的逻辑结构和内容安排。
首先,本文包括引言、正文和结论三个部分。
引言部分主要对哈夫曼树及哈夫曼编码的算法实现进行了概述,包括相关的概念、原理和目的。
正文部分则深入介绍了哈夫曼树的概念和原理,以及哈夫曼编码的算法实现。
最后,结论部分对本文的主要内容进行了总结,并提出了对哈夫曼树和哈夫曼编码的进一步研究方向。
1.初始化:从文件(程序运行时,由用户输入)读入字符集大小n,以及n个字符和n个权值,建立哈夫曼树,将它存于文件中。
2.编码:利用已建好的哈夫曼树(如不在内存,则从文件中读入)对文件字符集中的每一个进行编码,将结果放在中。
3.译码:利用已建好的哈夫曼树将中的代码进行译码,结果保存在中。
4.印代码文件。
将文件以紧凑的格式显示在终端上,每行50个代码。
同时将结果保存在中。
二.概要设计:1.哈夫曼树的抽象数据类型定义:ADT haffman{ 数据对象:D={ai|ai为charnode型的结点,i=1,2,3,……n,n>0}数据关系:R={<ai,><ai,>|ai是D上的元素}} ADT haffman2.编码集结构体的抽象数据类型的定义:ADT code{ 数据对象:D1={ai| ai是charlink型的结点,i=1,2,……n,n>0}D2={bi|bi是codelink型的结点,i=1,2,……n,n>0}数据关系: R1={<ai,>|ai是D1上的元素}R2={<bi,>|bi是D2上的元素}} ADT code3.程序分为四个部分:1)读入字符集以及相应频度,建立哈夫曼树。
2)根据哈夫曼树得到每一个字符的哈夫曼编码。
3)读入要编码的字符串,根据哈夫曼树和编码集求出字符串的哈夫曼编码。
4)根据哈夫曼编码和哈夫曼树得到字符串。
三.详细设计:h >> hufW[ ii ].wt;}(); .eight<< setw( 8 ) << hufT[ tOut ].parent<< setw( 8 ) << hufT[ tOut ].lChild<< setw( 8 ) << hufT[ tOut ].rChild << endl;}hufTreeOutPut << "-- end HT --------------------------- " << endl << endl << "-- HC ------------------------------- " << endl;for( int cOut = 1 ; cOut <= hufNum ; cOut++ ){hufTreeOutPut << " " << hufC[ cOut ].ch << " ---->> " << hufC[ cOut ].hufCh << endl;}hufTreeOutPut << "-- convert -- ok -------------------- " << endl;(); t;p->parent = p->lChild = p->rChild = 0; i-1 ]选择parent 为 0 且weight 最小的两个结点,其序号分别为 s1 和 s2arent = i; arent = i; Child = s1; Child = s2; eight =HT[ s1 ].weight + HT[ s2 ].weight; arent ; f != 0 ; c = f , f =HT[ f ].parent ) Child == c ) { cd[ --start ] = '0'; }else { cd[ --start ] = '1'; }}HC[ i ].ch = w[ i-1 ].ch ; ufCh = ( char* ) malloc ( ( n - start ) * sizeof( char ) ); ufCh , &cd[ start ] ); arent != 0 ) continue;else{sm1 = HT[ m ].weight;s1=m;break;}}for( int j = m+1 ; j <= i ; j++ ) arent != 0 ) continue;else{if( sm1 > HT[ j ].weight ){sm1 = HT[ j ].weight;s1 = j;}}}for( m = 1 ; m <= i ; m++ ) arent != 0 ) continue;else{sm2 = HT[ m ].weight;s2=m;if( s2 == s1 ) continue;else break;}}for( int k = m+1 ; k <= i ; k++ ) arent != 0 ) continue;else{if( (HT[ k ].weight < sm2) && ( k != s1 ) ) eight;s2 = k;}}}} ufCh == ' 'fOut << HC[ sub ].hufCh;}else if( inBuf == '\n' ){continue;}else{ufCh == 'A'. 以下的字符雷同sub = inBuf - 63;fOut << HC[ sub ].hufCh;}}HT[p]就为 HT 的根.Child != 0 ) Child; ufCh , cd ) == 0 ){fOut << HC[ iHC ].ch;break; Child; Child != 0 ) Child; ufCh , cd ) == 0 ){fOut << HC[ iHC ].ch;break; Child; ufCh , cd ) == 0 ){fOut << HC[ iHC ].ch;break; ufCh , cd ) == 0 ){fOut << HC[ iHC ].ch;break; 试分析1.本次作业在打印树形结构的时候有点遗憾,其他的都应该做的完美的了。
哈夫曼(huffman)树和哈夫曼编码讨论QQ群:待定哈夫曼树哈夫曼树也叫最优二叉树(哈夫曼树)问题:什么是哈夫曼树?例:将学生的百分制成绩转换为五分制成绩:≥90 分: A,80~89分: B,70~79分: C,60~69分: D,<60分: E。
if (a < 60){b = 'E';}else if (a < 70) {b = ‘D’;}else if (a<80) {b = ‘C’;}else if (a<90){b = ‘B’;}else {b = ‘A’;}判别树:用于描述分类过程的二叉树。
如果每次输入量都很大,那么应该考虑程序运行的时间如果学生的总成绩数据有10000条,则5%的数据需1 次比较,15%的数据需 2 次比较,40%的数据需 3 次比较,40%的数据需 4 次比较,因此 10000 个数据比较的次数为: 10000 (5%+2×15%+3×40%+4×40%)=31500次此种形状的二叉树,需要的比较次数是:10000 (3×20%+2×80%)=22000次,显然:两种判别树的效率是不一样的。
问题:能不能找到一种效率最高的判别树呢?那就是哈夫曼树回忆树的基本概念和术语路径:若树中存在一个结点序列k1,k2,…,kj,使得ki是ki+1的双亲,则称该结点序列是从k1到kj的一条路径。
路径长度:等于路径上的结点数减1。
结点的权:在许多应用中,常常将树中的结点赋予一个有意义的数,称为该结点的权。
结点的带权路径长度:是指该结点到树根之间的路径长度与该结点上权的乘积。
树的带权路径长度:树中所有叶子结点的带权路径长度之和,通常记作:其中,n表示叶子结点的数目,wi和li分别表示叶子结点ki的权值和树根结点到叶子结点ki之间的路径长度。
赫夫曼树(哈夫曼树,huffman树)定义:在权为w1,w2,…,wn的n个叶子结点的所有二叉树中,带权路径长度WPL最小的二叉树称为赫夫曼树或最优二叉树。
数据结构c+python代码6:哈夫曼树构造及编码⾸先介绍⼀下什么是哈夫曼树?给定N个权值作为N个叶⼦结点,构造⼀棵⼆叉树,若该树的带权路径长度达到最⼩,称这样的⼆叉树为最优⼆叉树,也称为哈夫曼树(Huffman Tree)。
哈夫曼树是带权路径长度最短的树,权值较⼤的结点离根较近。
哈夫曼树⼜称为最优树.1、路径和路径长度在⼀棵树中,从⼀个结点往下可以达到的孩⼦或孙⼦结点之间的通路,称为路径。
通路中分⽀的数⽬称为路径长度。
若规定根结点的层数为1,则从根结点到第L层结点的路径长度为L-1。
2、结点的权及带权路径长度哈夫曼树哈夫曼树(3张)若将树中结点赋给⼀个有着某种含义的数值,则这个数值称为该结点的权。
结点的带权路径长度为:从根结点到该结点之间的路径长度与该结点的权的乘积。
3、树的带权路径长度树的带权路径长度规定为所有叶⼦结点的带权路径长度之和,记为WPL。
哈夫曼树的构造假设有n个权值,则构造出的哈夫曼树有n个叶⼦结点。
n个权值分别设为 w1、w2、…、wn,则哈夫曼树的构造规则为:(1) 将w1、w2、…,wn看成是有n 棵树的森林(每棵树仅有⼀个结点);(2) 在森林中选出两个根结点的权值最⼩的树合并,作为⼀棵新树的左、右⼦树,且新树的根结点权值为其左、右⼦树根结点权值之和;(3)从森林中删除选取的两棵树,并将新树加⼊森林;(4)重复(2)、(3)步,直到森林中只剩⼀棵树为⽌,该树即为所求得的哈夫曼树。
c代码过程分析构造哈夫曼树算法的实现可以分成两⼤部分:1、初始化:⾸先动态申请2n个单元;然后循环2n-1次,从1号单元开始,依次将1⾄2n-1所有单元中的双亲、左孩⼦、右孩⼦的下标都初始化为0;最后再循环n次,输⼊前n个单元中叶⼦节点的权值。
2、创建树:循环n-1次,通过n-1次的选择、删除与合并来创建哈夫曼树。
选择是从当前森林中选择双亲为0且权值最⼩的两个树跟节点是s1和s2;删除是指将节点s1和s2的双亲改为⾮0;合并就是将s1和s2的权值和作为⼀个新节点的权值依次存⼊到数组的第n+1之后的单元中,同时记录这个新节点左孩⼦的下标为s1,右孩⼦的下标为s2。
哈夫曼编码算法实现完整版.doc
哈夫曼编码(Huffman Coding)是一种编码方式,它通过对最常出现频率最高的字符
串编码最短的字节,以节省带宽和存储空间。
它可以将字符信息编码为变长的序列,最短
的字符占用的位数就更少,而最长的字符占用的位数则更多。
实现哈夫曼编码步骤:
(1)统计字符串中字符出现的次数,并生成频率表
(2)将每个字符对应的频率以及编码长度(未分配)加入一个哈夫曼树(Huffman Tree)的叶节点集合中
(3)将集合中的叶节点按照哈夫曼编码的原则进行排序,并重新构造哈夫曼树
(4)从根节点开始计算叶节点的哈夫曼编码,并以二进制形式记录:找到从根节点
到叶节点的路径,从根节点出发,左子节点编码为0,右子节点编码为1
(5)最终给出每个字符对应的哈夫曼编码
哈夫曼编码有如下特点:
(1)使用有穷自动机原理:利用“最优子结构”和“贪心算法”的原理,构造符合
条件的哈夫曼树,从而获得哈夫曼编码;
(2)信源编码理论:哈夫曼编码是考虑到信源编码理论的一种应用,它能把信源各
字符的分布概率考虑在内,根据信源各字符分布给出较合理的字符编码,使得信源编码长
度最短;
(3)使用哈夫曼编码能更加有效地利用存储空间;
(4)哈夫曼编码能减少网络传输数据量,加快网络传输速度;
(5)哈夫曼编码的解码有较高的效率,可以采用类似BinarySearch的方式进行搜索,时间复杂度可以以O(log n)的速度进行解码
通过使用哈夫曼编码,能使编码的效率更高,节省大量存储空间和带宽。
此外,它的
实现原理相对较为简单,因此,现有大多数编码解码系统都会支持哈夫曼编码。
实验六 Huffman编码算法实现---2011级通信一班尚青一、实验目的1、加深对压缩理论和技术的理解;2、增进对压缩编码算法的设计和编写能力;3、编写Vc++的Huffman编码;4、编写Matlab函数实现哈夫曼编码的算法。
(3或4选做一个即可)二、实验原理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”;⑥从根节点开始,对符号进行编码;⑦译码时流程逆向进行,从文件中读出哈夫曼树,并利用哈夫曼树将编码序列解码。
四、实验代码及结果function [h,l,hh,t]=huffman(p)%判断输入合不合法if (~isempty(find(p<0, 1)))error('Not a prob,negative component');endif (abs(sum(p)-1)>10e-10)error('Not a prob.vector,component do not add to 1')endn=length(p);q=p; %数组p附给qm=zeros(n-1,n); %创建(n-1)*n矩阵for i=1:n-1[q,l]=sort(q);%对概率数组q 进行从小至大的排序,并且用l 数组返回一个数组,该数组表示概率数组q 排序前的顺序编号m(i,:)=[l(1:n-i+1),zeros(1,i-1)];%由数组l 构建一个矩阵,该矩阵表明概率合并时的顺序,用于后面的编码q=[q(1)+q(2),q(3:n),1];%将排序后的概率数组q 的前两项,即概率最小的两个数加和,得到新的一组概率序列endfor i=1:n-1c(i,:)=blanks(n*n);%生成一个n-1 行n 列,并且每个元素的的长度为n 的空白数组,c 矩阵用于进行huffman 编码并且在编码中与 m矩阵有一定的对应关系endc(n-1,n)='0';%由于c矩阵的第n-1 行的前两个元素为进行huffman 编码加和运算时所得的最c(n-1,2*n)='1';%后两个概率,因此其值为0 或1,在编码时设第n-1 行的第一个空白字符为0,第二个空白字符1。
实验6:哈夫曼树及哈夫曼编码的算法实现-副本实验6:哈夫曼树及哈夫曼编码的算法实现实验所需学时数2学时实验目的1)掌握哈夫曼树的基本概念及其存储结构;2)掌握哈夫曼树的建立算法;3)掌握哈夫曼树的应用(哈夫曼编码和译码)。
实验内容对输入的一串电文字符实现哈夫曼编码,再对哈夫曼编码生成的代码串进行译码,输出电文字符串。
实验所需器材计算机及VC++ 6.0软件内容要求:1、初始化(Init):能够对输入的任意长度的字符串s进行统计,统计每个字符的频度,并建立哈夫曼树2、建立编码表(CreateTable):利用已经建好的哈夫曼树进行编码,并将每个字符的编码输出。
3、编码(Encoding):根据编码表对输入的字符串进行编码,并将编码后的字符串输出。
4、译码(Decoding):利用已经建好的哈夫曼树对编码后的字符串进行译码,并输出译码结果。
测试数据:输入字符串“this*program*is*my*favourite”,完成这28个字符的编码和译码。
实验结果1、演示程序运行结果。
2、说明调试过程中出现的现象学生实验评价依据:优:实验认真、刻苦,有钻研精神,不无故缺席。
良:能认真对待实验,不无故缺席。
中:基本能认真对待实验,不无故缺席。
差:对待实验不够认真,有少量迟到、早退或无故缺席现象。
不及格:对待实验马虎、敷衍,经常迟到、早退或无故缺席。
#include#include#define maxvalue 10000 //定义最大权值常量#define maxnodenumber 100 //定义节点最大数#define maxbit 10 //定义哈弗曼编码最大长度typedef struct{ //定义新数据类型即节点结构int weight; //权重域int parent,lchild,rchild; //指针域}htnode; //节点类型标识符//typedef htnode * huffmanstree; //定义哈弗曼数类型htnode ht[maxnodenumber]; //定义三叉链表存储数组typedef struct {//定义保存一个叶子节点哈弗曼编码的结构int bit[maxbit]; //定义一维数组为编码域int start; //定义位置域}hcnodetype; //定义编码类型htnode * creatstree(int n) //huffmanstree creatstree(int n) //建立哈夫曼树算法实现函数{int i,j,m1,m2,k1,k2; //局部变量for(i=0;i<2*n-1;i++) //初始化各节点{ht[i].weight=0; //权重初始化为0ht[i].parent=-1; //根节点和给左右孩子初始化为-1ht[i].lchild=-1;ht[i].rchild=-1;}for(i=0;i<="">{scanf("%d",&ht[i].weight);}for(i=0;i<="">{m1=maxvalue; //预置最小权值变量为最大权值m2=maxvalue; //预置次小权值变量为最大权值k1=0; //预置最小权值节点位置为下标为0处k2=0; //预置次小权值节点位置为下标为0处for(j=0;j<="">if(ht[j].parent==-1&&ht[j].weight<m1)< p="">{m2=m1;k2=k1;m1=ht[j].weight;k1=j;}else //当小于当前次小m2则更新m2及其位置if(ht[j].parent==-1&&ht[j].weight<m2)< p="">{m2=ht[j].weight;k2=j;}ht[k1].parent=n+i; //修改最小权值节点的双亲为刚生成的新节点ht[k2].parent=n+i; //修改次小权值节点的双亲为刚生成的新节点ht[n+i].weight=ht[k1].weight+ht[k2].weight; //将新生成的权重值填入新的根节点ht[n+i].lchild=k1; //新生节点左孩子指向k1 ht[n+i].rchild=k2; //新生节点右孩子指向k2}return ht; //返回哈夫曼树指针}void getstree(htnode * ht,int n) //哈夫曼编码算法及打印函数的实现{int i,j,c,p; //局部变量的定义hcnodetype cd[maxnodenumber]; //定义存储哈夫曼编码的数组for(i=0;i<="">{c=i; //为编码各节点初始化c和jj=maxbit;do{j--; //j指向bit中存放编码为的正确位置p=ht[c].parent; //p指向c的双亲节点if(ht[p].lchild==c) //如果c是p的左孩子cd[i].bit[j]=0; //编码为赋值0else //否则即c是p的右孩子cd[i].bit[j]=1; //编码赋值1c=p;//更新当前指针,为下一节点编码做准备}while(ht[p].parent!=-1); //判断是否编码结束即循环至最终根节点cd[i].start=j; //编码完成,记下编码开始位置}for(i=0;i<="">{for(j=cd[i].start;j<="">printf("%d",cd[i].bit[j]);printf("\n"); //每输出一编码后换行}}int main() //主函数{int n;printf("请输入节点数:"); //用户输入节点数scanf("%d",&n);htnode * p; // huffmanstree p //定义哈夫曼树类型pp=(htnode * )malloc(sizeof(htnode *));//p=(huffmanstree)malloc(sizeof(huffmanstree))//分配内存空间p=creatstree(n);//调用建立哈夫曼树函数赋返回值给pgetstree(p,n); //调用编码函数读入建立的哈夫曼树p进行编码return 0;}</m2)<></m1)<>。
哈夫曼树及哈夫曼编码的算法实现1. 哈夫曼树的概念和原理哈夫曼树是一种带权路径长度最短的树,也称最优二叉树。
它是由美国数学家大卫・哈夫曼发明的,用于数据压缩编码中。
哈夫曼树的构建原理是通过贪心算法,将权重较小的节点不断合并,直到所有节点都合并成为一个根节点,形成一棵树。
这样构建的哈夫曼树能够实现数据的高效压缩和解压缩。
2. 哈夫曼编码的概念和作用哈夫曼编码是一种可变长度编码,它根据字符在文本中出现的频率来进行编码,频率越高的字符编码越短,频率越低的字符编码越长。
这种编码方式能够实现数据的高效压缩,减小数据的存储空间,提高数据传输的效率。
3. 哈夫曼树和编码的算法实现在实现哈夫曼树和编码的算法过程中,首先需要统计文本中每个字符出现的频率,并根据频率构建哈夫曼树。
根据哈夫曼树的结构,确定每个字符的哈夫曼编码。
利用哈夫曼编码对文本进行压缩和解压缩。
4. 个人观点和理解哈夫曼树及哈夫曼编码算法是一种非常有效的数据压缩和编码方式,能够在保证数据完整性的前提下,减小数据的存储和传输成本。
在实际应用中,哈夫曼编码被广泛应用于通信领域、数据存储领域以及图像压缩等领域。
通过深入理解和掌握哈夫曼树及哈夫曼编码的算法实现,可以为我们在实际工作中处理大量数据时提供便利和效率。
5. 总结与回顾通过本篇文章的详细讲解,我深入了解了哈夫曼树及哈夫曼编码的算法原理和实现方式,对其在数据处理中的重要性有了更深刻的认识。
掌握了哈夫曼树及哈夫曼编码的算法实现,将为我未来的工作和学习提供更多的帮助和启发。
根据您提供的主题,本篇文章按照从简到繁、由浅入深的方式探讨了哈夫曼树及哈夫曼编码的算法实现。
文章共计超过3000字,深入剖析了哈夫曼树和编码的原理、实现方式以及应用场景,并结合个人观点进行了阐述。
希望本篇文章能够满足您的需求,如有任何修改意见或其他要求,欢迎随时告知。
哈夫曼树和哈夫曼编码是一种十分重要的数据压缩和编码方式,它们在实际的数据处理和传输中发挥着非常重要的作用。
哈夫曼实验报告(附代码)以下是为大家整理的哈夫曼实验报告(附代码)的相关范文,本文关键词为哈夫曼,实验,报告,代码,,您可以从右上方搜索框检索更多相关文章,如果您觉得有用,请继续关注我们并推荐给您的好友,您可以在综合文库中查看更多范文。
哈弗曼编码/译码器一、程序的功能分析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.主模块的流程及各子模块的主要功能主函数负责提供选项功能,循环调控整个系统。
创建模块实现接收字符、权值、构建哈夫曼树,并保存文件,此功能是后续功能的基础。
编码模块实现利用已编好的哈夫曼树对每个字符进行哈夫曼编码,即对每个字符译出其密文代码,并保存文件。