数据结构实验报告八—哈夫曼编译码
数据结构 哈夫曼编码实验报告
数据结构哈夫曼编码实验报告数据结构哈夫曼编码实验报告1. 实验目的本实验旨在通过实践理解哈夫曼编码的原理和实现方法,加深对数据结构中树的理解,并掌握使用Python编写哈夫曼编码的能力。
2. 实验原理哈夫曼编码是一种用于无损数据压缩的算法,通过根据字符出现的频率构建一棵哈夫曼树,并根据哈夫曼树对应的编码。
根据哈夫曼树的特性,频率较低的字符具有较长的编码,而频率较高的字符具有较短的编码,从而实现了对数据的有效压缩。
实现哈夫曼编码的主要步骤如下:1. 统计输入文本中每个字符的频率。
2. 根据字符频率构建哈夫曼树,其中树的叶子节点代表字符,内部节点代表字符频率的累加。
3. 遍历哈夫曼树,根据左右子树的关系对应的哈夫曼编码。
4. 使用的哈夫曼编码对输入文本进行编码。
5. 将编码后的二进制数据保存到文件,同时保存用于解码的哈夫曼树结构。
6. 对编码后的文件进行解码,还原原始文本。
3. 实验过程3.1 统计字符频率首先,我们需要统计输入文本中每个字符出现的频率。
可以使用Python中的字典数据结构来记录字符频率。
遍历输入文本的每个字符,将字符添加到字典中,并递增相应字符频率的计数。
```pythondef count_frequency(text):frequency = {}for char in text:if char in frequency:frequency[char] += 1else:frequency[char] = 1return frequency```3.2 构建哈夫曼树根据字符频率构建哈夫曼树是哈夫曼编码的核心步骤。
我们可以使用最小堆(优先队列)来高效地构建哈夫曼树。
首先,将每个字符频率作为节点存储到最小堆中。
然后,从最小堆中取出频率最小的两个节点,将它们作为子树构建成一个新的节点,新节点的频率等于两个子节点频率的和。
将新节点重新插入最小堆,并重复该过程,直到最小堆中只剩下一个节点,即哈夫曼树的根节点。
数据结构课程设计哈夫曼编码实验
数据结构设计性实验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)练习通过普通树来构造霍夫曼树。
数据结构哈夫曼编码实验报告
数据结构哈夫曼编码实验报告【正文】1.实验目的本实验旨在研究哈夫曼编码的原理和实现方法,通过实验验证哈夫曼编码在数据压缩中的有效性,并分析其应用场景和优缺点。
2.实验原理2.1 哈夫曼编码哈夫曼编码是一种无损数据压缩算法,通过根据字符出现的频率构建一颗哈夫曼树,将频率较高的字符用较短的编码表示,频率较低的字符用较长的编码表示。
哈夫曼编码的编码表是唯一的,且能够实现前缀编码,即一个编码不是另一个编码的前缀。
2.2 构建哈夫曼树构建哈夫曼树的过程如下:1) 将每个字符及其频率作为一个节点,构建一个节点集合。
2) 每次从节点集合中选择出现频率最低的两个节点,构建一个新节点,并将这两个节点从集合中删除。
3) 将新节点加入节点集合。
4) 重复以上步骤,直到节点集合中只有一个节点,这个节点就是哈夫曼树的根节点。
2.3 编码过程根据哈夫曼树,对每个字符进行编码:1) 从根节点开始,根据左子树为0,右子树为1的规则,将编码依次加入编码表。
2) 对于每个字符,根据编码表获取其编码。
3) 将编码存储起来,得到最终的编码序列。
3.实验步骤3.1 数据读取与统计从输入文件中读取字符序列,并统计各个字符的频率。
3.2 构建哈夫曼树根据字符频率构建哈夫曼树。
3.3 构建编码表根据哈夫曼树,构建每个字符的编码表。
3.4 进行编码根据编码表,对输入的字符序列进行编码。
3.5 进行解码根据哈夫曼树,对编码后的序列进行解码。
4.实验结果与分析4.1 压缩率分析计算原始数据和压缩后数据的比值,分析压缩率。
4.2 编码效率分析测试编码过程所需时间,分析编码效率。
4.3 解码效率分析测试解码过程所需时间,分析解码效率。
4.4 应用场景分析分析哈夫曼编码在实际应用中的优势和适用场景。
5.结论通过本次实验,我们深入了解了哈夫曼编码的原理和实现方法,实践了哈夫曼编码的过程,并对其在数据压缩中的有效性进行了验证。
实验结果表明,哈夫曼编码能够实现较高的压缩率和较高的编解码效率。
数据结构哈夫曼编码实验报告-无删减范文
数据结构哈夫曼编码实验报告数据结构哈夫曼编码实验报告实验背景哈夫曼编码是一种常用的数据压缩方法,通过使用变长编码来表示不同符号,将出现频率较高的符号用较短的编码表示,从而达到压缩数据的目的。
通过实现哈夫曼编码算法,我们能够更好地理解和掌握数据结构中的树形结构。
实验目的1. 理解哈夫曼编码的原理及实现过程。
2. 掌握数据结构中树的基本操作。
3. 进一步熟悉编程语言的使用。
实验过程1. 构建哈夫曼树首先,我们需要根据给定的字符频率表构建哈夫曼树。
哈夫曼树是一种特殊的二叉树,其叶子节点表示字符,而非叶子节点表示字符的编码。
构建哈夫曼树的过程如下:1. 根据给定的字符频率表,将每个字符视为一个节点,并按照频率从小到大的顺序排列。
2. 将频率最小的两个节点合并为一个新节点,并将其频率设置为两个节点的频率之和。
这个新节点成为新的子树的根节点。
3. 将新节点插入到原来的节点列表中,并继续按照频率从小到大的顺序排序。
4. 重复步骤2和步骤3,直到只剩下一个节点,这个节点即为哈夫曼树的根节点。
2. 哈夫曼编码表在构建完哈夫曼树后,我们需要根据哈夫曼树每个字符的哈夫曼编码表。
哈夫曼编码表是一个字典,用于存储每个字符对应的编码。
哈夫曼编码表的过程如下:1. 从哈夫曼树的根节点出发,遍历整个树。
2. 在遍历的过程中,维护一个路径,用于记录到达每个字符节点的路径,0表示左子树,1表示右子树。
3. 当到达一个字符节点时,将路径上的编码存储到哈夫曼编码表中对应的字符键下。
3. 压缩数据有了哈夫曼编码表后,我们可以使用哈夫曼编码对数据进行压缩。
将原本以字符表示的数据,转换为使用哈夫曼编码表示的二进制数据。
压缩数据的过程如下:1. 将待压缩的数据转换为对应的哈夫曼编码,将所有的编码连接成一个字符串。
2. 将该字符串表示的二进制数据存储到文件中,同时需要保存哈夫曼编码表以便解压时使用。
实验结果通过实验,我们成功实现了哈夫曼编码的构建和使用。
数据结构哈夫曼编码实验报告
数据结构哈夫曼编码实验报告
第一章实验目的
本实验旨在掌握哈夫曼编码的原理和实现方法,并通过编写代码实现一个简单的哈夫曼编码程序。
第二章实验内容
1.理解哈夫曼编码的基本概念和原理。
2.设计并实现一个哈夫曼编码的数据结构。
3.实现哈夫曼编码的压缩和解压缩功能。
4.通过实验验证哈夫曼编码的效果和压缩比。
第三章实验步骤
1.确定实验所需的编程语言和开发环境。
2.定义并实现哈夫曼编码的数据结构。
3.实现哈夫曼编码的压缩和解压缩算法。
4.设计实验样例数据,进行测试和验证。
5.分析实验结果,计算压缩比。
第四章实验结果与分析
1.实验样例数据:________提供一段文本,统计字符出现的频率,并进行哈夫曼编码。
2.实验结果:________展示压缩后的编码结果,计算压缩比。
3.分析:________分析实验结果,讨论哈夫曼编码的效果和优劣。
第五章实验总结与感想
本次实验深入了解了哈夫曼编码的原理和实现方法,通过编写代码实现哈夫曼编码的压缩和解压缩功能。
实验结果表明,哈夫曼编码能够有效地减小数据的存储空间,提高了数据传输的效率。
第六章本文档涉及附件
本实验报告所涉及到的附件包括:________
1.实验代码文件:________.c
2.实验样例数据文件:________.txt
第七章法律名词及注释
1.哈夫曼编码:________一种用于无损数据压缩的编码方法,通过对频率高的字符赋予较短的编码,对频率低的字符赋予较长的编码,从而实现压缩数据的目的。
哈夫曼编码译码器实验报告
哈夫曼编码译码器实验报告实验名称:哈夫曼编码译码器实验一、实验目的:1.了解哈夫曼编码的原理和应用。
2.实现一个哈夫曼编码的编码和译码器。
3.掌握哈夫曼编码的编码和译码过程。
二、实验原理:哈夫曼编码是一种常用的可变长度编码,用于将字符映射到二进制编码。
根据字符出现的频率,建立一个哈夫曼树,出现频率高的字符编码短,出现频率低的字符编码长。
编码过程中,根据已建立的哈夫曼树,将字符替换为对应的二进制编码。
译码过程中,根据已建立的哈夫曼树,将二进制编码替换为对应的字符。
三、实验步骤:1.构建一个哈夫曼树,根据字符出现的频率排序。
频率高的字符在左子树,频率低的字符在右子树。
2.根据建立的哈夫曼树,生成字符对应的编码表,包括字符和对应的二进制编码。
3.输入一个字符串,根据编码表将字符串编码为二进制序列。
4.输入一个二进制序列,根据编码表将二进制序列译码为字符串。
5.比较编码前后字符串的内容,确保译码正确性。
四、实验结果:1.构建哈夫曼树:-字符出现频率:A(2),B(5),C(1),D(3),E(1) -构建的哈夫曼树如下:12/\/\69/\/\3345/\/\/\/\ABCDE2.生成编码表:-A:00-B:01-C:100-D:101-E:1103.编码过程:4.译码过程:5.比较编码前后字符串的内容,结果正确。
五、实验总结:通过本次实验,我了解了哈夫曼编码的原理和应用,并且实现了一个简单的哈夫曼编码的编码和译码器。
在实验过程中,我充分运用了数据结构中的树的知识,构建了一个哈夫曼树,并生成了编码表。
通过编码和译码过程,我进一步巩固了对树的遍历和节点查找的理解。
实验结果表明,本次哈夫曼编码的编码和译码过程正确无误。
在实验的过程中,我发现哈夫曼编码对于频率较高的字符具有较短的编码,从而实现了对字符串的高效压缩。
同时,哈夫曼编码还可以应用于数据传输和存储中,提高数据的传输效率和存储空间的利用率。
通过本次实验,我不仅掌握了哈夫曼编码的编码和译码过程,还深入了解了其实现原理和应用场景,加深了对数据结构和算法的理解和应用能力。
数据结构哈夫曼树编码译码实验报告
【详细设计】具体代码实现如下://HaffmanTree、h#include〈iostream>#include<fstream>#include〈string〉struct HuffmanNode //哈夫曼树得一个结点{int weight;int parent;int lchild,rchild;};class HuffmanTree //哈夫曼树{private:HuffmanNode *Node; //Node[]存放哈夫曼树char *Info; //Info[]存放源文用到得字符——源码,如’a’,'b','c',’d',’e’,此内容可以放入结点中,不单独设数组存放int LeafNum; //哈夫曼树得叶子个数,也就是源码个数public:HuffmanTree();~HuffmanTree();voidCreateHuffmanTree(); /*在内存中建立哈夫曼树,存放在Node[]中. 让用户从两种建立哈夫曼树得方法中选择:ﻩﻩﻩ1、从键盘读入源码字符集个数,每个字符,与每个字符得权重,建立哈夫曼树,ﻩ并将哈夫曼树写入文件hfmTree中。
2、从文件hfmTree 中读入哈夫曼树信息,建立哈夫曼树*/void CreateHuffmanTreeFromKeyboard();void CreateHuffmanTreeFromFile();voidEncoder(); /*使用建立好得哈夫曼树(如果不在内存,则从文件hfmTre e中读入并建立内存里得哈夫曼树),ﻩﻩ对文件ToBeTran中得正文进行编码,并将码文写入文件CodeFile中.ﻩﻩﻩToBeTran得内容可以用记事本等程序编辑产生。
*/void Decoder(); /*待译码得码文存放在文件CodeFile中,使用建立好得哈夫曼树(如果不在内存,ﻩﻩ则从文件hfmTree中读入并建立内存里得哈夫曼树)将码文译码,ﻩ得到得源文写入文件TextFile中,并同时输出到屏幕上。
数据结构 哈夫曼编码实验报告(2023版)
数据结构哈夫曼编码实验报告实验目的:本实验旨在了解和实现哈夫曼编码算法,通过将字符转换为对应的哈夫曼编码来实现数据的压缩和解压缩。
一、引言1.1 背景介绍哈夫曼编码是一种基于字符出现频率的编码方法,通过使用不等长编码来表示不同字符,从而实现数据的高效压缩。
该编码方法在通信、存储等领域有着广泛的应用。
1.2 目标本实验的目标是实现哈夫曼编码算法,通过对给定文本进行编码和解码,验证哈夫曼编码的有效性和可靠性。
二、实验过程2.1 数据结构设计在实现哈夫曼编码算法时,我们需要设计合适的数据结构来存储字符和对应的编码。
常用的数据结构包括树和哈希表。
我们将使用二叉树作为数据结构来表示字符的编码。
2.2 构建哈夫曼树哈夫曼树是由给定字符集合构建而成的最优二叉树。
构建哈夫曼树的过程分为两步:首先根据字符出现频率构建叶子节点,然后通过合并叶子节点和父节点构造哈夫曼树。
2.3 哈夫曼编码表根据构建好的哈夫曼树,我们可以对应的哈夫曼编码表。
哈夫曼编码表由字符和对应的编码组成,可以用于字符的编码和解码。
2.4 文本压缩利用的哈夫曼编码表,我们可以对给定的文本进行压缩。
将文本中的字符逐个替换为对应的哈夫曼编码,从而实现数据的压缩。
2.5 文本解压缩对压缩后的数据进行解压缩时,我们需要利用的哈夫曼编码表,将哈夫曼编码逐个替换为对应的字符,从而还原出原始的文本数据。
三、实验结果我们使用不同长度、不同频率的文本进行了实验。
实验结果表明,哈夫曼编码在数据压缩方面有着显著的效果,可以大大减小数据存储和传输的开销。
四、实验总结通过本实验,我们深入理解了哈夫曼编码算法的原理和实现过程,掌握了数据的压缩和解压缩技术。
哈夫曼编码作为一种经典的数据压缩算法,具有重要的理论意义和实际应用价值。
附件:本文档附带哈夫曼编码实验的源代码和实验数据。
法律名词及注释:在本文档中,涉及的法律名词和注释如下:1.哈夫曼编码:一种数据压缩算法,用于将字符转换为可变长度的编码。
数据结构 哈夫曼编码实验报告
数据结构哈夫曼编码实验报告数据结构实验报告----------1-实验目的----------本实验的目的是通过实现哈夫曼编码算法,加深对数据结构中树和堆的理解,以及掌握相关的编程技巧。
2-实验内容----------2-1 算法简介----------哈夫曼编码是一种无损压缩算法,通过根据字符出现的频率构建一颗二叉树,并将出现频率较高的字符编码为较短的二进制串,进而实现压缩的目的。
在本实验中,我们需要实现以下功能:●构建哈夫曼树●字符编码表●对给定的字符串进行编码●对给定的二进制串进行解码●实现压缩和解压缩功能2-2 数据结构----------在实现哈夫曼编码算法时,我们需要使用以下数据结构:●链表:用于存储字符出现的频率及对应的字符●堆:用于构建哈夫曼树●树:用于存储哈夫曼编码树●散列表或映射:用于存储字符的编码2-3 算法步骤----------1-统计字符的出现频率,并构建频率链表2-根据频率链表构建哈夫曼树3-字符的编码表4-对给定的字符串进行编码5-对给定的二进制串进行解码6-实现压缩和解压缩功能3-实验实现----------3-1 数据结构的设计----------在本实验中,我们将使用以下数据结构:●链表节点结构体:用于存储字符和频率●链表结构体:用于存储链表节点的头指针●堆节点结构体:用于存储字符和频率,并维护堆的结构●堆结构体:用于存储堆的根节点●树节点结构体:用于存储字符和编码,并维护哈夫曼树的结构●树结构体:用于存储哈夫曼树的根节点●散列表结构体:用于存储字符和对应的编码3-2 算法实现----------1-统计字符的出现频率并构建频率链表:遍历给定的字符串,统计字符的频率,并将字符频率按从小到大的顺序插入到频率链表中。
2-根据频率链表构建哈夫曼树:将频率链表的节点插入到堆中,并按照堆的定义调整堆的结构,直到堆中只有一个节点。
3-字符的编码表:遍历哈夫曼树,递归构造字符的编码表。
数据结构课程设计报告哈夫曼编码译码器
西安郵電學院数据结构课程设计报告题目1:哈夫曼编码/译码器题目2:学生信息管理系统系部名称:通信工程系专业名称:通信工程班级:****学号:*****学生姓名:****指导教师:*****时间:2009年12月16日至2009年12月25日题目1.哈夫曼编码/译码器一、课程设计目的通过对哈夫曼编码/译码器的实现,熟悉了解Huffman树的创建过程以及存储结构,对Huffman编码/译码过程及原则有了更深层次的认识,锻炼了动手能力,使知识更好的学以致用,为解决数据压缩问题提供方法。
二、课程设计内容通过统计文件中各字符的出现频率,建立Huffman树,再通过建立的已经Huffman的树,对文件中各字符进行编码,将结果存入新的文件中,然后从文件中读取Huffman编码,进行解码,结果存入新的文件中,并与源文件进行比较。
三、需求分析1.统计字符频率:存文件中读入字符,并对各字符出现频率进行统计;2.建立Huffman树:将各字符出现的频率作为权值,建立Huffman树;3.Huffman编码:通过已经建立的Huffman树,对个各字符进行编码,并存入新的文件中;4.译码:读取存放Huffman编码的文件,对文件中编码进行译码,把译码结果存入新的文件中;5.结果验证:将译码结果与原文件内容进行比较;四、概要设计1. 系统结构图(功能模块图)2.功能模块说明1:统计字符频率: 定义结构体 typedef struct str {char data; char num; }str;其中data 域存放字符名称,num 域存放字符出现频率,读取文件ywq1.txt ,通过循环比较将结果赋入S2[128]中;2:创建Huffman 树: 定义结构体 typedef struct {char data; int weight; int parent; int lchild;开始 main ()统计字符频率创建Huffman 树对文件编码对编码译码出现次数 字符名称初 始 化 结点赋值Huffma 编码 存入文件读取编码 存入文件对编码译码 对编码译码成功 失败int rchild;}HTNode,HuffmanTree[M+1];作为Huffman树存储节点类型,调用CrtHuffmanTree()函数,初始化各节点均为0;然后将存储字符频率的数组S2的值赋值给各节点,字符出现频率作为权值,创建Huffman树;3:对文件编码:定义结构体typedef struct{char data;char bits[N+1];}CodeNode,HuffmanCode[N];作为HuffmanCode的存储类型,调用CrtHuffmanCode()函数,从叶子节点向上回溯,是lchild则赋值‘0’,是rchild则赋值为‘1’,对各字符编码,再调用WriteToFile()函数,将结果写入文件ywq2.txt中;4:对文件译码:读取编码文件ywq2.txt中数据,调用DecodHuffmanCode()函数,从根节点开始,读取‘1’,走向rchild,读取‘0’, 走向lchild,直到叶子节点,将叶子节点data域的值写入文件ywq3.txt中;五、详细设计及运行结果1.读文件统计字符频率(read()函数中实现):源文件ywq1.txt :打开源文件 ywq1.txt读文件内的字符,初始化数组s1文件是否结束将字符存入数组 S1[ch].num++读下一个字符给数组末尾加上结束标志“\0”关闭文件是否开始结束运行结果:2:创建Huffman树,CrtHuffmanTree():运行结果:初始化结构体数组htCrtHuffmanTree()有n棵二叉树n > 1选权值最小2个二叉树权值相加得新二叉树n - 1n = 1建立Huffman树结束3:Huffman编码,CrtHuffmanCode();运行结果:CrtHuffmanCode()根cd[--start] = ‘0’cd[--start] = ‘1’否Lchild Rchild cd[start] 赋给hc[i].bits是结束对应字符编码写入文件ywq2.txt编码文件ywq2.txt:3:译码,DecodHuffmanCode():运行结果:文件ywq3.txt:DecodHuffmanCode()打开文件ywq2.txt 读取字符ch文件结束否否找根节点ch = ‘0’, 找lchild ; ch = ‘1’, 找rchild ;叶子节点是是保存 ywq3.txt是结束4:结果验证:比较源文件ywq1.txt 与译码文件ywq3.txt 可知,译码结果与源文件一致。
哈弗曼编码数据结构实验报告
数据结构实验报告哈夫曼编码一、需求分析:哈夫曼编码可以进行求取最优二叉树,以及进行编码等实际问题,当利用哈夫曼树做前缀编码,有效的节约存储密码的时间。
二、概要设计:首先定义一个哈弗曼树结构体,哈夫曼编码数组之后,编写输入函数(包括存到文件的部分),哈弗曼构造函数(从文件中调用构造),求哈夫曼编码函数,输出函数(打印出哈夫曼编码)等。
三、详细设计:下为程序源代码:#include<stdio.h>#include<stdlib.h>#include<string.h>#include<ctype.h>#define Maxsize 100typedef struct{char data;double weight;int parent;int lchild;int rchild;}HTNode;HTNode ht[Maxsize];typedef struct{char cd[Maxsize];int start;}HCode;HCode hcd[Maxsize];void Initialization(char str[], double w[], int n);void getn(char str[], double w[], int *n);void writehfmTree(int n);void Encoding(int n);void ReadhfmTree(void);void Decoding(int n);void TreePrint(int i);void Menu(char *ch);int getnumber(char *ch, int repeat);void Initialization(char str[], double w[], int n) //构造哈弗曼树{int i,k,lnode,rnode;double min1, min2;for(i=0; i<n; i++){ht[i].data = str[i];ht[i].weight = w[i];}for(i=0; i<2*n-1; i++)ht[i].lchild = ht[i].parent = 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[i].weight = ht[lnode].weight + ht[rnode].weight;ht[i].lchild = lnode;ht[i].rchild = rnode;ht[lnode].parent = i;ht[rnode].parent = i;}writehfmTree(n);}void getn(char str[], double w[], int *n){int i;FILE *fp;if((fp=fopen("ToBeTran", "w"))==NULL){printf("Can not open the file\n");exit(0);}printf("请输入字符集:");gets(str);gets(str);*n = strlen(str);for(i=0; i<*n; i++){printf("请输入%d个权值:", i+1);scanf("%lf",&w[i]);}for(i=0; i<*n; i++)fprintf(fp, "%c", str[i]);fclose(fp);}void writehfmTree(int n) //把哈弗曼树存入hrmTree文件中{int i;FILE *fp;if((fp=fopen("hfmTree","w"))==NULL){printf("Can not open the file\n");exit(0);}for(i=0; i<n; i++){fputc(ht[i].data, fp);fprintf(fp, "%.2f", ht[i].weight);}fprintf(fp,"\n");printf("存在文件hfmTree中的哈弗曼树形式为:\n");for(i=0; i<n; i++){putchar(ht[i].data);putchar('-');printf("%.2f ", ht[i].weight);}printf("\n文件hfmTree写入成功!\n");fclose(fp);}void Encoding(int n) //哈弗曼编码,并存于文件CodeFile中{int i, j, k, f, c;HCode hc;FILE *fp, *fp1;char text[Maxsize];ReadhfmTree();if((fp1=fopen("ToBeTran","r"))==NULL){printf("Can not open the file\n");exit(0);}fgets(text, Maxsize, fp1);printf("要进行编码的字符串是:\n");puts(text);fclose(fp1);if((fp=fopen("CodeFile","w"))==NULL){printf("Can not open the file\n");exit(0);}for(i=0; i<n; i++){hc.start = n;c=i;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++;hcd[i]=hc;}i=0;while(text[i]!='\0'){j=0;while(text[i]!=ht[j].data){j++;}for(k=hcd[j].start; k<=n; k++){fprintf(fp, "%c", hcd[j].cd[k]);}fputc(' ', fp);i++;}printf("编码结果如下:\n");i=0;while(text[i]!='\0'){j=0;while(text[i]!=ht[j].data){j++;}for(k=hcd[j].start; k<=n; k++){printf("%c", hcd[j].cd[k]);}printf(" ");i++;}printf("\n文件CodeFile写入成功!\n");fclose(fp);}void ReadhfmTree(void) //从内存中读入哈弗曼树,或从文件hfmTree文件中读取哈弗曼树{FILE *fp;char str[Maxsize];double w[Maxsize];int i=0, n;if(sizeof(ht)!=0)printf("内存中已存有哈弗曼树!\n");else{printf("内存中哈弗曼树不存在,从文件中读取数据重新构造哈弗曼树!\n");if((fp=fopen("hfmTree","r"))==NULL){printf("Can not open the file\n");exit(0);}do{fscanf(fp, "%c", &str[i]);fscanf(fp, "%lf", &w[i]);i++;}while(str[i]!='\n');n = i-2;Initialization(str, w, n);fclose(fp);}}void Decoding(int n)//从文件CodeFile中读入哈弗曼树编码,进行译码,将译码结果存入TextFile文件中{int i=0, j=0, k=0, l=0, num;char *text[Maxsize], str[Maxsize][Maxsize];FILE *fp, *fp1;if((fp=fopen("CodeFile","r"))==NULL){printf("Can not open the file “CodeFile”\n");exit(0);}if((fp1=fopen("TextFile","w"))==NULL){printf("Can not open the file “TextFile”\n");exit(0);}for(i=0; i<Maxsize; i++)text[i] = str[i];i=0;while(fscanf(fp, "%s", text[i])==1)i++;num = i;for(i=0; i<num; i++){l=0;j=0;k=hcd[l].start;while(1){if(hcd[l].cd[k]!=text[i][j]){l++;j=0;k=hcd[l].start;}else{j++;k++;}if(j==(signed)strlen(text[i]) && k==n+1)break;}fprintf(fp1, "%c", ht[l].data);}printf("译码结果如下:\n");for(i=0; i<num; i++){l=0;j=0;k=hcd[l].start;while(1){if(hcd[l].cd[k]!=text[i][j]){l++;j=0;k=hcd[l].start;}else{j++;k++;}if(j==(signed)strlen(text[i]) && k==n+1)break;}printf("%c", ht[l].data);}printf("\n文件TextFile写入成功!\n");fclose(fp);fclose(fp1);}void Print(void)//将文件CodeFile以紧凑个数显示在终端上,每行50个代码。
数据结构试验报告-哈弗曼编码
实验报告:哈弗曼编码班级:姓名:学号:一、需求分析:1.利用哈弗曼编码进行通信时可以大大提高信息利用率,缩短信息传输时间,降低传输成本;2.哈夫曼编码对终端“明文”文件中的正文进行编码,然后将结果存入“密文”中。
同时也可以将“密文”进行译码,提高了信息的安全性;3.输入输出的要求:要求在输入和输出端都有一个完整的编/译码系统,用户按照提示内容从键盘输入命令,系统根据用户输入的命令在保证界面友好的前提下输出用户所需要的信息,并按要求保存文件,以便保存备份信息;4.测试数据;1)令叶子节点的个数为4,权值集合为:w[]={5,7,11,6};2)令叶子节点的个数为8,权值集合为:w[]={7, 5, 2, 4, 14, 23, 3, 11};二、概要设计:1.定义哈弗曼编码数据结构类型:ADT Huffman{数据对象:D={ ai |ai 属于字符数集,i=1,2,3,4……n n>=0}数据关系:R1={<ai-1, ai >| ai-1, ai ∈D,ai-1< ai ,i=2……n}基本操作:void HuffmanCoding(HuffmanTree &HT, HuffmanCode &HC, int *w, int n)初始条件:HT,HC,w,n等都存在操作结果:将w数组内的数都转化到HT内的哈夫曼树内,然后将哈夫曼树内的数据转化到HC这个代码中,全部转化成只有0和1这两个二进制数的一串译码。
void Select(HuffmanTree &HT, int s, int &s1, int &s2)初始条件:HT这个哈夫曼树存在操作结果:通过该个函数,将原来的哈夫曼树扩展成为有权值,双亲,左孩子,右孩子等四个值得哈夫曼树。
并用s1,s2两个字将双亲为0中权值最小的两个的下标返回到HuffmanCoding函数中,改变哈夫曼树。
哈夫曼编码译码实训报告
一、实训目的本次实训旨在通过实际操作,使学生掌握哈夫曼编码的基本原理和方法,熟悉哈夫曼树的构建过程,并能够熟练地进行哈夫曼编码和译码操作。
通过实训,提升学生对数据压缩技术的理解和应用能力。
二、实训内容1. 哈夫曼树构建- 收集给定字符串中每个字符的出现频率。
- 根据字符频率构建哈夫曼树,其中频率高的字符对应较大的权重。
- 使用优先队列(最小堆)实现哈夫曼树的构建。
2. 哈夫曼编码- 遍历哈夫曼树,为每个叶子节点分配唯一的编码,左分支为0,右分支为1。
- 根据分配的编码生成字符编码表。
3. 哈夫曼译码- 使用生成的编码表,将编码字符串转换回原始字符串。
三、实训步骤1. 数据准备- 选择一段英文或中文文本作为输入数据。
2. 构建哈夫曼树- 统计输入数据中每个字符的出现频率。
- 使用优先队列构建哈夫曼树。
3. 生成哈夫曼编码- 遍历哈夫曼树,为每个叶子节点分配编码。
- 生成字符编码表。
4. 编码数据- 使用哈夫曼编码表对输入数据进行编码。
5. 译码数据- 使用哈夫曼编码表对编码后的数据进行译码。
6. 结果分析- 比较编码前后数据的大小,分析哈夫曼编码的压缩效果。
四、实训结果1. 哈夫曼树构建- 成功构建了给定字符串的哈夫曼树。
2. 哈夫曼编码- 成功生成了每个字符的哈夫曼编码。
3. 哈夫曼译码- 成功将编码后的数据译码回原始字符串。
4. 压缩效果分析- 通过对比编码前后数据的大小,验证了哈夫曼编码的压缩效果。
五、实训总结1. 哈夫曼编码原理- 哈夫曼编码是一种基于字符频率的变长编码方法,能够有效降低数据传输的冗余度。
2. 哈夫曼树构建- 哈夫曼树的构建是哈夫曼编码的关键步骤,通过优先队列(最小堆)实现。
3. 哈夫曼编码与译码- 哈夫曼编码和译码过程相对简单,但需要正确处理编码表和字符编码。
4. 实训收获- 通过本次实训,掌握了哈夫曼编码的基本原理和方法,熟悉了哈夫曼树的构建过程,并能够熟练地进行哈夫曼编码和译码操作。
数据结构哈夫曼树编码译码实验报告
【仔细安排】之阳早格格创做简曲代码真止如下:#include<iostream>#include<fstream>#include<string>struct HuffmanNode //哈妇曼树的一个结面{int weight;int parent;int lchild,rchild;};class HuffmanTree //哈妇曼树{private:HuffmanNode *Node; //Node[]存搁哈妇曼树char *Info; //Info[]存搁源文用到的字符——源码,如'a','b','c','d','e',此真质不妨搁进结面中,不但独设数组存搁 int LeafNum; //哈妇曼树的叶子个数,也是源码个数public:HuffmanTree();~HuffmanTree();void CreateHuffmanTree(); /*正在内存中修坐哈妇曼树,存搁正在Node[]中. 让用户从二种修坐哈妇曼树的要领中采用:1.从键盘读进源码字符集个数,每个字符,战每个字符的权沉,修坐哈妇曼树,并将哈妇曼树写进文献hfmTree中.2.从文献hfmTree中读进哈妇曼树疑息,修坐哈妇曼树*/void CreateHuffmanTreeFromKeyboard();void CreateHuffmanTreeFromFile();void Encoder(); /*使用修坐佳的哈妇曼树(如果不正在内存,则从文献hfmTree中读进并修坐内存里的哈妇曼树),对于文献ToBeTran中的正文举止编码,并将码文写进文献CodeFile中.ToBeTran的真质不妨用记事本等步调编写爆收.*/void Decoder(); /*待译码的码文存搁正在文献CodeFile 中,使用修坐佳的哈妇曼树(如果不正在内存,则从文献hfmTree中读进并修坐内存里的哈妇曼树)将码文译码,得到的源文写进文献TextFile中,并共时输出到屏幕上.*/ void PrintCodeFile(); /*将码文文献CodeFile隐现正在屏幕上*/void PrintHuffmanTree(); /*将哈妇曼树以曲瞅的形式(凸进表示法,或者广义表,或者其余树形表示法)隐现正在屏幕上,共时写进文献TreePrintFile中*/void PrintHuffmanTree_aoru(int T,int layer=1); /*凸进表示法隐现哈妇曼树,由PrintHuffmanTree()调用*/};#include<string>#include<limits> //为使用整型最大值#include"HuffmanTree.h"using namespace std;//************************************************** ****HuffmanTree::HuffmanTree(){Node=NULL;}//************************************************** ****HuffmanTree::~HuffmanTree(){delete[]Node;}//******************************************************void HuffmanTree::CreateHuffmanTree(){char Choose;cout<<"您要从文献中读进哈妇曼树(按1),仍旧从键盘输进哈妇曼树(按2)?";cin>>Choose;if(Choose=='2') {//键盘输进修坐哈妇曼树CreateHuffmanTreeFromKeyboard();}//choose=='2'CreateHuffmanTreeFromFile();}}//************************************************** ****void HuffmanTree::CreateHuffmanTreeFromKeyboard(){int Num;cout<<"\n请输进源码字符集个数:";cin>>Num;if (Num<=1){cout<<"无法修坐少于2个叶子结面的哈妇曼树.\n\n"; return;}LeafNum=Num;Node=new HuffmanNode[2*Num-1];Info=new char[2*Num-1];for(int i=0;i<Num;i++) {//读进哈妇曼树的叶子结面疑息cout<<"请输进第"<<i+1<<"个字符值";getchar();Info[i]=getchar(); //源文的字符存进字符数组Info[]getchar();cout<<"请输进该字符的权值或者频度";cin>>Node[i].weight; //源文的字符权沉存进Node[].weight Node[i].parent=-1;Node[i].lchild=-1;Node[i].rchild=-1;}for(i=Num;i<2*Num-1;i++){//循环修坐哈妇曼树里里结面int pos1=-1,pos2=-1;int max1=32767,max2=32767;for(int j=0;j<i;j++)//正在根节面中选出权值最小的二个if(Node[j].parent==-1)//是可为根结面if(Node[j].weight<max1){max2=max1;max1=Node[j].weight;pos2=pos1;pos1=j;}elseif(Node[j].weight<max2){max2=Node[j].weight;pos2=j;}Node[pos1].parent=i;Node[pos2].parent=i;Node[i].lchild=pos1;Node[i].rchild=pos2;Node[i].parent=-1;Node[i].weight=Node[pos1].weight+Node[pos2].weight; } //forcout<<"哈妇曼树已乐成构制完毕.\n";char ch;cout<<"是可要替换本去的哈妇曼树文献(Y/N):";cin>>ch;if (ch!='y'&&ch!='Y') return;else{ofstream fop;fop.open("hfmTree.dat",ios::out|ios::binary|ios::trunc); //挨启文献if(fop.fail()){cout<<"\n哈妇曼树文献挨启波折,无法将哈妇曼树写进hfmTree.dat文献.\n";return;}fop.write((char*)&Num,sizeof(Num)); //先写进哈妇曼树的叶子结面个数for(i=0;i<Num;i++){ //再写进源笔墨符集的所有字符(保存正在Info[]中)fop.write((char*)&Info[i],sizeof(Info[i]));flush(cout);}for(i=0;i<2*Num-1;i++){ //末尾写进哈妇曼树的各个结面(保存正在Node[]中)fop.write((char*)&Node[i],sizeof(Node[i]));flush(cout);}fop.close(); //关关文献cout<<"\n哈妇曼树已乐成写进hfmTree.dat文献.\n";}}//************************************************** ****void HuffmanTree::CreateHuffmanTreeFromFile(){ifstream fip;fip.open("hfmTree.dat",ios::binary|ios::in);if(fip.fail()){cout<<"哈妇曼树文献hfmTree.dat挨启波折,无法修坐哈妇曼树.\n";return;}fip.read((char*)&LeafNum,sizeof(LeafNum));{cout<<"哈妇曼树文献中的数据有误,叶子结面个数少于2个,无法修坐哈妇曼树.\n";fip.close();return;}Info=new char[LeafNum];Node=new HuffmanNode[2*LeafNum-1];for(int i=0;i<LeafNum;i++)fip.read((char*)&Info[i],sizeof(Info[i]));for(i=0;i<2*LeafNum-1;i++)fip.read((char*)&Node[i],sizeof(Node[i]));fip.close();cout<<"哈妇曼树已乐成构制完毕.\n";}//************************************************** ****void HuffmanTree::Encoder(){if(Node==NULL)CreateHuffmanTreeFromFile();{cout<<"内存无哈妇曼树.支配撤消.\n\n";return;}}//ifchar *SourceText; //字符串数组,用于存搁源文char Choose;cout<<"您要从文献中读进源文(按1),仍旧从键盘输进源文(按2)?";cin>>Choose;if(Choose=='1'){ifstream fip1("ToBeTran.txt");if(fip1.fail()){cout<<"源文文献挨启波折!无法继承真止.\n";return;}char ch;int k=0;while(fip1.get(ch)) k++; //第一次读文献只统计文献中有几个字符,将字符数存进kfip1.close();SourceText=new char[k+1]; //申请存搁源文的字符数组空间ifstream fip2("ToBeTran.txt");//第二次读源文文献,把真质写进SourceText[]k=0;while(fip2.get(ch)) SourceText[k++]=ch;fip2.close();SourceText[k]='\0';cout<<"需编码的源文为:";cout<<SourceText<<endl;}else{ //从键盘输进源文string SourceBuff;cin.ignore();cout<<"请输进需要编码的源文(可输进任性少,按回车键中断):\n";getline(cin,SourceBuff,'\n');int k=0;while(SourceBuff[k]!='\0')k++;SourceText=new char[k+1];k=0;while(SourceBuff[k]!='\0'){SourceText[k]=SourceBuff[k];k++;}SourceText[k]='\0';cout<<"覆盖已有的编码本文献?(Y/N)"; char ch;cin>>ch;if(ch=='y'||ch=='Y'){ofstream fip2;fip2.open("ToBeTran.txt");if(!fip2){cerr<<"文献挨启波折!"<<endl;abort();}fip2<<SourceText<<endl;fip2.close();cout<<"需编码的源文已写进ToBeTran.txt中"<<endl;}}//启初编码ofstream fop("CodeFile.dat",ios::trunc); //挨启码文存搁文献char *code;code=new char[LeafNum]; //存搁一个源笔墨符的编码int k=0;while(SourceText[k]!='\0') //源文串中从第一个字符启初逐个编码{int star=0;char ch=SourceText[k];for(int i=0;i<LeafNum;i++)if(Info[i]==ch)//供出该笔墨天圆的单元编号break;int j=i;while(Node[j].parent!=-1){j=Node[j].parent;if(Info[Node[j].lchild]==Info[i]) code[star++]='0';else code[star++]='1';i=j;}code[star]='\0';for(i=0;i<star/2;i++){int j=code[i];code[i]=code[star-i-1];code[star-i-1]=j;}i=0; //将源文的目前字符的对于应编码写进码文文献while(code[i]!='\0'){fop<<code[i];i++;}k++; //源文串中的字符后移一个}fop.close();cout<<"已完毕编码,码文已写进文献CodeFile.dat中.\n\n"; }//************************************************** ****void HuffmanTree::Decoder(){if(Node==NULL){CreateHuffmanTreeFromFile();if (LeafNum<=1){cout<<"内存无哈妇曼树.支配撤消.\n\n"; return;}}//将码文从文献CodeFile.dat中读进 CodeStr[] ifstream fip1("CodeFile.dat");if(fip1.fail()){cout<<"不码文,无法译码.\n";return;}char* CodeStr;int k=0;char ch;while(fip1.get(ch)){k++;}fip1.close();CodeStr=new char[k+1];ifstream fip2("CodeFile.dat");k=0;while(fip2.get(ch)) CodeStr[k++]=ch;fip2.close();CodeStr[k]='\0';cout<<"经译码得到的源文为:";ofstream fop("TextFile.dat");int j=LeafNum*2-1-1; //j指背哈妇曼树的根int i=0; //码文从第一个标记启初,逆着哈妇曼树由根下止,按码文的目前标记决断下止到左孩子仍旧左孩子while(CodeStr[i]!='\0'){ //下止到哈妇曼树的叶子结面处,则译出叶子结面对于应的源笔墨符if(CodeStr[i]=='0') j=Node[j].lchild;else j=Node[j].rchild;if(Node[j].rchild==-1){cout<<Info[j];fop<<Info[j];j=LeafNum*2-1-1;}i++;}fop.close();cout<<"\n译码乐成且已存到文献TextFile.dat中.\n\n";}//************************************************** ****void HuffmanTree::PrintCodeFile(){char ch;int i=1;ifstream fip("CodeFile.dat");ofstream fop("CodePrin.dat");if(fip.fail()){cout<<"不码文文献,无法隐现码文文献真质.\n";return;}while(fip.get(ch)){cout<<ch;fop<<ch;if(i==50){cout<<endl;fop<<endl;i=0;}i++;}cout<<endl;fop<<endl;fip.close();fop.close();}//************************************************** ****void HuffmanTree::PrintHuffmanTree(){if(Node==NULL){CreateHuffmanTreeFromFile();if (LeafNum<=1){cout<<"内存无哈妇曼树.支配撤消.\n\n";return;}}ofstream fop("TreePrint.dat",ios_base::trunc);fop.close();PrintHuffmanTree_aoru(2*LeafNum-1-1,0);return;}//************************************************** ****void HuffmanTree::PrintHuffmanTree_aoru(int T,int layer){for(int i=0;i<layer;i++) cout<<"___";cout<<Node[T].weight<<endl;if(Node[T].lchild!=-1)PrintHuffmanTree_aoru(Node[T].lchild,++layer);if(Node[T].rchild!=-1)PrintHuffmanTree_aoru(Node[T].rchild,layer--);}#include<string.h>#include<stdlib.h>using namespace std;int main(){HuffmanTree huftree;char Choose;while(1){cout<<"\n\n**********************欢迎使用哈妇曼编码/译码系统***********************"<<endl;cout<<"您不妨举止以下支配:"<<endl;cout<<"1 修坐哈妇曼树 3 译码(码文已正在文献CodeFile中) 5 隐现哈妇曼树"<<endl;cout<<"2 编码(源文已正在文献ToBeTran中,或者键盘输进) 4 隐现码文 6 退出 "<<endl;cout<<"请采用一个支配:";cin>>Choose;switch(Choose){huftree.CreateHuffmanTree();break;case '2':huftree.Encoder();break;case '3':huftree.Decoder();break;case '4':huftree.PrintCodeFile();break;case '5':huftree.PrintHuffmanTree();break;case '6':cout<<"\n*************************感动使用本系统!***********************\n\n";system("pause");return 0;}//switch}//while【用户脚册】加进哈弗曼树系统,出现以下界里:1修坐弗曼树2、编码(源文中读进,键盘输进)3、译码4、隐现码文 5、隐现哈弗曼树 6、退出用户根据该提示,采用前里数字,便能加进各个功能函数,真止函数功能.【运止截止】截图一:截图二:截图三:截图四:【心得体验】本真验是收集相关资料,而后自己减少功能函数的代码真止的.果此,正在完毕已完毕的功能函数之前还必须要小心阅读所给出代码,完全瞅察各个部分之前的通联,搞领会已给出战已完毕的代码功能之后,才根据算法,安排出该功能的函数代码.正在完毕真验时,有收新颖码也有忽视的场合,如正在源文献读进的时间,多出了一个值,得要减少下表减那个代码去去掉.另有便是正在译码的时间,由于变量定义的殽杂,正在编译的时间通过,但是真止时却出现意料不到的截止,正在自己小心瞅察、思索之前也还出找堕落误之处.厥后通过请教教授,正在战教授计划查看之后才知讲了过得之天圆,末尾改正过得.真验乐成完毕.【参照文献】数据结构取算法(课本)C++谈话前提。
数据结构哈夫曼树编码及译码的实现实验报告
实验:哈夫曼树编码及译码的实现一.实验题目给定字符集的HUFFMANN编码与解码,这里的字符集及其字符频数自己定义,要求输出个字符集的哈夫曼编码及给定的字符串的哈夫曼码及译码结果。
二.实验原理首先规定构建哈夫曼树,然后进行哈夫曼树的编码,接着设计函数进行字符串的编码过程,最后进行哈夫曼编码的译码。
首先定义一个结构体,这个结构体定义时尽可能的大,用来存放左右的变量,再定义一个地址空间,用于存放数组,数组中每个元素为之前定义的结构体。
输入n个字符及其权值。
构建哈夫曼树:在上述存储结构上实现的哈夫曼算法可大致描述为:1.首先将地址空间初始化,将ht[0…n-1]中所有的结点里的指针都设置为空,并且将权值设置为0.2.输入:读入n个叶子的权值存于向量的前n个分量中。
它们是初始森林中n个孤立的根结点上的权值。
3.合并:对森林中的树共进行n-1次合并,所产生的新结点依次放入向量ht的第i个分量中。
每次合并分两步:①在当前森林ht[0…i-1]的所有结点中,选取权最小和次小的两个根结点[s1]和 [s2]作为合并对象,这里0≤s1,s2≤i-1。
②将根为ht[s1]和ht[s2]的两棵树作为左右子树合并为一棵新的树,新树的根是新结点ht[i]。
具体操作:将ht[s1]和ht[s2]的parent置为i,将ht[i]的lchild和rchild分别置为s1和s2 .新结点ht[i]的权值置为ht[s1]和ht[s2]的权值之和。
4.哈夫曼的编码:约定左子为0,右子为1,则可以从根结点到叶子结点的路径上的字符组成的字符串作为该叶子结点的编码。
当用户输入字母时。
就在已经找好编码的编码结构体中去查找该字母。
查到该字母就打印所存的哈夫曼编码。
接着就是完成用户输入0、1代码时把代码转成字母的功能。
这是从树的头结点向下查找,如果当前用户输入的0、1串中是0则就走向该结点的左子。
如果是1这就走向该结点的右结点,重复上面步骤。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
问题描述:利用哈夫曼编码进行通信可以大大提高信道利用率,缩短信息传输时间,降低传输成本。
但是,这要求在发送端通过一个编码系统对待传数据预先编码,在接收端将传来的数据进行译码(复原)。
对于双工通信(即可以双向传输信息的信道),每端都需要一个完整的编/译码系统,试设计一个哈夫曼编码系统。
基本要求:(1)从文件中读入字符集大小n,以及n个字符和n个权值。
(2)构建哈夫曼树,对每个字符生成哈夫曼编码。
(3)从文件中读入需编码的字符串,利用哈夫曼编码,对字符串进行编码,编码结果保存在文件。
一、需求分析:(1)、根据输入的字符和字符的权值建立哈夫曼树。
(2)、字符的数目和字符的权值由用户自己设定。
(3)、根据建立的哈夫曼树进行,编码和译码操作。
二、概要设计:1.哈夫曼树的定义typedef struct{char letter; //存储字符int weight; //存储字符的权值int parent; //父亲int lchild; //左孩子int rchild; //右孩子}HTNode,*HuffmanTree;2.算定义的存储结构//本结构存储哈夫曼树、编码等,便于后面的操作进行typedef struct{HuffmanTree HT;//动态分配数组存储哈夫曼编码表HuffmanCode HC;//记录输入字符的长度,编码和译码用到int len;char *c;//存储输入的字符}Huf;3.一些操作函数void setHuffmanTree(HuffmanTree &HT,char *str,int *w,int n)建立哈夫曼树,str是存储输入字符的数组,w 是存储字符权值的数组,n为输入字符的数目Huf setHuffmanCode(HuffmanTree &HT,HuffmanCode &HC,int n,char*s)为哈夫曼树编码,HT是已经建立的哈夫曼树,HC用于存储编码,民为字符的数目,s是存储字符的数组Huf Initialization()初始化函数void Encoding(Huf huf)编码函数void Decoding(Huf huf)译码函数void Print()打印代码文件的函数void Treeprinting(Huf huf)打印哈夫曼树的函数4.主函数void main(){根据不同的选择,执行特定的函数,完成操作}三、详细设计核心程序为哈夫曼树的构建,实现该功能时,通过不断调用selecte(在已有的结点中选择双亲结点值为0,且权值最小的两个结点)函数查找构造哈夫曼树中的各个子树的结点,直到所有这种结点全部用完,即一颗哈夫曼树即构造完成。
1、建立哈夫曼树及求哈夫曼编码//初始化操作,接受输入,调用函数setHuffmanTree,//setHuffmanCode创建树并编码Huf Initialization(){HuffmanTree HT;HuffmanCode HC;char c[100];//存放输入的字符int w[100];//存放字符的权值int n;cout<<"请输入字符的个数:"<<endl;cin>>n;cout<<"请输入所有字符:"<<endl;gets(c);for(int i=1;i<=n;i++){cout<<"请输入第"<<i<<"个字符的权值:"<<endl;cin>>w[i];}//将数组c中的元素向右移动一位for(int j=n-1;j>=0;j--){c[j+1]=c[j];}// 调用setHuffmanTree函数setHuffmanTree(HT,c,w,n);//调用setHuffmanCode函数Huf huf=setHuffmanCode(HT,HC,n,c);return huf;}//选择权值最小的两个结点void Select(HuffmanTree &HT,int s,int &s1,int &s2){int j, k, i;j=k=10000;s1=s2=0;for(i=1;i<=s;i++){if(HT[i].parent==0){if(HT[i].weight<j){k=j;s2=s1;j=HT[i].weight;s1=i;}else if(HT[i].weight<k){k=HT[i].weight;s2=i;}}}}//创建哈夫曼树函数的具体实现void setHuffmanTree(HuffmanTree &HT,char *str,int *w,int n){HuffmanTree p;int m,i,s1,s2; //s1,s2是权值最小的两个结点的序号m = 2*n-1; //一棵有N个叶子节点的哈夫曼树共有2*N-1个结点//动态定义长度,0号单元未使用HT=(HuffmanTree)malloc((m+1)*sizeof(HTNode));//初始化for(p=HT+1,i=1;i<=n;++i,++p){p->letter = str[i]; p->weight = w[i];(*p).parent = 0; p->lchild = 0; p->rchild = 0;}for(;i<=m;++i,++p){p->weight=0; p->parent=0; p->lchild=0; p->rchild=0;}//建立哈夫曼树for(i=n+1;i<=m;++i){Select(HT,i-1,s1,s2); //此函数为自己定义用于选择出s1,s2HT[s1].parent=i; HT[s2].parent=i;HT[i].lchild=s1; HT[i].rchild=s2;HT[i].weight=HT[s1].weight+HT[s2].weight;}// 将哈夫曼树写入到文件hufTree.dat中FILE *huftree;huftree=fopen("hufTree.dat","rt");if(huftree==NULL){ huftree=fopen("hufTree.dat","wt");for(i=1;i<=m;i++)fprintf(huftree,"%d %d %d %d\n",HT[i].weight,HT[i].parent,HT[i].lchild,HT[i].rchild);//向文件中写入rewind(huftree);}}//从叶子到根结点逆向求每个字符的赫夫曼编码Huf setHuffmanCode(HuffmanTree &HT,HuffmanCode &HC,int n,char *s){ Huf huf;// 分配n个字符编码的头指针向量huf.c=(char *)malloc((n+1)*sizeof(char));//将以输入的字符存储在huf的c中for(int j=1;j<=n;j++){huf.c[j]=s[j];}int start = 1; char *cd; int f,c,i;//分配n个字符编码的头指针向量HC=(HuffmanCode)malloc((n+1)*sizeof(char*));//临时的编码存储,作用是分配求编码的工作空间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';else cd[--start] = '1';//为第i个字符编码分配空间HC[i] = (char *)malloc((n - start) * sizeof(char));//从cd复制编码(串)到HCstrcpy(HC[i], &cd[start]);}//将HC,HT,n分别存储到结构体Huf中huf.HC=HC;huf.HT=HT;huf.len=n;free(cd); //释放工作空间return huf;//返回值,供后面的操作使用}2、编码//利用已建好的哈夫曼树对文件中的正文进行编码,然后将结果存入文//件codefile.dat中,如果正文中没有要编码的字符,则键盘读入void Encoding(Huf huf){int i=0,j=0,n;char ch[10000];//code为指向文件CodeFile.dat的指针,tbt为指向文件//ToBeTran的指针FILE *code,*tbt;n=huf.len;tbt=fopen("ToBeTran.dat","rt");//如果ToBeTran中没有要编码的字符,则键盘读入//如果ToBeTran中有要编码的字符,则从文件读取if(tbt==NULL){printf("不存在文件ToBeTran.dat");printf("\n请输入要进行编码的报文: ");gets(ch);printf("\n");code=fopen("CodeFile.dat","wt+");}else{fscanf(tbt,"%s",&ch);fclose(tbt);code=fopen("CodeFile.dat","wt+");}// 将ch中的元素与哈夫曼树中的进行匹配,为字符串编码while(ch[j]){for(i=1;i<=n;i++)if(ch[j]==huf.HT[i].letter){ //将编码写入到文件中fprintf(code,"%s",huf.HC[i]);break;}j++;}rewind(code);fclose(code);printf("已进行编码,结果保存到文件CodeFile.dat中");}3、译码//利用已建好的哈夫曼树将文件对CodeFile.dat中的代码进行译码,//结果存入文件TextFile.dat 中void Decoding(Huf huf){HuffmanTree p;int i,n,j=0;char d[10000];FILE *code;//指向CodeFile.dat的指针n=huf.len;code=fopen("CodeFile.dat","rt");if(code==NULL){printf("没有找到CodeFile.dat文件,先编码\n");printf("输入哈夫曼码进行译码:");scanf("%s",&d);}else{fscanf(code,"%s",d);fclose(code);}code=fopen("TextFile.dat","wt+");while(d[j]){p=&huf.HT[2*n-1];//从根开始找叶子节点进行译码//简而言之就是遇到0向左,遇到一向右,直到找到叶子while(p->lchild||p->rchild){if(d[j]=='0'){i=p->lchild;p=&huf.HT[i];}else{ i=p->rchild;p=&huf.HT[i]; }j++;}printf("%c",huf.c[i]);//将找到叶子节点的字符写入TextFile.datfprintf(code,"%c",huf.c[i]); }fclose(code);printf("译码成功,结果保存到文件TextFile.dat中");}4、打印代码文件//将文件CodeFile每行50个代码显示到终端//将此字符形式的编码写入CodePrin中void Print(){char ch;//code是指向CodeFile的指针,codeprin是指向//CodePrin的指针FILE *code,*codeprin;code=fopen("CodeFile.dat","r");codeprin=fopen("CodePrin.dat","w");//每行输出50个字符,将编码写进文件CodePrin中for(int i=1;(ch=fgetc(code))!=EOF;i++){if(i>=50){printf("\n");fputc('\n',codeprin);i=1;}putchar(ch);fputc(ch,codeprin);}fclose(codeprin);fclose(code);printf("\n已经写入到文件CodePrin.dat中\n");}5、打印哈夫曼树//输出哈夫曼树节点,权值,双亲,左孩子,右孩子//前n个结点打出对应的字符void Treeprinting(Huf huf){int j,n;FILE *tree;tree=fopen("TreePrint.dat","w");n=huf.len;for (j=1; j<=n; j++){printf("\n%4d(%c)%5d%8d%8d%8d",j,huf.c[j],huf.HT[j].weight,h uf.HT[j].parent,huf.HT[j].lchild, huf.HT[j].rchild);fprintf(tree,"\n%4d(%c)%5d%8d%8d%8d",j,huf.c[j],huf.HT[j].we ight,huf.HT[j].parent,huf.HT[j].lchild, huf.HT[j].rchild);}for (int h=n+1; h<=2*n-1; h++){printf("\n%4d%8d%8d%8d%8d",h,huf.HT[h].weight,huf.HT[h].pare nt,huf.HT[h].lchild, huf.HT[h].rchild);fprintf(tree,"\n%4d%8d%8d%8d%8d",h,huf.HT[h].weight,huf.HT[h ].parent,huf.HT[h].lchild, huf.HT[h].rchild);}fclose(tree);}6、主函数//通过不接收不同的输入,调用相应的函数void main(){Huf huf;int num;char input;while(1){cout<<"I:初始化"<<endl;cout<<"E:编码"<<endl;cout<<"D:译码"<<endl;cout<<"P:印代码文件"<<endl;cout<<"T:打印哈夫曼树"<<endl;cout<<"Q:退出"<<endl<<endl;cout<<"请输入你的选择:";cin>>input;if(input=='I'||input=='i'){num=1;}else if(input=='E'||input=='e'){num=2;}else if(input=='D'||input=='d'){num=3;}else if(input=='P'||input=='p'){num=4;}else if(input=='T'||input=='t'){num=5;}else if(input=='Q'||'q'){num=6;}else{num=7;}switch(num){case 1:huf=Initialization();getch(); break;case 2:Encoding(huf);getch(); break;case 3:Decoding(huf);getch(); break;case 4:Print();getch(); break;case 5:Treeprinting(huf);getch(); break;case 6:return;default:printf("选择有错,请重新选择\n");getch(); break;}}}四、调试分析1.开始时并未设计Huf这个结构体,但后来发现进行操作的时候很费力,在编写的过程中,就将后面要用到东西都放到这个结构体中了。