哈夫曼编码程序设计
哈弗曼编码及译码算法(包含源程序)
![哈弗曼编码及译码算法(包含源程序)](https://img.taocdn.com/s3/m/1ef7a51bc281e53a5802ffa8.png)
哈夫曼编码一、实验目的1、掌握哈夫曼编码的二叉树结构表示方法;2、编程实现哈夫曼编码译码器;3、掌握贪心算法的设计策略。
二、实验任务①从文件中读取数据,构建哈夫曼树;②利用哈夫曼树,对输入明文进行哈夫曼编码;③利用哈夫曼树,对输入编码译码为明文。
三、实验设计方案1、结构体设计Huffman树:包括字符,权,父亲下标,左孩子下标,右孩子下标2、自定义函数设计①函数原型声明void input(); //读取文件字符、权值数据void huffman(); //建立huffman树void getcode(int i, char *str); //得到单个字符的huffman编码void encode(char ch); //将明文进行huffman编码void decode(char *str); //将huffman编码译为明文3、主函数设计思路:主函数实现实验任务的基本流程。
void main(){char ch;int i;char str[100];huffman(); //建立huffman树printf("请输入明文:"); //输入明文while((ch=getchar())!='\n')encode(ch); //得到huffman编码printf("\n");printf("\n请按字符编码对应表输入密文:\n");for(i=0;i<N;i++) //显示字符编码对应表{printf("%c:",ht[i].c);encode(ht[i].c);printf("\t");}scanf("%s",str); //输入编码串decode(str); //翻译成明文printf("\n");}程序代码:#include<stdio.h>struct shuju{char str;int data;};struct treenode{char c;int w;int f;int l;int r;};void sort(shuju a[],int num) {int i,j;shuju t;for(i=0;i<num;i++){int m=i;for(j=i+1;j<num;j++)if(a[j].data<a[m].data)m=j;t=a[m];a[m]=a[i];a[i]=t;}}void huffman(shuju a[],treenode htree[],int num) {int i,j,k,n;for(i=0; i<num; i++){htree[i].c=a[i].str;htree[i].w=a[i].data;htree[i].l=-1;htree[i].f=-1;htree[i].r=-1;}j=0;k=num;for(n=num;n<2*num-1;n++)htree[n].w=0;for(n=num;n<2*num-1;n++){int r=0,s=0;htree[n].l=-1;htree[n].f=-1;htree[n].r=-1;while(r<2){if((htree[k].w==0 || htree[k].w>htree[j].w) && j<num){ s=s+htree[j].w;if(r==0) htree[n].l = j;else htree[n].r=j;htree[j].f=n;j++;}else{s=s+htree[k].w;if(r==0) htree[n].l = k;else htree[n].r=k;htree[k].f=n;k++;}r++;}htree[n].w=s;}}int getcode(int i, int str[],treenode htree[]){int n,l=0;for(n=i;htree[n].f!=-1;n=htree[n].f){int m=htree[n].f;if(n==htree[m].l)str[l++]=0;elsestr[l++]=1;}return l;}void decode(treenode htree[],int c[],int n,int num){ int ch,m=0;ch=c[m];while(m<n){int i;for(i=2*num-2;htree[i].l!=-1;){if(ch==0)i=htree[i].l;elsei=htree[i].r;m++;ch=c[m];}printf("%c",htree[i].c);}}void main(){int str[1000],i,j,k,l,n,c[1000];FILE *fp;treenode htree[57];shuju a[29];char b[100];printf("请输入明文的长度n:");scanf("%d",&n);printf("请输入明文:");for(i=0;i<=n;i++)scanf("%c",&b[i]);fp=fopen("D:\\hanfuman\\shuju.txt","r"); for( i=0;i<29;i++){fscanf(fp,"%c%d\n",&a[i].str,&a[i].data);}fclose(fp);sort(a,29);huffman(a,htree,29);printf("输出译码是:");for(i=0;i<=n;i++){for(j=0;j<29;j++){if(b[i]==a[j].str){l=getcode(j,str,htree);for(k=l-1;k>=0;k--)printf("%d",str[k]);}}}printf("\n");printf("请输入译码的长度n:"); scanf("%d",&n);printf("请输入译码:");for(i=0;i<n;i++)scanf("%d",&c[i]);printf("输出解码为:");decode(htree,c,n,29);printf("\n");}D:\\hanfuman\\shuju.txt中的内容为:j 217z 309q 343x 505k 1183w 1328v 1531f 1899. 2058y 2815b 2918g 3061, 3069h 3724d 4186m 4241p 4283u 49105005c 6028s 6859l 6882n 7948o 8259t 8929r 9337i 9364a 10050e 11991 运行结果为:。
数据结构课程设计 哈夫曼编码与译码器课程设计
![数据结构课程设计 哈夫曼编码与译码器课程设计](https://img.taocdn.com/s3/m/affb71c8360cba1aa811daa2.png)
数据结构课程设计题目名称:哈夫曼编码与译码器课程设计计算机科学与技术学院1.需求分析(1)熟练掌握哈夫曼编译原理(2)掌握程序设计步骤(3)根据哈夫曼编码原理,设计一个程序,在已知相关字符和字符对应权值(文件中存在或者用户输入)的情况下,根据用户要求对相应内容进行编码、译码等相应操作。
(4)输入的形式和输入值的范围;(5) 输出的形式;(6) 程序所能达到的功能;(7) 测试数据:包括正确的输入及其输出结果和含有错误的输入及其输出结果2.概要设计1.写好流程图,设计实验方案。
2.初始化,从终端读入字符集大小n,以及n个字符和n个权值,建立哈夫曼树,并将它存于文件HuofumanTree中。
3.编码。
利用已建好的哈夫曼树,对文件ToBeTran中的正文进行编码,然后将结果存入文件CodeFile中。
4.译码。
利用已建好的哈夫曼树将文件CodeFile中的代码进行译码,结果存入文件Textfile中。
5.印代码文件(Print)将文件CodeFile以紧凑格式显示在终端上,每行50个代码。
同时将此字符形式的编码文件写入文件CodePrint中。
6.印哈夫曼树(Treeprinting).将已在内存中的哈夫曼树以直观的方式(比如树)显示在终端上,同时将此字符形式的哈夫曼树写入文件TreePrint中。
具体函数如下:1.Initialization()初始化2.Encoding()编码3.Decoding()译码4.Print_file()打印代码文件5.search(k,j,p)搜索二叉树6.Print_tree() 打印二叉树7.menu()主菜单8.main()主函数3.详细设计(1)哈夫曼结点定义类型以一个节点为单位,其中节点中包括他的父亲·左孩子·右孩子,权值(2)存储字符信息(3)用于编码时存取字符长度及起始位置(4)初始化将数据存入文件中void Initialization(){int i,j;FILE* HFM_f;//定义一个指针指向文件HFM_f = fopen("C:/Users/lenovo/Desktop/x.txt","w");//将文件打开,赋值给HFM_fif(HFM_f == NULL){printf("create file error!\n");}printf(" 请输入字符集大小: ");scanf("%d",&leaves);fprintf(HFM_f,"----输入的值-----\n");fprintf(HFM_f," 字符大小%4d\n",leaves);fprintf(HFM_f," 字符权值\n");for(i=0; i<leaves; i++){printf(" 请输入第%d个字符和其权:",i+1);scanf(" %c ",&HFM_num[i].hfstr);scanf("%d",&HFM_num[i].weight);fprintf(HFM_f,"%4c",HFM_num[i].hfstr);fprintf(HFM_f,"%4d\n",HFM_num[i].weight); //存储字符和权值}(5)建立哈夫曼树for(i=0; i<maxsize; i++)//哈夫曼树初始化{HFM_tree[i].parent = -1;HFM_tree[i].lchild = -1;HFM_tree[i].rchild = -1;HFM_tree[i].weight = 0;}for(i=0; i<leaves; i++){HFM_tree[i].weight = HFM_num[i].weight;}for(i=0; i<leaves-1; i++){int m1,m2;int m1_pos,m2_pos;m1=m2=65536;m1_pos=m2_pos=0;for(j=0; j<leaves+i; j++)//选出最小且没被访问的两个数{if(HFM_tree[j].weight<m1&&HFM_tree[j].parent == -1) {m2 = m1;m1 = HFM_tree[j].weight;m2_pos = m1_pos;m1_pos = j;}else{if(HFM_tree[j].weight<m2&&HFM_tree[j].parent == -1){m2 = HFM_tree[j].weight;m2_pos = j;}}}HFM_tree[leaves+i].parent = -1;HFM_tree[leaves+i].lchild = m1_pos;//HFM_tree[leaves+i]为两者的最小和的结点,即他们的父亲HFM_tree[leaves+i].rchild = m2_pos;HFM_tree[m1_pos].parent = leaves+i;HFM_tree[m2_pos].parent = leaves+i;HFM_tree[leaves+i].weight = m2+m1;//将和赋为他们的父亲结点的权值}(6)输出哈夫曼树printf("----------------哈夫曼编码--------------\n");printf(" parent lchild rchild weight\n");fprintf(HFM_f,"-------------哈夫曼编码------------\n");fprintf(HFM_f," parent lchild rchild weight\n");for(i=0; i<leaves*2-1; i++){printf("%8d%8d%8d%8d\n",HFM_tree[i].parent,HFM_tree[i].lchild,HFM_tre e[i].rchild,HFM_tree[i].weight);fprintf(HFM_f,"%8d%8d%8d%8d\n",HFM_tree[i].parent,HFM_tree[i].lchild, HFM_tree[i].rchild,HFM_tree[i].weight);}printf("\n");fclose(HFM_f);//关上文件}(7)编码void Encoding(){int i,j,p,c,k;FILE* HFM_f = fopen("CodeFile.txt","w");//打开文件if(HFM_f == NULL){printf("open file error!\n");}for(i=0; i<leaves; i++){c = i;//当前结点编号p = HFM_tree[i].parent;//父亲结点编号HFM_hf.start = len-1;//单个结点路径长度-1,即循环次数,从0开始算while(p!=-1)//根节点的p=-1,即根结点的父亲值为-1,即为初始化的值,证明根节点没有父亲结点{if(HFM_tree[p].lchild == c)//若左孩子为C,赋值0{HFM_hf.bit[HFM_hf.start] = 0;}else{HFM_hf.bit[HFM_hf.start] = 1;//若右孩子为c,赋值1 }--HFM_hf.start;c = p;//沿着树往上走,将刚才的父亲变为孩子p = HFM_tree[c].parent;//寻找当前结点的父亲,即原节点的爷爷}for(j=HFM_hf.start+1,k=0; j<len; j++,k++){HFM_code[i].bit[k] = HFM_hf.bit[j];}HFM_code[i].length = len-HFM_hf.start-1;HFM_code[i].start = HFM_hf.start+1;}for(i=0; i<leaves; i++){HFM_code[i].hfch = HFM_num[i].hfstr;printf(" character:%c start:%d length:%dCode:",HFM_code[i].hfch,HFM_code[i].start,HFM_code[i].length );for(j=0; j<HFM_code[i].length; j++){printf("%d",HFM_code[i].bit[j]);fprintf(HFM_f,"%d",HFM_code[i].bit[j]);}printf("\n");}printf("\n");fclose(HFM_f);}4.调试结果输入26个字符及其权值26个字母的编码如下:译码如下:打印文件中的内容:打印出的哈夫曼树如下:5.时间复杂度本代码的哈夫曼算法的时间复杂度为O(n^3)。
哈夫曼树和哈夫曼编码(数据结构程序设计)
![哈夫曼树和哈夫曼编码(数据结构程序设计)](https://img.taocdn.com/s3/m/a39f5bff284ac850ad0242b3.png)
课程设计(数据结构)哈夫曼树和哈夫曼编码二○○九年六月二十六日课程设计任务书及成绩评定课题名称表达式求值哈夫曼树和哈夫曼编码Ⅰ、题目的目的和要求:巩固和加深对数据结构的理解,通过上机实验、调试程序,加深对课本知识的理解,最终使学生能够熟练应用数据结构的知识写程序。
(1)通过本课程的学习,能熟练掌握几种基本数据结构的基本操作。
(2)能针对给定题目,选择相应的数据结构,分析并设计算法,进而给出问题的正确求解过程并编写代码实现。
Ⅱ、设计进度及完成情况Ⅲ、主要参考文献及资料[1] 严蔚敏数据结构(C语言版)清华大学出版社 1999[2] 严蔚敏数据结构题集(C语言版)清华大学出版社 1999[3] 谭浩强 C语言程序设计清华大学出版社[4] 与所用编程环境相配套的C语言或C++相关的资料Ⅳ、成绩评定:设计成绩:(教师填写)指导老师:(签字)二○○九年六月二十六日目录第一章概述 (1)第二章系统分析 (2)第三章概要设计 (3)第四章详细设计及实现代码 (8)第五章调试过程中的问题及系统测试情况 (12)第六章结束语 (13)参考文献 (13)第一章概述课程设计是实践性教学中的一个重要环节,它以某一课程为基础,可以涉及和课程相关的各个方面,是一门独立于课程之外的特殊课程。
课程设计是让同学们对所学的课程更全面的学习和应用,理解和掌握课程的相关知识。
《数据结构》是一门重要的专业基础课,是计算机理论和应用的核心基础课程。
数据结构课程设计,要求学生在数据结构的逻辑特性和物理表示、数据结构的选择和应用、算法的设计及其实现等方面,加深对课程基本内容的理解。
同时,在程序设计方法以及上机操作等基本技能和科学作风方面受到比较系统和严格的训练。
在这次的课程设计中我选择的题目是表达式求值和哈夫曼树及哈夫曼编码。
这里我们介绍一种简单直观、广为使用的算法,通常称为“算符优先法”。
哈夫曼树又称最优树,是一类带权路径长度最短的树,有着广泛的应用。
哈夫曼编码课程设计
![哈夫曼编码课程设计](https://img.taocdn.com/s3/m/3c617125482fb4daa58d4b47.png)
目录1设计内容与设计要求 (1)1.1系统的基本功能 (2)1.2系统的设计要求 (2)2 系统需求分析 (1)2.1系统设计目标 (1)2.2哈夫曼算法 (1)3系统的实现 (3)4 程序调试 (3)5 总结 (3)5.1本系统特色 (3)5.2心得体会 (3)附件:源程序清单 (5)1设计内容与设计要求1.1系统的基本功能哈夫曼编码是根据字符出现频率对数据进行编码解码,以便对文件进行压缩的一种方法,目前大部分有效的压缩算法(如MP3编码方法)都是基于哈夫曼编码的。
数据压缩过程称为编码,也就是把文件中的每个字符均转换为一个唯一的二进制串。
数据解压过程称为解码,也就是把给定的二进制位字符串转换为对应的字符。
1.2系统的设计要求(1)数据结构可以使用结构体数组或结构体链表实现,结构体的属性可进行扩充。
(2)由用户输入相应文本。
(3)对于系统运行时,要求有相应的提示信息,方便用户进行选择。
2 系统需求分析2.1系统设计目标(1)哈夫曼树的建立。
(2)哈夫曼编码的生成。
(3)求出平均查找长度。
(4)用户输入权值的个数。
(5)输出的形式为整型。
(6)程序的执行可使用户在输入一列数值后,可得到由这些权值所得到的编码。
2.2 哈夫曼算法哈夫曼算法流程如下:(1)根据给定的N个权值{W1,W2,····,WN}构成N棵二叉树的集合F={T1,T2,T3,···,Tn},其中每棵二叉树Ti中只有一个带权为Wi的根节点,其左右子树均空。
(2)在F中选取两颗根节点的权值最小的树作为左右子树构造一棵新的二叉树,且置新的二叉树的根结点的权值最小的树为其左右子树上根节点的权值之和。
(3)在F中删除这两棵树,同时将新得到的二叉树加入F中。
(4)重复(2)和(3),直到F只含一棵树为止。
这棵树便是哈夫曼树。
(5)约定左分支表示字符‘0’,右分支表示字符‘1’,则可以从根结点到叶子结点的路径上分支字符组成的字符串作为该叶子结点字符的编码,这就是哈夫曼编码。
哈夫曼编解码算法设计
![哈夫曼编解码算法设计](https://img.taocdn.com/s3/m/23c6f32acbaedd3383c4bb4cf7ec4afe04a1b1d8.png)
哈夫曼编解码算法设计1.引言1.1 概述概述部分将对哈夫曼编解码算法进行简要介绍,包括该算法的产生背景、主要特点以及应用领域等方面的内容。
哈夫曼编解码算法是一种基于权重分布的压缩算法,它通过对输入的数据流进行编码和解码来实现数据的压缩和恢复。
该算法由大卫·哈夫曼(David A. Huffman)于1952年提出,是一种被广泛应用于信息论和数据压缩领域的有效算法。
该算法的主要特点是根据输入数据的权重分布构建一棵哈夫曼树,通过不等长的编码方式来表示输入数据中出现频率较高的字符或数据块。
编码时,出现频率较高的字符使用较短的二进制编码,而出现频率较低的字符则使用较长的二进制编码,以此来实现数据的压缩效果。
哈夫曼编码算法在数据压缩领域有着广泛的应用。
由于压缩后的数据长度较短,可以大大节省存储空间和传输带宽,因此被广泛应用于各种数据传输和存储场景中,如文件压缩、图像压缩、语音压缩等。
此外,哈夫曼编码算法的设计思想也对后续的数据压缩算法提供了重要的借鉴和参考价值。
本文将详细介绍哈夫曼编码算法的原理、设计与实现,并通过实例和实验验证算法的性能和效果。
通过对哈夫曼编码算法的研究与分析,可以更好地理解该算法的优势和不足,并为后续的算法改进和优化提供参考。
最后,本文将总结哈夫曼编码算法的主要特点和应用场景,并对未来的研究方向提出展望。
1.2 文章结构文章结构部分主要介绍本文的各个部分以及每个部分的内容安排。
在本文中,共包含引言、正文和结论三个部分。
引言部分主要介绍了整篇文章的背景和目的。
在概述部分,简要说明了哈夫曼编解码算法的概念和作用,以及该算法在通信领域的重要性。
然后,文章结构部分具体说明了本文的组织结构,以便读者能够清晰地了解文章的整体脉络。
正文部分是本文的主体,分为两个部分:哈夫曼编码算法原理和哈夫曼编码算法设计与实现。
在哈夫曼编码算法原理部分,将详细介绍哈夫曼编码算法的基本原理,包括频率统计、构建哈夫曼树和生成哈夫曼编码等步骤。
数据结构课程设计哈夫曼编码实验
![数据结构课程设计哈夫曼编码实验](https://img.taocdn.com/s3/m/91e3345c0a4e767f5acfa1c7aa00b52acfc79ca9.png)
数据结构设计性实验Huffman编码与译码学号姓名班级设计性实验—Huffman 编码与译码一.实验目的:在掌握相关基础知识的基础上,学会自己设计实验算法,熟练掌握Huffman 树的建立方法,Huffman 编码的方法,进而设计出Huffman 译码算法,并编程实现。
二.实验要求:在6学时以内,制作出能够实现基于26个英文字母的任意字符串的编译码。
写出技术工作报告并附源程序。
三.实验内容及任务:1.设字符集为26个英文字母,其出现频度如下表所示。
2.建Huffman 树; 3.利用所建Huffman 树对任一字符串文件进行编码——即设计一个Huffman 编码器;4.对任一字符串文件的编码进行译码——即设计一个Huffman 译码器。
实现步骤:1.数据存储结构设计; 2.操作模块设计; 3.建树算法设计; 4.编码器设计;5. 译码器设计;51 48 1 15 63 57 20 32 5 1频度z y x w v u t 字符11611882380频度p 21 f q15 g r 47 h s o n m l k j 字符 57 103 32 22 13 64 186 频度 i e d c b a 空格 字符四.分析以及算法描述1.分析问题1)首先学习二叉树的知识,了解二叉树的路径、权数以及带权路径长度计算。
2)认识霍夫曼树,了解霍夫曼树的定义,构造霍夫曼树构造算法①又给定的n个权值{w1,w2,w3,……,w n}构造根节点的二叉树,从而得到一个二叉树森林F={T1,T2,T3,……T n}。
②在二叉树森里选取根节点全职最小和此最小的两棵二叉树作为左右节点构造新的二叉树,此时新的二叉树的根节点权值为左右子树权值之和。
③在二叉树森林中删除作为新二叉树的根节点左右子树的两棵二叉树,将新的二叉树加入到二叉树森林F中。
④重复②和③,当二叉树森林F只剩下一棵二叉树时,这棵二叉树是所构造的霍夫曼树。
3)练习通过普通树来构造霍夫曼树。
c哈夫曼编码课程设计
![c哈夫曼编码课程设计](https://img.taocdn.com/s3/m/5552a06eeffdc8d376eeaeaad1f34693daef1082.png)
c 哈夫曼编码课程设计一、课程目标知识目标:1. 学生能理解哈夫曼编码的基本原理,掌握其构建过程和应用场景。
2. 学生能运用哈夫曼编码进行数据压缩,并了解压缩比的概念。
3. 学生能理解哈夫曼编码在通信、图像处理等领域的重要性。
技能目标:1. 学生能够运用所学知识,独立构建哈夫曼树并进行编码。
2. 学生能够分析给定数据,选择合适的编码方法进行数据压缩。
3. 学生能够运用编程工具实现哈夫曼编码和解码过程。
情感态度价值观目标:1. 学生通过学习哈夫曼编码,培养对数据压缩技术的兴趣,提高信息素养。
2. 学生在合作学习过程中,培养团队协作能力和沟通能力。
3. 学生了解我国在数据压缩领域的研究成果,增强民族自豪感。
课程性质:本课程为信息技术课程,旨在帮助学生掌握数据压缩的基本方法,提高数据处理能力。
学生特点:学生处于高年级阶段,具备一定的编程基础和逻辑思维能力。
教学要求:结合学生特点和课程性质,注重理论与实践相结合,培养学生的实际操作能力和创新能力。
通过分解课程目标为具体学习成果,使学生在学习过程中能够明确自身的学习进度和目标。
二、教学内容1. 哈夫曼编码基本原理:介绍哈夫曼编码的概念、原理和优势,结合教材相关章节,使学生理解哈夫曼编码在数据压缩中的应用。
- 哈夫曼树的构建方法- 哈夫曼编码的生成过程- 压缩比的概念及其计算方法2. 哈夫曼编码的实际操作:通过实际操作,让学生掌握哈夫曼编码的构建和编码过程。
- 利用编程工具实现哈夫曼树的构建- 编程实现哈夫曼编码的生成- 数据压缩与解压缩的实际操作3. 哈夫曼编码的应用案例分析:结合教材案例,分析哈夫曼编码在通信、图像处理等领域的作用。
- 通信领域的数据压缩- 图像处理中的哈夫曼编码应用- 其他领域中的应用案例4. 编程实践:布置相关编程任务,巩固学生对哈夫曼编码的理解和应用。
- 实现哈夫曼编码的压缩和解压缩程序- 分析不同数据集的压缩效果,优化哈夫曼编码方法教学内容安排和进度:第1课时:哈夫曼编码基本原理及构建方法第2课时:哈夫曼编码的实际操作(构建哈夫曼树、生成编码)第3课时:哈夫曼编码的应用案例分析第4课时:编程实践(实现压缩与解压缩程序,优化编码方法)三、教学方法本课程将采用以下教学方法,以促进学生的主动参与和深入理解:1. 讲授法:对于哈夫曼编码的基本原理和概念,通过教师清晰的讲解,结合教材内容,使学生快速掌握理论基础。
huffman哈夫曼树编码译码课程设计报告
![huffman哈夫曼树编码译码课程设计报告](https://img.taocdn.com/s3/m/bd2cffa859eef8c75ebfb301.png)
数据结构课程设计信息科学与工程学院:学院计算机科学与技术专业:1601 计卓级:班号:学:学生姓名指导教师:23/ 1年月日题目名称一、实验内容哈夫曼编码译码系统【问题描述】用哈夫曼编码进行通信可以大大提高信道利用率,缩短信息传输时间,降低传输成本。
但是,这要求在发送端通过一个编码系统对待传数据预先编码,在接收端将传来的数据进行译码(复原)。
对于双工信道(即可以双向传输信息的信道),每端都需要一个完整的编/译码系统。
试为这样的信息收发站写一个哈夫曼码的编/译码系统。
【基本要求】1)初始化。
从终端读入字符集大小n,以及n个字符和n个权值,建立哈夫曼树。
2)编码。
利用已建好的哈夫曼树对输入英文进行编码,编码结果存储在数组中。
3)译码。
利用已建好的哈夫曼树将数组中的代码进行译码,结果存入一个字符数组。
4)输出编码。
将编码结果显示在终端上,每行50个代码。
5)输出哈夫曼树。
将哈夫曼树以直观的方式(树或凹入表形式)显示出来。
【实现提示】用户界面可以设计为“菜单”方式,再加上一个“退出”功能。
请用户键入一个选择功能符。
此功能执行完毕后再显示此菜单,直至某次用户选择了“退出”为止。
参考教材P240-246【选做内容】将哈夫曼树保存到文件中,编码和译码的结果也分别存放在两个文本文件中。
23/ 2二、数据结构设计储存结构struct HNodeType {//字符结构体类型int weight;//权int parent;//双亲位置int lchild;//左孩子int rchild;//右孩子char inf;// 字符};struct HcodeType {存储编码int bit[MaxBit];// int start;// 起始位置};三、算法设计1、在构造哈夫曼树时,设计一个结构体数组HuffNode保存哈夫曼树中各结点的信息,根据二叉树的性质可知,具有n个叶子结点的哈夫曼树共有2n-1个结点,所以数组HuffNode的大小设置为2n-1。
哈夫曼编码系统的设计与实现
![哈夫曼编码系统的设计与实现](https://img.taocdn.com/s3/m/fedd7a76842458fb770bf78a6529647d27283413.png)
哈夫曼编码系统的设计与实现
哈夫曼编码是一种用于数据压缩的编码方式,通过将出现频率高的字符用较短的编码表示,从而实现对数据的压缩。
哈夫曼编码系统的设计与实现包括以下几个步骤:
1. 字符频率统计:根据待压缩的数据,统计每个字符出现的频率。
可以使用哈希表或数组来记录每个字符的频率。
2. 构建哈夫曼树:根据字符的频率构建哈夫曼树。
首先将每个字符及其频率作为叶子节点,并按照频率的大小构建一个最小堆。
然后,每次从最小堆中取出两个频率最小的节点,将它们作为子节点构建一个新的节点,频率为子节点频率之和。
将新的节点放回最小堆中,重复上述步骤,直到最小堆中只剩下一个节点,即为哈夫曼树的根节点。
3. 构建编码表:通过遍历哈夫曼树,可以得到每个字符对应的哈夫曼编码。
一种常用的方式是,从根节点开始,每次向左走为0,向右走为1,直到叶子节点,将走过的路径记录下来,即为该字符的哈夫曼编码。
可以使用哈希表来存储每个字符及其对应的哈夫曼编码。
4. 数据压缩:根据构建好的哈夫曼编码表,将待压缩的数据中的每个字符替换为对应的哈夫曼编码,并将编码后的数据保存起来。
由于哈夫曼编码的特性,编码后的数据长度会变短,从而实现对数据的压缩。
5. 数据解压缩:使用相同的哈夫曼树和哈夫曼编码表,将压缩后的数据中的每个哈夫曼编码替换为对应的字符,从而实现对数据的解压缩。
要注意的是,设计和实现哈夫曼编码系统需要考虑到字符频率统计的效率、哈夫曼树的构建算法选择、编码表的存储结构选择等问题。
此外,还需要注意对压缩后的数据进行合理的保存和传输,以便于解压缩时能够正确恢复原始数据。
哈夫曼编码的研究及其某某程序的实现
![哈夫曼编码的研究及其某某程序的实现](https://img.taocdn.com/s3/m/54c91a2b0a1c59eef8c75fbfc77da26924c5967c.png)
一、概述哈夫曼编码是一种被广泛应用于数据压缩和传输领域的编码方法,由David A. Huffman于1952年提出。
其独特的编码方式能够使得频率较高的字符用较短的编码表示,从而实现对数据的高效压缩。
在本文中,我们将探讨哈夫曼编码的研究历程以及针对某某程序的实现。
二、哈夫曼编码的原理哈夫曼编码的原理主要基于字符的出现频率。
在给定的字符集中,将频率较高的字符用较短的编码表示,而频率较低的字符用较长的编码表示,从而实现数据的压缩。
哈夫曼编码的主要步骤包括:建立字符的频率统计表、构建哈夫曼树、生成哈夫曼编码表和进行编解码。
通过这些步骤,我们可以利用哈夫曼编码对数据进行高效的压缩和传输。
三、哈夫曼编码的研究历程哈夫曼编码作为一种经典的编码方法,其研究历程可以追溯到上世纪50年代。
当时,David A. Huffman提出了哈夫曼编码的概念,并通过其论文《A Method for the Construction of Minimum-Redundancy Codes》详细阐述了这一编码方法的原理和算法。
随后,哈夫曼编码被广泛应用于通信、数据存储和图像压缩等领域,成为了数据压缩技术中的重要组成部分。
四、某某程序的实现在现实应用中,我们经常需要对数据进行压缩和传输,而哈夫曼编码正是其中一种常用的方法。
针对某某程序的实现,我们可以通过以下步骤来实现哈夫曼编码的功能:1. 构建字符的频率统计表在实现某某程序时,首先需要对给定的字符集进行频率统计,以便后续的编码操作。
可以利用哈希表或数组来记录每个字符的出现次数,并按照频率进行排序。
2. 构建哈夫曼树基于字符的频率统计表,我们可以构建哈夫曼树。
哈夫曼树的构建需要借助最小堆或优先队列等数据结构,通过不断合并频率最小的节点来构建一棵树,直到所有字符都被合并为止。
3. 生成哈夫曼编码表一旦构建好哈夫曼树,就可以根据树的结构来生成哈夫曼编码表。
通过遍历哈夫曼树,可以得到每个字符对应的哈夫曼编码,从而实现对数据的编码操作。
数据结构课程设计哈夫曼编码译码器
![数据结构课程设计哈夫曼编码译码器](https://img.taocdn.com/s3/m/bf91b82bff4733687e21af45b307e87101f6f8a3.png)
题目一: 哈夫曼编码与译码一、任务设计一个运用哈夫曼算法的编码和译码系统, 反复地显示并解决以下项目, 直到选择退出为止。
规定:1) 将权值数据存放在数据文献(文献名为data.txt, 位于执行程序的当前目录中) ;2) 初始化:键盘输入字符集记录字符权值、自定义26个字符和26个权值、记录文献中一篇英文文章中26个字母, 建立哈夫曼树;3) 编码: 运用建好的哈夫曼树生成哈夫曼编码;4) 输出编码(一方面实现屏幕输出, 然后实现文献输出);5)译码(键盘接受编码进行译码、文献读入编码进行译码);6) 界面优化设计。
二、流程图三、代码分解 //头文献 #include<stdio.h> #include<string.h> #include<stdlib.h> #include <conio.h> #define N 1000 #define M 2*N-1 #define MAXcode 6000 //函数声明void count(CHar &ch,HTNode ht[]);void editHCode(HTNode ht[],HCode hcd[],CHar &ch,int n,char bianma[]); //编码函数void printyima(HTNode ht[],HCode hcd[],int n,char bianma[]); //译码函数 void creatHT(HTNode ht[],int n);字符集记录符集记录权值 权值 至文献“哈夫曼树。
t xt” 菜单1.从键盘输入字符集进行编码2.从文献读入字符集进行编码1.从键盘输入编码进行译码2.从文献读入编码进行译码0.返回上级菜单 0.返回上级菜单void CreateHCode (HTNode ht[],HCode hcd[],int n);void DispHCode(HTNode ht[],HCode hcd[],int n);void input_key(CHar &ch);void input_file(CHar &ch);void input_cw(HTNode ht[]);void bianma1(HTNode ht[],HCode hcd[],CHar &ch,int n,char bianma[]); void bianma2(HTNode ht[],HCode hcd[],CHar &ch,int n,char bianma[]); void yima1(HTNode ht[],HCode hcd[],int n,char bianma[]);void yima2(HTNode ht[],HCode hcd[],int n,char bianma[]);void creat_cw();void bianmacaidan();void yimacaidan();void bianmayima();int caidan();//结构体typedef struct{char data;int parent;int weight;int lchild;int rchild;}HTNode;typedef struct{char cd[N];int start;}HCode;typedef struct{char s[N];int num;}CHar;CHar ch;HTNode ht[M];HCode hcd[N];//主函数int main(){int xh;while(1){system("color 1f"); //操作菜单背景颜色 xh=caidan(); //调用菜单函数switch(xh) //switch语句 {case 1:system("cls");creat_cw();break;case 2:system("cls");creatHT(ht,n);break;case 3:system("cls");CreateHCode(ht,hcd,n);DispHCode(ht,hcd,n);break;case 4:system("cls");bianmayima();break;case 0:system("cls");printf("\n\n\n\n\n\n\n\n\n\t\t\t\t感谢使用本系统!\n\n\n\n\n\n\n \t\t\t");exit(0);default:system("cls");putchar('\a');printf("\n\t\t输入有误, 请重新输入:\n");break;}}return 0;}//菜单函数int caidan() //菜单函数模块//{int xh;printf("\n\n\n");printf("\t\t 欢迎使用哈夫曼编码译码系统\n");printf("\t\t \n");printf("\t\t*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*\n");printf("\t\t*= =*\n");printf("\t\t*= *=*=*=*=*=*=*=*=*=*=*= =*\n");printf("\t\t*= 1.建立字符权值=*\n");printf("\t\t*= *=*=*=*=*=*=*=*=*=*=*= =*\n"); printf("\t\t*= 2.建立并输出哈夫曼树=*\n"); printf("\t\t*= *=*=*=*=*=*=*=*=*=*=*= =*\n"); printf("\t\t*= 3.生成并查看哈夫曼编码=*\n"); printf("\t\t*= *=*=*=*=*=*=*=*=*=*=*= =*\n"); printf("\t\t*= 4.编码与译码=*\n"); printf("\t\t*= *=*=*=*=*=*=*=*=*=*=*= =*\n"); printf("\t\t*= 0.退出系统=*\n"); printf("\t\t*= =*\n"); printf("\t\t*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*\n"); printf("\n\t\t请输入序号进行选择:");scanf("%d", &xh);return xh; //返回从键盘接受的选项}void bianmayima(){int xh;while(1){printf("\n\n\n\n\n");printf("\t\t 编码与译码\n"); printf("\t\t \n"); printf("\t\t*= *=*=*=*=*=*=*=*=*=*=*=*=*=*=* =*\n");printf("\t\t*= 1.编码=*\n"); printf("\t\t*= *=*=*=*=*=*=*=*=*=*=*=*=*=*=* =*\n"); printf("\t\t*= 2.译码=*\n"); printf("\t\t*= *=*=*=*=*=*=*=*=*=*=*=*=*=*=* =*\n"); printf("\t\t*= 0.返回上级菜单=*\n"); printf("\t\t*= *=*=*=*=*=*=*=*=*=*=*=*=*=*=* =*\n"); printf("\n\t\t请输入序号进行选择:");scanf("%d",&xh);switch(xh) //switch语句{case 1:system("cls");bianmacaidan();break;case 2:system("cls");yimacaidan();break;case 0:system("cls");return;default:system("cls");putchar('\a');printf("\n\t\t输入有误, 请重新输入:\n");break;}}}void yimacaidan(){int xh;while(1){printf("\n\n\n\n\n");printf("\t\t 译码\n"); printf("\t\t \n"); printf("\t\t*= *=*=*=*=*=*=*=*=*=*=*=*=*=*=* =*\n"); printf("\t\t*= 1.键盘输入编码进行译码=*\n"); printf("\t\t*= *=*=*=*=*=*=*=*=*=*=*=*=*=*=* =*\n"); printf("\t\t*= 2.文献读入编码进行译码=*\n"); printf("\t\t*= *=*=*=*=*=*=*=*=*=*=*=*=*=*=* =*\n"); printf("\t\t*= 0.返回上级菜单=*\n"); printf("\t\t*= *=*=*=*=*=*=*=*=*=*=*=*=*=*=* =*\n"); printf("\n\t\t请输入序号进行选择:");scanf("%d",&xh);switch(xh) //switch语句{case 1:system("cls");yima1(ht,hcd,n,bianma);break;case 2:system("cls");yima2(ht,hcd,n,bianma);break;case 0:system("cls");return;default:system("cls");putchar('\a');printf("\n\t\t输入有误, 请重新输入:\n");break;}}}void bianmacaidan(){int xh;while(1){printf("\n\n\n\n\n");printf("\t\t 编码\n"); printf("\t\t \n"); printf("\t\t*= *=*=*=*=*=*=*=*=*=*=*=*=*=*=* =*\n"); printf("\t\t*= 1.键盘输入字符集编码=*\n"); printf("\t\t*= *=*=*=*=*=*=*=*=*=*=*=*=*=*=* =*\n"); printf("\t\t*= 2.文献读入文章编码=*\n"); printf("\t\t*= *=*=*=*=*=*=*=*=*=*=*=*=*=*=* =*\n"); printf("\t\t*= 0.返回上级菜单=*\n"); printf("\t\t*= *=*=*=*=*=*=*=*=*=*=*=*=*=*=* =*\n"); printf("\n\t\t请输入序号进行选择:");scanf("%d",&xh);switch(xh) //switch语句{case 1:system("cls");bianma1(ht,hcd,ch,n,bianma);break;case 2:system("cls");bianma2(ht,hcd,ch,n,bianma);break;case 0:system("cls");return;default:system("cls");putchar('\a');printf("\n\t\t输入有误, 请重新输入:\n");break;}}}void creat_cw(){int xh2;while(1){printf("\n\n\n\n\n");printf("\t\t 建立字符权值\n"); printf("\t\t \n"); printf("\t\t*= *=*=*=*=*=*=*=*=*=*=*=*=*=*=* =*\n"); printf("\t\t*= 1.从键盘输入字符集进行记录=*\n"); printf("\t\t*= *=*=*=*=*=*=*=*=*=*=*=*=*=*=* =*\n"); printf("\t\t*= 2.从文献读入字符集记录=*\n"); printf("\t\t*= *=*=*=*=*=*=*=*=*=*=*=*=*=*=* =*\n"); printf("\t\t*= 3.自定义字符权值=*\n"); printf("\t\t*= *=*=*=*=*=*=*=*=*=*=*=*=*=*=* =*\n"); printf("\t\t*= 0.返回上级菜单=*\n"); printf("\t\t*= *=*=*=*=*=*=*=*=*=*=*=*=*=*=* =*\n"); printf("\n\t\t请输入序号进行选择:");scanf("%d",&xh2);switch(xh2) //switch语句{case 1:system("cls");input_key(ch);break;case 2:system("cls");input_file(ch);break;case 3:system("cls");input_cw(ht);break;case 0:system("cls");return;default:system("cls");putchar('\a');printf("\n\t\t输入有误, 请重新输入:\n");break;}}}//建立字符权值模块void input_key(CHar &ch){int i,j=0;char st[N];printf("请输入字符集(以‘#’结束):\n");for(i=0;i<N;i++){scanf("%c",&st[i]);if(st[i]=='#'){st[i]='\0';break;}}strcpy(ch.s,st);count(ch,ht);printf("按任意键返回!");getch();system("cls");return;}void input_file(CHar &ch){int i;FILE*fp;char filename[20];printf("请输入要打开的文献名(*.txt):");scanf("%s",&filename);if((fp=fopen(filename,"r"))==NULL){printf("\n\t\t文献打开失败");return;}for(i=0;!feof(fp);i++){fread(&ch.s[i],sizeof(char),1,fp);}printf("读入成功!\n");printf("文献中的字符集为:%s\n",ch.s);fclose(fp);count(ch,ht);printf("按任意键返回!");getch();system("cls");return;}void input_cw(HTNode ht[]){int i,w,s,j;char a;printf("要输入的字符总个数是?:");scanf("%d",&s);n=s;printf("请输入字符及其权值:\n");for(i=0;i<s;i++){printf("请输入第%d个字母:",i+1);scanf("%s",&a);ht[i].data=a;printf("请输入其权值:");scanf("%d",&w);ht[i].weight=w;}FILE *fp;if((fp=fopen("data.txt","w"))==0){printf("\n\t\t文献打开失败");return;}printf("\n定义权值成功!\n\n");printf("各字符及其权值为:\n\n");fprintf(fp,"各字符及其权值为:\n");printf(" 字符\t权值");fprintf(fp," 字符\t权值");for(j=0;j<i;j++){ printf("\n");fprintf(fp,"\n");printf(" %-8c%-8d",ht[j].data,ht[j].weight);fprintf(fp," %-8c%-8d%",ht[j].data,ht[j].weight); }printf("\n");printf("\n字符权值已输出至文献“data.txt”!");fclose(fp);printf("输入完毕, 按任意键返回!");getch();system("cls");return;}//记录字符权值函数void count(CHar &ch,HTNode ht[]){int i,j,m=0;char c[N];int sum[N]={0};for(i=0;ch.s[i]!='\0';i++){for(j=0;j<m;j++)if(ch.s[i]==c[j]||(c[j]>='a'&&c[j]<='z'&&ch.s[i]+32==c[j])) break;if(j<m)sum[j]++;else{if(ch.s[i]>='A'&&ch.s[i]<='Z')c[j]=ch.s[i]+32;else c[j]=ch.s[i];sum[j]++;m++;}}for(i=0;i<m;i++){ht[i].data=c[i];ht[i].weight=sum[i];}n=m;FILE *fp;if((fp=fopen("data.txt","w"))==0) {printf("\n\t\t文献打开失败"); return;}printf("\n记录权值成功!\n\n"); printf("各字符及其权值为:\n\n"); fprintf(fp,"各字符及其权值为:\n"); printf(" 字符\t权值");fprintf(fp," 字符\t权值");for(j=0;j<m;j++){ printf("\n");fprintf(fp,"\n");printf(" %-8c%-8d",ht[j].data,ht[j].weight);fprintf(fp," %-8c%-8d%",ht[j].data,ht[j].weight);}printf("\n");printf("\n字符权值已输出至文献“data.txt”!");fclose(fp);}//构造哈夫曼树void creatHT(HTNode ht[],int n){FILE *fp;if((fp=fopen("哈夫曼树.txt","w"))==0){printf("\n\t\t文献打开失败");return;}int i,j,k,lnode,rnode;int min1,min2;for (i=0;i<2*n-1;i++)ht[i].parent=ht[i].lchild=ht[i].rchild=-1;for (i=n;i<2*n-1;i++){min1=min2=32767;lnode=rnode=-1;for(k=0;k<=i-1;k++)if(ht[k].parent==-1){if (ht[k].weight<min1){min2=min1;rnode=lnode;min1=ht[k].weight;lnode=k;}else if(ht[k].weight<min2){min2=ht[k].weight;rnode=k;}}ht[lnode].parent=i;ht[rnode].parent=i;ht[i].weight=ht[lnode].weight+ht[rnode].weight;ht[i].lchild=lnode;ht[i].rchild=rnode;}printf("建立huffman树成功!\n");printf("输出huffman树:\n");fprintf(fp,"输出huffman树:\n");printf("\t字符\t权值\t父节点\t 左子节点\t右子节点");fprintf(fp,"\t字符\t权值\t父节点\t 左子节点\t右子节点");for(j=1;j<i;j++){ printf("\n");fprintf(fp,"\n");printf("\t %-8c%-8d%-10d%-14d%-10d",ht[j].data,ht[j].weight,ht[j].parent,ht[i]. lchild,ht[j].rchild);fprintf(fp,"\t %-8c%-8d%-10d%-14d%-10d",ht[j].data,ht[j].weight,ht[j].parent,h t[i].lchild,ht[j].rchild);}printf("\n");printf("哈夫曼树已输出至文献“哈夫曼树.txt”!按任意键返回!");fclose(fp);getch();system("cls");return;}//生成哈夫曼编码void CreateHCode (HTNode ht[],HCode hcd[],int n){int i,f,c,j=0;HCode hc;for(i=0;i<n;i++){hc.start=n;c=i;hc.cd[hc.start--]='0';f=ht[i].parent;while(f!=-1){if (ht[f].lchild==c)hc.cd[hc.start--]='0';elsehc.cd[hc.start--]='1';c=f;f=ht[f].parent;}hc.start++;for(j=0;j<hc.start;j++)hc.cd[j]=' ';hcd[i]=hc;}}void DispHCode(HTNode ht[],HCode hcd[],int n) {FILE *fp;if((fp=fopen("哈夫曼编码.txt","w"))==0){printf("\n\t\t文献打开失败");return;}int i,k;int sum=0,m=0,j;printf("输出字符哈夫曼编码:\n"); fputs("输出字符哈夫曼编码:\n",fp); for (i=0;i<n;i++){j=0;printf("%c:\t",ht[i].data);fprintf(fp,"\n%c:\t",ht[i].data);for (k=hcd[i].start;k<=n;k++){printf("%c",hcd[i].cd[k]);j++;fprintf(fp,"%c",hcd[i].cd[k]); }m+=ht[i].weight;sum+=ht[i].weight*j;printf("\n");}printf("\n哈夫曼编码已保存至文献“哈夫曼编码.txt!按任意键返回!”");fclose(fp);getch();system("cls");}//编码函数void bianma1(HTNode ht[],HCode hcd[],CHar &ch,int n,char bianma[]){int i;char str[N];printf("请输入要编码的字符集(以‘#’结束):\n");for(i=0;i<N;i++){scanf("%c",&str[i]);if(str[i]=='#'){str[i]='\0';break;}}strcpy(ch.s,str);ch.num=strlen(str);editHCode(ht,hcd,ch,n,bianma);getch();system("cls");}void bianma2(HTNode ht[],HCode hcd[],CHar &ch,int n,char bianma[]) {int i;FILE*fp;char filename[20];printf("请输入要打开的文献名(*.txt):");scanf("%s",&filename);if((fp=fopen(filename,"r"))==NULL){printf("\n\t\t文献打开失败");return;}for(i=0;!feof(fp);i++){fread(&ch.s[i],sizeof(char),1,fp);}ch.num=strlen(ch.s);printf("\n读入成功!\n");printf("文献中的字符集为:\n%s",ch.s);fclose(fp);editHCode(ht,hcd,ch,n,bianma);system("cls");return;}//译码函数void yima1(HTNode ht[],HCode hcd[],int n,char bianma[]) {int i;char code[MAXcode];printf("请输入编码进行译码(以‘#’结束):\n");for(i=0;i<MAXcode;i++){scanf("%c",&code[i]);if(code[i]=='#'){code[i]='\0';break;}}strcpy(bianma,code);printyima(ht,hcd,n,bianma);printf("\n译码完毕!按任意键返回!");getch();system("cls");return;}void yima2(HTNode ht[],HCode hcd[],int n,char bianma[]) {int i;FILE*fp;char filename[20];printf("请输入要打开的文献名(*.txt):");scanf("%s",&filename);if((fp=fopen(filename,"r"))==NULL){printf("\n\t\t文献打开失败");return;}for(i=0;!feof(fp);i++){fread(&bianma[i],sizeof(char),1,fp);}printf("读入成功!\n");printf("文献中的编码是:%s\n",bianma);printyima(ht,hcd,n,bianma);printf("\n译码完毕!按任意键返回!");getch();system("cls");}四、调试结果主菜单建立字符权值选择2.从文献读入字符进行记录输入测试文献名“cs.txt”输出个字符权值建立哈夫曼树并输出至文献生成哈夫曼编码并保存至文献编码选择2.从文献读入字符集编码编码结果保存至文献译码选择2.从文献读入编码, 读入上一步的编码译码完毕, 返回!退出系统。
数据结构课程设计之哈夫曼编码
![数据结构课程设计之哈夫曼编码](https://img.taocdn.com/s3/m/9b752828336c1eb91a375d74.png)
一、设计思想(一) 哈夫曼树的设计思想对于一组具有确定权值的叶子结点可以构造出多个具有不同带权路径长度的二叉树,其中具有最小带权路径长度的二叉树称作哈夫曼树或最优二叉树。
首先给定n个权值制造n个只含根结点的二叉树,得到一个二叉树林;再在这二叉树林里面找根结点的权值最小和次小的两棵树作成新的二叉树,其中新的二叉树的根结点的权值为左右子根结点权值之和;最后在二叉树林中把组合过的二叉树删除,再重复第二步,直到最后就剩一颗二叉树的时候得到的这棵二叉树就是哈夫曼树。
(二)哈夫曼编码与解码的设计思想在数据通讯中,经常要将传送的文字转换为二进制字符0和1组成的二进制串,称这个过程为编码。
与子相对的是解码或是译码,就是用与编码相同的方式将二进制串转换称编码前的文字的过程称作解码。
在这里是通过哈夫曼树实现编码与解码的,所以称作是哈夫曼编码与解码。
首先输入一个字符串,还有相应的在哈夫曼树里的权值,这样用哈夫曼树把字符串用二进制串代替它,这个过程要注意树和编码问题,其中树的问题在上面已经解决,主要看编码的问题,就是根据我们输入的字符串和权值建立相应的树模型,这一步完成那编码就已经完成了,最后打印就行了;然后就是解码,完成编码相应的解码就相对简单了,就是先找到在编码的时候建的那个模型树,将编码中的二进制串再根据权值转换为相应的字符串,这样一步步解码就行了。
以上就是通过用哈夫曼树进行哈夫曼编码与解码如何实现的主要设计思想。
二、算法流程图(一)哈夫曼树的流程图图1哈夫曼树的流程图(二)编码与解码的流程图图2编码与解码的流程图图片说明:(左边)编码流程图,(右边)解码流程图。
三、源代码下面给出的是用中缀转后缀算法实现的程序的源代码:#include "stdio.h"#include "string.h"#define MAX 100 /*定义常量*/struct HaffNode{int weight; /*权值*/int parent; /*双亲结点下标*/char ch;int rchild;}*myHaffTree; /*构造哈夫曼树*/struct Coding{char bit[MAX]; /*定义数组*/char ch;int weight; /*字符的权值*/}*myHaffCode; /*定义结构体*/void Haffman(int n) /*定义哈夫曼函数*/{int i,j,x1,x2,s1,s2;for (i=n+1;i<=2*n-1;i++) /*树的初始化*/{s1=s2=10000;x1=x2=0;for (j=1;j<=i-1;j++) /*构造哈夫曼树的非叶子结点*/{if(myHaffTree[j].parent==0&&myHaffTree[j].weight<s1) /*分配左右结点*/ {s2=s1;x2=x1;s1=myHaffTree[j].weight;x1=j;}else if(myHaffTree[j].parent==0&&myHaffTree[j].weight<s2){s2=myHaffTree[j].weight;x2=j;}}myHaffTree[x1].parent=i;myHaffTree[x2].parent=i;myHaffTree[i].weight=s1+s2; /*左右子组合为新树*/myHaffTree[i].lchild=x1;myHaffTree[i].rchild=x2;}}void HaffmanCode(int n) /*构造n个结点哈夫曼编码*/{int start,c,f,i,j,k;char *cd;cd=(char *)malloc(n*sizeof(char));myHaffCode=(struct Coding *)malloc((n+1)*sizeof(struct Coding));cd[n-1]='\0';for(i=1;i<=n;++i) /*n个叶子结点的哈夫曼编码*/{for(c=i,f=myHaffTree[i].parent;f!=0;c=f,f=myHaffTree[f].parent)if(myHaffTree[f].lchild==c) cd[--start]='0';else cd[--start]='1';for(j=start,k=0;j<n;j++){myHaffCode[i].bit[k]=cd[j];k++;}myHaffCode[i].ch=myHaffTree[i].ch; /*取编码对应的权值*/ myHaffCode[i].weight=myHaffTree[i].weight;}free(cd);}Init() /*定义有返回值的函数*/ {int i,n,m;printf("please input the number of words:");scanf("%d",&n);m=2*n-1;myHaffTree=(struct HaffNode *)malloc(sizeof(struct HaffNode)*(m+1));for(i=1;i<=n;i++){printf("please input the word and the equal:");scanf("%s%d",&myHaffTree[i].ch,&myHaffTree[i].weight);myHaffTree[i].parent=0;myHaffTree[i].lchild=0;myHaffTree[i].rchild=0;}for(i=n+1;i<=m;i++){myHaffTree[i].ch ='#';myHaffTree[i].lchild=0;myHaffTree[i].parent=0;myHaffTree[i].rchild=0;myHaffTree[i].weight=0;}Haffman(n);HaffmanCode(n);for(i=1;i<=n;i++){printf("%c %d",myHaffCode[i].ch,myHaffCode[i].weight);printf("\n");}printf("init success!\n");return n;}void Caozuo_C(int m) /* 编码函数*/{int n,i,j;char string[50],*p;printf("please input the words:");scanf("%s",string);n=strlen(string); /*计算字符串长度*/ for(i=1,p=string;i<=n;i++,p++) /*进行编码*/{for(j=1;j<=m;j++)if(myHaffCode[j].ch==*p)printf("%s\n",myHaffCode[j].bit);}}void Caozuo_D(int n) /*解码函数*/{int i,c;char code[1000],*p;printf("please input the coding:"); /*输入二进制编码*/ scanf("%s",code);for(p=code,c=2*n-1;*p!='\0';p++) /*进行解码*/{if(*p=='0') /*结束条件*/{c=myHaffTree[c].lchild; /*赋值*/if(myHaffTree[c].lchild==0) /* 扫描*/{printf("%c",myHaffTree[c].ch);c=2*n-1;continue; /*结束*/}}else if(*p=='1'){c=myHaffTree[c].rchild;if(myHaffTree[c].lchild==0){printf("%c",myHaffTree[c].ch);c=2*n-1; /*赋值*/continue;}}}printf("\n");}void main() /*主函数*/{int n;char char1; /*定义字符*/n=Init(); /*函数的调用*/printf("A.coding B.codeprinting C.exit\nplease input the process:\n");while(1){scanf("%c",&char1);if(char1=='c') /*判断字符*/break;switch(char1){case'A':Caozuo_C(n);break; /*执行编码操作*/case'B':Caozuo_D(n);break; /*执行解码操作*/case'C':;break;}}}四、运行结果(一)中缀转后缀算法的运行结果:五、遇到的问题及解决这部分我主要遇到了如下三个问题,其内容与解决方法如下所列:●问题1:刚开始不知道如何建一个好树,因为我开始试着建了几个二叉树,不知道什么原因运行的时候那编码总是不对,跟在草稿纸上自己画的那个二叉树总是不相符,就找原因。
数据结构实验哈夫曼树及哈夫曼编码c语言
![数据结构实验哈夫曼树及哈夫曼编码c语言](https://img.taocdn.com/s3/m/9222096bec630b1c59eef8c75fbfc77da369975e.png)
数据结构实验报告:哈夫曼树及哈夫曼编码一、实验目的1. 理解哈夫曼树及哈夫曼编码的概念和原理;2. 掌握C语言中哈夫曼树及哈夫曼编码的实现方法;3. 分析和讨论哈夫曼编码在实际应用中的优势和不足。
二、实验内容和步骤1. 哈夫曼树的构建1.1 通过C语言实现哈夫曼树的构建算法;1.2 输入一组权值,按哈夫曼树构建规则生成哈夫曼树;1.3 输出生成的哈夫曼树结构,并进行可视化展示。
2. 哈夫曼编码的实现2.1 设计哈夫曼编码的实现算法;2.2 对指定字符集进行编码,生成哈夫曼编码表;2.3 对给定字符串进行哈夫曼编码,并输出编码结果。
三、实验过程及结果1. 哈夫曼树的构建在C语言中,通过定义结构体和递归算法实现了哈夫曼树的构建。
根据输入的权值,依次选择权值最小的两个节点构建新的父节点,直至构建完成整棵哈夫曼树。
通过调试和可视化展示,确认了程序正确实现了哈夫曼树的构建。
2. 哈夫曼编码的实现经过分析和设计,利用哈夫曼树的特点实现了哈夫曼编码的算法。
根据生成的哈夫曼树,递归地生成字符对应的哈夫曼编码,并输出编码结果。
对指定的字符串进行了编码测试,验证了哈夫曼编码的正确性和有效性。
四、实验结果分析1. 哈夫曼编码在数据传输和存储中具有较高的压缩效率和可靠性,能够有效减少数据传输量和存储空间;2. 哈夫曼树及哈夫曼编码在通信领域、数据压缩和加密等方面有着广泛的应用和重要意义;3. 在实际应用中,哈夫曼编码的构建和解码算法需要较大的时间和空间复杂度,对于大规模数据的处理存在一定的局限性。
五、实验总结通过本次实验,深入理解了哈夫曼树及哈夫曼编码的理论知识,并掌握了C语言中实现哈夫曼树及哈夫曼编码的方法。
对哈夫曼编码在实际应用中的优势和局限性有了更深入的认识,这对今后的学习和工作有着积极的意义。
六、参考文献1. 《数据结构(C语言版)》,严蔚敏赵现军著,清华大学出版社,2012年;2. 《算法导论》,Thomas H. Cormen 等著,机械工业出版社,2006年。
哈夫曼编码生成程序
![哈夫曼编码生成程序](https://img.taocdn.com/s3/m/154e735d804d2b160b4ec06c.png)
#include <stdio.h>#include <stdlib.h>#define MaxSize 50typedef struct{char c; //代码;int w; //代码权值;char code[MaxSize]; //代码的Huffman编码;}HuffCode[MaxSize];typedef struct{int Weight; //权值;int LChild,RChild,Parent;}HTNode,HuffTree[MaxSize];//===================================================================== ===========void HuffmanTree(HuffTree HT,int length,HuffCode hc); //生成Huffman树;void SelectHTNode(HuffTree HT,int n,int *min1,int *min2); //查找最小和次小序号;void HuffmanCode(HuffTree HT,int len,HuffCode hc); //生成Huffman编码;//===================================================================== ===========int main(void){HuffTree HT; //Huffman树;HuffCode HC; //Huffman编码;int i,len;printf("<<<< Huffman编码生成程序>>>>\t\tby Haroldi.\n\n\n\n\n\n");printf("\n输入代码数量:"); scanf("%d",&len); system("cls");printf("代码数量:%2d\n\n",len);printf("输入代码及权值(e.g.: \"a16[回车]\" ):\n");for(i=1;i <= len;i++){while(getchar() != '\n') NULL;printf("No.%2d:",i);HC[i].c = getchar();scanf("%d",&HC[i].w);}HuffmanTree(HT,len,HC);HuffmanCode(HT,len,HC);printf("\n输出Huffman编码:\n");for(i = 1;i<=len;i++){printf("\n %c :",HC[i].c);puts(HC[i].code);}//测试Huffman树结构;printf("\n\n输出Huffman树结构:");system("pause");printf("\nHT[i]:\t权值\t双亲\t左孩子\t右孩子\n");for(i = 1;i<2*len;i++){if(i <= len) printf("(%c)",HC[i].c);printf("%2d,\t %2d,\t %2d,\t %2d,\t %2d\n",i,HT[i].Weight,HT[i].Parent,HT[i].LChild,HT[i].RChild);}return 0;}void HuffmanTree(HuffTree HT,int length,HuffCode hc) //Huffman树初始化;{int i,min1,min2;HT[0].Weight = 65535;for(i = 1;i <= length;i++){HT[i].Weight = hc[i].w;HT[i].LChild = HT[i].RChild = HT[i].Parent = -1;}for(;i < 2*length;i++) //i初值= length+1;{HT[i].LChild = HT[i].RChild = HT[i].Parent = -1;}for(i = length+1;i < 2*length;i++){SelectHTNode(HT,i,&min1,&min2);HT[min1].Parent = i;HT[min2].Parent = i;HT[i].LChild = min1;HT[i].RChild = min2;HT[i].Weight = HT[min1].Weight + HT[min2].Weight;}}//===================================================================== ===========void SelectHTNode(HuffTree HT,int n,int *min1,int *min2) //查找最小和次小序号;{int i;*min1 = *min2 = 0;for(i = 1;i < n;i++){if(HT[i].Parent == -1){if(HT[*min1].Weight >= HT[i].Weight){*min2 = *min1;*min1 = i;}else if(HT[*min2].Weight > HT[i].Weight) *min2 = i;}}}//===================================================================== ===========void HuffmanCode(HuffTree HT,int len,HuffCode hc) //生成Huffman编码;{int i,j,tc,Stack[MaxSize],top = -1;char flag[MaxSize];HTNode th;for(i = 1;i <= len;i++){top = -1; //栈初始化;j = 0; //hc[i].code串首位置偏移;th = HT[i]; //当前结点th;tc = i; //当前结点标记tc;while(th.Parent != -1){ //当前结点th双亲P入栈,由P的孩子是th,确定flag;确定下次结点标记tc;Stack[++top] = th.Parent;if(HT[th.Parent].LChild == tc) {flag[top] = 'L'; tc = th.Parent;}if(HT[th.Parent].RChild == tc) {flag[top] = 'R'; tc = th.Parent;}th = HT[Stack[top]]; //下一结点;}while(top != -1){if(flag[top] == 'L') hc[i].code[j++] ='0';else hc[i].code[j++] ='1';Stack[top--]; //出栈;}hc[i].code[j] ='\0'; //当前串结束;}}哈夫曼树在一般的数据结构的书中,树的那章后面,著者一般都会介绍一下哈夫曼(HUFFMAN)树和哈夫曼编码。
数据结构 哈夫曼编码器课程设计报告
![数据结构 哈夫曼编码器课程设计报告](https://img.taocdn.com/s3/m/bc160134773231126edb6f1aff00bed5b8f37345.png)
数据结构哈夫曼编码器课程设计报告哈夫曼编码器课程设计报告设计目标:本课程设计的目标是实现一个哈夫曼编码器,能够实现对给定文本文件进行压缩和解压缩操作。
通过使用哈夫曼编码,可以使文本文件的大小大幅度减小,从而节约存储空间。
设计原理及实现方法:本设计主要包括以下几个步骤:1、文本文件的读取:首先需要从外部文件中读取待压缩的文本文件,读取过程可以通过使用文件输入流进行操作。
读取的文本内容将用于构建哈夫曼树和编码表。
2、构建哈夫曼树:哈夫曼树是通过给定文本中的字符出现频率来构建的,出现频率更高的字符将拥有更短的编码。
构建哈夫曼树的过程可以通过使用优先队列和二叉树来实现。
3、编码表:在构建哈夫曼树的过程中,每个字符都会有一个唯一的编码。
根据哈夫曼树的特性,左子树的编码为0,右子树的编码为1,根据这个规则可以通过遍历哈夫曼树来编码表。
4、压缩文本文件:在编码表后,可以利用编码表来对文本文件进行压缩操作。
遍历文本文件中的每个字符,通过编码表将字符转换为对应的哈夫曼编码,并将编码存储在一个压缩文件中。
5、解压缩文本文件:解压缩操作是压缩操作的逆过程。
根据编码表将压缩文件中的哈夫曼编码逐个解码为字符,并将解码后的字符写入解压缩文件中。
附件说明:本文档的附件包括以下内容:1、源代码文件:- HuffmanEncoder:java:包含了哈夫曼编码器的主要实现代码。
- Mn:java:包含了测试哈夫曼编码器的主函数。
2、示例文本文件:- input:txt:用于测试的示例文本文件。
法律名词及注释:本文档中涉及的法律名词及注释如下:1、哈夫曼编码:用于数据压缩的一种编码方式,旨在通过减少字符的编码长度来节省存储空间。
2、压缩:将原始文件经过编码转换为较短的文件,从而减小存储空间的占用。
3、解压缩:将压缩文件经过解码转换为原始文件,恢复原始文件的过程。
全文结束。
设计哈夫曼编码算法概率程序设计
![设计哈夫曼编码算法概率程序设计](https://img.taocdn.com/s3/m/30f6484702d8ce2f0066f5335a8102d276a26195.png)
设计哈夫曼编码算法概率程序设计1. 概述哈夫曼编码算法是一种广泛应用于数据压缩领域的算法,它通过根据字符出现的频率来设计不等长编码,从而实现对数据的高效压缩。
本文将介绍哈夫曼编码算法的原理和实现过程,涵盖概率统计、编码设计、程序实现等内容。
2. 哈夫曼编码算法原理哈夫曼编码算法的核心思想是基于字符的出现概率来设计编码,具体流程如下:- 首先统计待编码的字符出现的频率,并根据频率构建一个最小堆,将频率最小的字符放在堆的顶部;- 然后从最小堆中取出频率最小的两个字符,合并成一个新字符,并将其频率设置为两者之和;- 不断重复上述步骤,直至最小堆中只剩下一个字符;- 根据合并的过程构建出哈夫曼树,根据树的结构设计字符的编码,出现频率较高的字符编码较短,出现频率较低的字符编码较长。
3. 哈夫曼编码算法实现哈夫曼编码算法的实现主要包括概率统计、编码设计和程序实现三个步骤。
3.1 概率统计在实现哈夫曼编码算法之前,首先需要统计待编码字符的出现频率。
可以通过遍历待编码的数据,对每个字符出现的次数进行统计,并构建出字符频率统计表。
3.2 编码设计在进行编码设计时,需要根据字符的频率构建出哈夫曼树,并根据哈夫曼树的结构,设计字符的编码。
可以通过递归的方式构建哈夫曼树,并根据树的结构设计每个字符的编码。
3.3 程序实现在程序实现过程中,可以使用C++、Java、Python等编程语言来实现哈夫曼编码算法。
可以封装字符频率统计、哈夫曼树构建、编码设计等功能模块,并提供接口供外部调用。
4. 哈夫曼编码算法应用哈夫曼编码算法被广泛应用于数据压缩领域,例如文本文件、图片文件、音频文件等。
通过对数据进行哈夫曼编码压缩,可以显著减小数据的存储空间,提高数据传输效率。
5. 结语本文介绍了哈夫曼编码算法的原理和实现过程,涵盖了概率统计、编码设计和程序实现等内容。
哈夫曼编码算法作为一种高效的数据压缩算法,在实际应用中发挥着重要作用,希望本文对读者能有所帮助。
数据结构 程序设计 哈夫曼编码
![数据结构 程序设计 哈夫曼编码](https://img.taocdn.com/s3/m/f35b9e77f242336c1eb95e7d.png)
学号数据结构课程设计设计说明书哈夫曼编码起止日期:2011年12月12 日至2011 年12月16日学生姓名班级成绩指导教师(签字)电子与信息工程系2011年12月16日一、设计目的 (3)二、设计要求 (3)三、设计内容 (3)一、需求分析 (3)1.构造哈夫曼树的方法如下: (3)2.程序实现的功能 (4)二、问题求解 (4)三、总体设计 (5)1.程序设计组成框图: (5)2.流程图: (6)四、详细设计 (6)1. 构造结点的结构体 (6)2. 构造哈夫曼树 (6)3. 求哈夫曼编码 (6)五、调试与测试 (7)1.测试过程中遇到的主要问题 (7)六、关键源程序清单和执行结果 (7)1.源代码: (7)2.执行结果: (10)四、参考文献 (11)天津城市建设学院课程设计任务书2011—2012学年第1学期电子与信息工程系软件工程专业班级课程设计名称:数据结构课程设计设计题目:哈夫曼编码完成期限:自2011 年12 月12 日至2011 年12 月16 日共 1 周设计依据、要求及主要内容(可另加附页):一、设计目的熟悉各种数据结构和运算,会使用数据结构的基本操作解决一些实际问题。
二、设计要求(1)重视课程设计环节,用严谨、科学和踏实的工作态度对待课程设计的每一项任务;(2)按照课程设计的题目要求,独立地完成各项任务,严禁抄袭;凡发现抄袭,抄袭者与被抄袭者皆以零分计入本课程设计成绩。
凡发现实验报告或源程序雷同,涉及的全部人员皆以零分计入本课程设计成绩;(3)学生在接受设计任务后,首先要按设计任务书的要求编写设计进程表;(4)认真编写课程设计报告。
三、设计内容一、需求分析1.构造哈夫曼编码的方法如下:第一步定义一个结点的结构体,包括结点的权值,结点的双亲结点,左孩子,右孩子。
并定义两个HTNode,*HuffmanTree为该类型的名字。
第二步创建一个Select函数用来选择结点较小的结点权值和下标。
设计一个利用哈夫曼算法的编码系统
![设计一个利用哈夫曼算法的编码系统](https://img.taocdn.com/s3/m/537e698b02d276a200292e52.png)
设计一个利用哈夫曼算法的编码系统,重复地显示并处理以下项目,直到选择退出为止。
【基本要求】1) 将权值数据存放在数据文件(文件名为data.txt,位于执行程序的当前目录中)2) 初始化:键盘输入字符集大小n、n个字符和n个权值,建立哈夫曼树;3) 编码:利用建好的哈夫曼树生成哈夫曼编码;4) 输出(1)各个字符的编码;(2)1111111;;;;;;#include<stdio.h>#include<string.h>#include<malloc.h>#define M 50#define MAX 1000;typedef struct{int parent,lchild,rchild;}HTNODE,*HUFFMANTREE;{int m1,m2,k;int i,j,x1,x2;HUFFMANTREE ht;ht=(HUFFMANTREE)malloc((2*n)*sizeof(HTNODE));for(i=1;i<(2*n);i++)//初始化哈夫曼树中各结点的数据,没初始值的赋值为0{ht[i].parent=ht[i].lchild=ht[i].rchild=0;if(i<=n)ht[i].weight=weight[i];elseht[i].weight=0;}for(i=1;i<n;i++)//每一重循环从森林中选择最小的两棵树组建成一颗新树{m1=m2=MAX;x1=x2=0;for(j=1;j<(n+i);j++){if((ht[j].weight<m1)&&(ht[j].parent==0)){m2=m1;x2=x1;m1=ht[j].weight;x1=j;}else if((ht[j].weight<m2)&&(ht[j].parent==0)){m2=ht[j].weight;x2=j;}}k=n+i;ht[x1].parent=ht[x2].parent=k;ht[k].weight=m1+m2;ht[k].lchild=x1;ht[k].rchild=x2;}return ht;}void huffmancoding(const int n,HUFFMANCODE hc,HUFFMANTREE ht,char str[]){int i,start,child,father;char *cd;cd=(char*)malloc(n*sizeof(char));//分配求编码的工作空间cd[n-1]='\0';//编码结束符for(i=1;i<=n;++i)//逐个字符求哈夫曼编码{start=n-1;for(child=i,father=ht[i].parent;father!=0;child=father,father=ht[father].parent)/*从叶子结点到根结点求逆向编码*/if(ht[father].lchild==child)cd[--start]='0';elsecd[--start]='1';hc[i]=(char*)malloc((n-start)*sizeof(char));//为i个字符编码分配空间strcpy(hc[i],&cd[start]);//从cd复制哈夫曼编码串到hc}free(cd);//释放工作空间for(i=1;i<=n;++i){printf("%c的编码:",str[i]);printf("%s\n",hc[i]);}}void main(){int i,j,k;char str[50];int weight[50];printf("请输入字符(一次性连续输入所求的字符):");/*如:abcjhjg不要输成ab cj hig,即字符间不加空格*/gets(str);for(j=0;j<50;j++){if(str[j]=='\0')break;}const int n=j;for(j=n;j>0;j--)str[j]=str[j-1];str[n+1]='\0';for(k=0;k<n;k++){printf("请输入%c的权值:",str[k+1]);scanf("%d",&weight[k]);}for(k=n;k>0;k--)weight[k]=weight[k-1];weight[0]=0;HUFFMANCODE hc=NULL;HUFFMANTREE ht;ht=huffmantree(n,weight);huffmancoding(n,hc,ht,str);}补充:噢,我忘了你需要存档。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
算法与数据结构课程设计哈夫曼编码/译码器设计学生姓名:学号:专业:(计算机科学与技术)年级:(大二)指导教师:(汪洋)2009年6月19日哈夫曼编码/译码器问题描述:利用哈夫曼编码进行通信可以大大提高信道利用率,缩短信息传输时间,降低传输成本,但是,这要求在发送端通过一个编码系统对待传数据预先编码,在接收端将传来的数据进行译码(复原)。
对于双工信道(即可以双向传输信息的信道)每端都需要一个完整的编/译码系统。
试为这样的信息收发站写一哈夫曼编/译码系统。
基本要求:I:初始化(Initialization)。
从终端读入字符集大小n,以及n个字符和n个权值,建立哈夫曼树,并将它存于文件hfmTree中。
E:编码(Encoding)。
利用已建好的哈夫曼树(如不在内存,则从文件hfmTree中读入),对文件ToBeTran中的正文进行编码,然后将结果存入文件CodeFile中。
D:译码(Decoding)。
利用已建好的哈夫曼树将文件CodeFile中的代码进行译码,结果存入文件TextFile中。
P:打印代码文件(Print)。
将文件CodeFile以紧凑格式显示在终端上,每行50个代码。
同时将此字符形式的编码文件写入文件CodePrin中。
T:打印哈夫曼树(Tree printing)。
将已在中的哈夫曼树以直观的方式(树或凹入表形式)显示在终端上,同时将此字符形式的哈夫曼树写入文件TreePrint中。
大体解题思路:(1)对输入的一段欲编码的字符串进行统计各个字符出现的次数,并它们转化为权值{w1,w2,……,wN}构成n棵二叉树的集合F={T1,T2,……,Tn}把它们保存到结构体数组HT[n]中,其中{Ti是按它们的ASCⅡ码值先后排序。
其中每棵二叉树Ti中只有一个带权为Wi的根结点的权值为其左、右子树上根结点的权值之和。
(2)在HT[1..i]中选取两棵根结点的权值最小且没有被选过的树作为左右子树构造一棵新的二叉树,且置新的二叉树的根结点的权值为左、右子树上根结点的权值之和。
(3)哈夫曼树已经建立后,从叶子到根逆向求每一个字符的哈夫曼编码。
概要设计:实现的功能:1.查看原文(showpassage()),2.字符统计(showdetail()),3.哈夫曼编码并输出内容(HuffmanCoding(HT,HC,30,w)),4.输出整篇文章的码字(printcode()),5.求最小权值(minweight()),6.最码字进行解码(decode()),7.测试解码(testdecode()),8.推出(break)。
(1)定义结构体HTNOde,*HuffmanTree;typedefchar**HuffmanCode;定义堆结构体RedType;定义全局变量;(2)编程序:测试编码(void testdecode());解码(void decode);求最小权值(void minweight());打印码字(voidprintcode());堆排序(void HeapAdjust(SqList&L,ints,int m));哈夫曼编码(voidHuffmanCoding(HuffmanTree &HT,HuffmanCode&HC,float *w,int n ));输出个字符的次数比例(voidshowdetail());输出原英文文章并做统计(voidshowpassage());(3)主函数详细设计:(1)定义结构体1.哈夫曼结构体typedef struct{float weight;unsigned int parent, lchild, rchild;}HTNode, *HuffmanTree;typedef char **HuffmanCode ;2.堆结构体typedef struct{float key; //关键字项int otherinfo; //其他数据项(此题目中用不到)}RedType;typedef struct{RedType r[MAXSIZE+1]; //r[0]闲置用作哨兵int length; //顺序表长度}SqList;3.定义全局变量HuffmanTree HT; //赫夫曼树HuffmanCode HC; //码值FILE *fp, *fp1, *fp2;int a[30] = {0};float b[30];float *w; //权(2)程序代码1.测试解码(可以输入一个不正确的二进制码串)void testdecode(){char str[200]; //存放自己输入的码子int p, p1, i; //解码的线索char ch;printf("\n请根据以上各个字符的编码输入一串二进制码字(200个以内):\n");gets(str);printf("以上码子解码后为:\n");p = 59; //最初令p为树根整数,p由根顺着树枝一直到树叶i = 0;ch = str[i++];while (ch!='\0'){for ( ; ch!='\0' && (HT[p].lchild!=0||HT[p].rchild!=0) ; ){if (ch == '0'){p = HT[p].lchild;}else if(ch == '1'){p = HT[p].rchild;}else{printf("\n你输入了'0','1'之外的字符,无法正确译码,请检查!\n");return ; //直接结束}ch = str[i++]; //下一个码字不断的取下一个}if(p <= 30) //小于等于30的时候才正确,有可能最后一位p还没有在1-30范围内的时候就没有二进制码了,也就是说二进制码最后不完整。
switch (p){case 27 : printf(",");break;case 28 : printf(".");break;case 29 : printf(" ");break;case 30 : printf("\n");break;default : printf("%c", p+96);}p1 = p; //让p1记住pp = 59; //这里p要重置为59,因为经过上面的程序p已经变化了,不重置为1则HT[p].lchild!=0||HT[p].rchild!=0所以for语句无法进行} //while循环if (p1 > 30)printf("\n以上正确译出了前面的字符,由于你输入的二进制码不完整,最后一位字符无法译出,请检查!\n");}2.下面是解码void decode(){int p;char ch;printf("\n\n对码子解码后的如下:\n");fp1 = fopen("bianma.txt","r");if(!fp1){printf("can not open this file!\n");exit(0);}p = 59; //最初令p为任意一个非零整数,p由根顺着树枝一直到树叶ch = fgetc(fp1);fp2 = fopen("jiema.txt","w");if (!fp2){printf("can not open this file!\n");exit(0);}while (ch!=EOF){for ( ; HT[p].lchild!=0||HT[p].rchild!=0 ; ){if (ch == '0'){p = HT[p].lchild;}else{p = HT[p].rchild;}ch = fgetc(fp1); //下一个码字不断的取下一个}switch (p){case 27 : printf(",");fprintf(fp2,",");break;case 28 : printf(".");fprintf(fp2, ".");break;case 29 : printf(" ");fprintf(fp2, " ");break;case 30 : printf("\n");fprintf(fp2, "\n");break;default : printf("%c", p+96);fprintf(fp2, "%c", p+96);} p = 59; //这里p要重置为59,因为经过上面的程序p已经变化了,不重置为1则HT[p].lchild!=0||HT[p].rchild!=0所以for语句无法进行} //while循环printf("\n");fprintf(fp2, "\n");fclose(fp1);fclose(fp2);}3.求最小权值void minweight(){float Weight = 0;int i;for (i = 0 ; i < 30 ; i++)Weight = Weight + strlen(HC[i+1])*b[i];printf("最小权值是:%f\n",Weight);}4.打印码子void printcode(){char ch;fp = fopen("Huffman.txt","r");if (!fp){printf("can not open this file!\n");exit(0);}fp1 = fopen("bianma.txt","w");if (!fp1){printf("can not open this file!\n");exit(0);}printf("\n原英文文章经编码后如下:\n");ch = fgetc(fp);while (ch!=EOF){if (ch > 96 && ch < 123) //小写字母{printf("%s", HC[ch-96]);fputs(HC[ch-96], fp1); //输出到文件里面ch = fgetc(fp);continue;}if (ch > 64 && ch < 91) //大小字母{ printf("%s", HC[ch-64]);fputs(HC[ch-64], fp1); //输出到文件里面ch = fgetc(fp);continue;}if (ch == ','){printf("%s", HC[27]);fputs(HC[27], fp1);ch = fgetc(fp);continue;}if (ch == '.'){printf("%s", HC[28]);fputs(HC[28], fp1);ch = fgetc(fp);continue;}if (ch == ' '){printf("%s", HC[29]);fputs(HC[29], fp1);ch = fgetc(fp);continue;}if (ch == '\n'){printf("%s", HC[30]);fputs(HC[30], fp1);ch = fgetc(fp);continue;}}printf("\n\n");fclose(fp);fclose(fp1);}5.堆排序void HeapAdjust(SqList &L, int s, int m) {RedType rc;int j;rc = L.r[s];for (j = 2 * s ; j <= m ; j*=2){if (j < m && L.r[j].key > L.r[j+1].key) //即使等于也不要动,不用加1 ++j;if (rc.key <= L.r[j].key) //即使等于也不要动,直接跳出来break;L.r[s] = L.r[j];s = j;}L.r[s] = rc;}void select(HuffmanTree t, int i, int &s1, int &s2){ //此函数被调用一次则就用堆排序选择两个最小的赋给s1和s2SqList L;RedType rc;int j, k, n = 1;L.length = 0;for (j = 1 ; j <= i ; j++){ if (t[j].parent!=0)continue;L.r[n].key = t[j].weight; //赋值好,用堆排序L.r[n].otherinfo = j; //存放序号,j是一直在加一的,循环一次加1,但是n不是的只有在符合条件的情况下才加1n++;L.length++; //这样写很巧妙的}for (k = L.length/2 ; k > 0 ; --k)HeapAdjust(L,k,L.length);s1 = L.r[1].otherinfo; //最小的选出来了!/***把最小的换到最下面***/rc = L.r[1];L.r[1] = L.r[L.length]; //此次的select函数,进行堆排序的只有L.length 个(parent!=0的没有在里面),所以这里是L.length 而不是iL.r[L.length] = rc;HeapAdjust(L,1,L.length-1);s2 = L.r[1].otherinfo; //次小的选出来了(这里当输入1 4 2 8四个数时,第一次选出的s1=1,s2=3是对的,但第二次选出的s1=5,但s2是随机数)}6.赫夫曼编码void HuffmanCoding(HuffmanTree &HT, HuffmanCode &HC, float *w, int n) // 算法6.12{ // w存放n个字符的权值(均>0),构造赫夫曼树HT,并求出n个字符的赫夫曼编码HCint m, i, s1, s2, start, k;unsigned c, f;HuffmanTree p;char *cd;if (n <= 1)return;m = 2 * n - 1;w = (float *)malloc(30*sizeof(float));for (i = 0 ; i < 30 ; i++)*(w+i) = b[i];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 = n + 1 ; 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; //最小的和次小的双亲已经不为0了,下次就不在它两中间找最小的和次小的了。