哈夫曼树实验报告
- 格式:doc
- 大小:92.00 KB
- 文档页数:9
数据结构哈夫曼树实验报告一、实验目的本次实验的主要目的是深入理解和掌握哈夫曼树的数据结构及其相关算法,通过实际编程实现哈夫曼编码和解码的过程,提高对数据结构的应用能力和编程技能。
二、实验环境本次实验使用的编程语言为 Python,开发工具为 PyCharm。
操作系统为 Windows 10。
三、实验原理哈夫曼树(Huffman Tree),又称最优二叉树,是一种带权路径长度最短的二叉树。
其基本思想是通过构建一棵二叉树,使得权值较大的节点离根节点较近,权值较小的节点离根节点较远,从而实现带权路径长度的最小化。
哈夫曼编码是一种基于哈夫曼树的变长编码方式。
对于给定的字符集及其出现的频率,通过构建哈夫曼树,可以为每个字符生成唯一的编码,使得编码后的字符串总长度最短。
在构建哈夫曼树的过程中,首先将每个字符及其出现的频率作为一个独立的节点,然后按照频率从小到大的顺序进行合并,每次合并两个频率最小的节点,生成一个新的节点,其频率为两个子节点频率之和。
重复这个过程,直到所有节点合并为一个根节点,最终得到的二叉树即为哈夫曼树。
四、实验步骤1、定义节点类```pythonclass Node:def __init__(self, char, freq, left=None, right=None):selfchar = charselffreq = freqselfleft = leftselfright = rightdef __lt__(self, other):return selffreq < otherfreq```这个节点类包含了字符、频率以及左右子节点的信息,并实现了小于比较方法,以便在构建哈夫曼树时进行节点的排序。
2、构建哈夫曼树```pythondef build_huffman_tree(freq_dict):nodes = Node(char, freq) for char, freq in freq_dictitems()while len(nodes) > 1:nodessort()left = nodespop(0)right = nodespop(0)merged_freq = leftfreq + rightfreqnew_node = Node(None, merged_freq, left, right)nodesappend(new_node)return nodes0```该函数根据字符频率字典创建节点列表,然后不断合并频率最小的两个节点,直到只剩下一个节点,即哈夫曼树的根节点。
数据结构实验报告实验名称:实验三哈夫曼树学生姓名:班级:班内序号:学号:日期:程序分析:2.1 存储结构:二叉树2.2 程序流程:template <class T>class BiTree{public:BiTree(); //构造函数,其前序序列由键盘输入 ~BiTree(void); //析构函数BiNode<T>* Getroot(); //获得指向根结点的指针protected:BiNode<T> *root; //指向根结点的头指针};//声明类BiTree及定义结构BiNodeData:二叉树是由一个根结点和两棵互不相交的左右子树构成二叉树中的结点具有相同数据类型及层次关系哈夫曼树类的数据域,继承节点类型为int的二叉树class HuffmanTree:public BiTree<int>data:HCode* HCodeTable;//编码表int tSize; //编码表中的总字符数二叉树的节点结构template <class T>struct BiNode //二叉树的结点结构{T data; //记录数据T lchild; //左孩子T rchild; //右孩子T parent; //双亲};编码表的节点结构struct HCode{char data; //编码表中的字符char code[100]; //该字符对应的编码};待编码字符串由键盘输入,输入时用链表存储,链表节点为struct Node{char character; //输入的字符unsigned int count;//该字符的权值bool used; //建立树的时候该字符是否使用过Node* next; //保存下一个节点的地址};示意图:2.3 关键算法分析:1.初始化函数(void HuffmanTree::Init(string Input))算法伪代码:1.初始化链表的头结点2.获得输入字符串的第一个字符,并将其插入到链表尾部,n=1(n记录的是链表中字符的个数)3.从字符串第2个字符开始,逐个取出字符串中的字符3.1 将当前取出的字符与链表中已经存在的字符逐个比较,如果当前取出的字符与链表中已经存在的某个字符相同,则链表中该字符的权值加1。
一、实验目的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. 实验结果分析通过实验,验证了哈夫曼树和哈夫曼编码的正确性。
实验报告1、实验目的:(1)理解哈夫曼树的含义和性质。
(2)掌握哈夫曼树的存储结构以及描述方法。
(3)掌握哈夫曼树的生成方法。
(4)掌握哈夫曼编码的一般方法,并理解其在数据通讯中的应用.2、实验内容:哈夫曼树与哈弗曼编码、译码a。
问题描述:哈夫曼问题的提出可以参考教材P。
145。
利用哈弗曼编码进行通信可以大大提高通信利用率,缩短信息传输时间,降低传输成本。
但是,这要求在发送端通过一个编码系统对待传数据预先编码,在接收端将传来的数据进行译码.b。
算法提示:参见教材P.147—148算法6.12、6。
13的描述.3、实验要求:建立哈夫曼树,实现编码,译码。
错误!.初始化(Initialization)。
从终端读入字符集大小n,以及n个字符和n个权值,建立哈夫曼树,并将它存于文件hfmTree中。
○2。
编码(Encoding).利用已建好的哈夫曼树(如不在内存,则从文件hfmTree中读入),对文件ToBeTran 中的正文进行编码,然后将结果存入文件CodeFile中。
○3.译码(Decoding ).利用已建好的哈夫曼树将文件CodeFile中的代码进行译码,结果存入文件T extFile 中。
错误!.输出代码文件(Print).将文件CodeFile以紧凑格式显示在终端上,每行50个代码。
同时将此字符形式的编码文件写入文件CodePrint中。
错误!。
输出哈夫曼树(TreePrinting).将已在内存中的哈夫曼树以直观的方式(树或凹入表形式)显示在终端上,同时将此字符形式的哈夫曼树写入文件TreePrint中。
测试数据:设权值c= (a,b, c, d , e, f,g,h)w=(5,29,7,8,14,23,3,11),n=8。
按照字符‘0’或‘1’确定找左孩子或右孩子,则权值对应的编码为:5:0001,29:11,7:1110,8:111114:110,23:01,3:0000,11:001。
哈夫曼树编码实验报告哈夫曼树编码实验报告引言:哈夫曼树编码是一种常用的数据压缩算法,通过对数据进行编码和解码,可以有效地减小数据的存储空间。
本次实验旨在探究哈夫曼树编码的原理和应用,并通过实际案例验证其有效性。
一、哈夫曼树编码原理哈夫曼树编码是一种变长编码方式,根据字符出现的频率来确定不同字符的编码长度。
频率较高的字符编码较短,频率较低的字符编码较长,以达到最佳的数据压缩效果。
1.1 字符频率统计首先,需要对待编码的数据进行字符频率统计。
通过扫描数据,记录每个字符出现的次数,得到字符频率。
1.2 构建哈夫曼树根据字符频率构建哈夫曼树,频率较低的字符作为叶子节点,频率较高的字符作为父节点。
构建哈夫曼树的过程中,需要使用最小堆来维护节点的顺序。
1.3 生成编码表通过遍历哈夫曼树,从根节点到每个叶子节点的路径上的左右分支分别赋予0和1,生成对应的编码表。
1.4 数据编码根据生成的编码表,将待编码的数据进行替换,将每个字符替换为对应的编码。
编码后的数据长度通常会减小,实现了数据的压缩。
1.5 数据解码利用生成的编码表,将编码后的数据进行解码,恢复原始数据。
二、实验过程与结果为了验证哈夫曼树编码的有效性,我们选择了一段文本作为实验数据,并进行了以下步骤:2.1 字符频率统计通过扫描文本,统计每个字符出现的频率。
我们得到了一个字符频率表,其中包含了文本中出现的字符及其对应的频率。
2.2 构建哈夫曼树根据字符频率表,我们使用最小堆构建了哈夫曼树。
频率较低的字符作为叶子节点,频率较高的字符作为父节点。
最终得到了一棵哈夫曼树。
2.3 生成编码表通过遍历哈夫曼树,我们生成了对应的编码表。
编码表中包含了每个字符的编码,用0和1表示。
2.4 数据编码将待编码的文本数据进行替换,将每个字符替换为对应的编码。
编码后的数据长度明显减小,实现了数据的压缩。
2.5 数据解码利用生成的编码表,将编码后的数据进行解码,恢复原始文本数据。
哈夫曼树实验报告一、问题描述利用哈夫曼编码进行通信可以大大提高信道利用率,缩短信息传输时间,降低传输成本。
但是,这要求在发送端通过一个编码系统对待传数据预先编码,在接收端将穿来的数据进行译码,此试验即设计这样的一个简单的编/译码系统。
系统应该具有如下的几个功能。
1. 接受原始数据从终端任意读入字母,求出其各自的权重值,建立哈夫曼树,并将它存于hfmtree.dat文件中。
2. 编码利用已建好的哈夫曼树,对文件中的正文进行编码,然后将结果存入codefile.dat中。
3. 译码利用已建好的哈夫曼树将文件codefile.dat中的代码进行译码,结果存入文件textfile.dat中。
4. 打印编码规则即字符与编码的一一对应关系。
5. 打印哈夫曼树将已存在内存中的哈夫曼树以直观的方式显示在终端上。
二、数据结构设计1. 构造哈夫曼树时使用静态量表作为哈夫曼树的存储。
在构造哈夫曼树时,设计一个结构体数组HuffNode保存哈夫曼树中各节点的信息,根据二叉树的性质可知,具有n个叶子节点的哈夫曼树共有2n-1个结点,所以数组HuffNode的大小设置为2n-1,描述节点的数据类型为:typedef struct{int weight; //结点权值int parent;int lchild;int rchild;}HNodeType;2. 求哈夫曼编码时使用一位结构数组HuffCode作为哈腹满编码信息的存储。
求哈夫曼编码,实质上就是在以建立的哈夫曼树中,从叶子结点开始,沿结点的双亲链域退到根结点,每退回一步,就走过了哈夫满树的一个分支,从而得到一位哈夫曼码值,由于一个字符的哈夫曼编码是从根结点到相应叶子结点所经过的路径上各分支所组成的0、1序列,因此先得到的分支代码为所求编码的低位码,后得到的分支代码为所求编码的高位码,所以设计如下数据类型:typedef struct{int bit[26];int start;}HCodeType;3. 文件hfmtree.dat、codefile.dat、和textfile.dat。
一、实训目的本次实训旨在通过实际操作,让学生掌握哈夫曼树的基本概念、构建方法以及编码解码过程,加深对数据结构中树型结构在实际应用中的理解。
通过本次实训,学生能够:1. 理解哈夫曼树的基本概念和构建原理;2. 掌握哈夫曼树的编码和解码方法;3. 熟悉Java编程语言在哈夫曼树编码中的应用;4. 提高数据压缩和传输效率的认识。
二、实训内容1. 哈夫曼树的构建(1)创建叶子节点:根据给定的字符及其权值,创建叶子节点,并设置节点信息。
(2)构建哈夫曼树:通过合并权值最小的两个节点,不断构建新的节点,直到所有节点合并为一棵树。
2. 哈夫曼编码(1)遍历哈夫曼树:从根节点开始,按照左子树为0、右子树为1的规则,记录每个叶子节点的路径。
(2)生成编码:将遍历过程中记录的路径转换为二进制编码,即为哈夫曼编码。
3. 哈夫曼解码(1)读取编码:将编码字符串按照二进制位读取。
(2)遍历哈夫曼树:从根节点开始,根据读取的二进制位,在哈夫曼树中寻找对应的节点。
(3)输出解码结果:当找到叶子节点时,输出对应的字符,并继续读取编码字符串。
三、实训过程1. 准备工作(1)创建一个Java项目,命名为“HuffmanCoding”。
(2)在项目中创建以下三个类:- HuffmanNode:用于存储哈夫曼树的节点信息;- HuffmanTree:用于构建哈夫曼树、生成编码和解码;- Main:用于实现主函数,接收用户输入并调用HuffmanTree类进行编码和解码。
2. 编写代码(1)HuffmanNode类:```javapublic class HuffmanNode {private char data;private int weight;private HuffmanNode left;private HuffmanNode right;public HuffmanNode(char data, int weight) {this.data = data;this.weight = weight;}}```(2)HuffmanTree类:```javaimport java.util.PriorityQueue;public class HuffmanTree {private HuffmanNode root;public HuffmanNode buildHuffmanTree(char[] data, int[] weight) {// 创建优先队列,用于存储叶子节点PriorityQueue<HuffmanNode> queue = new PriorityQueue<>();for (int i = 0; i < data.length; i++) {HuffmanNode node = new HuffmanNode(data[i], weight[i]);queue.offer(node);}// 构建哈夫曼树while (queue.size() > 1) {HuffmanNode left = queue.poll();HuffmanNode right = queue.poll();HuffmanNode parent = new HuffmanNode('\0', left.weight + right.weight);parent.left = left;parent.right = right;queue.offer(parent);}root = queue.poll();return root;}public String generateCode(HuffmanNode node, String code) {if (node == null) {return "";}if (node.left == null && node.right == null) {return code;}generateCode(node.left, code + "0");generateCode(node.right, code + "1");return code;}public String decode(String code) {StringBuilder result = new StringBuilder();HuffmanNode node = root;for (int i = 0; i < code.length(); i++) {if (code.charAt(i) == '0') {node = node.left;} else {node = node.right;}if (node.left == null && node.right == null) { result.append(node.data);node = root;}}return result.toString();}}```(3)Main类:```javaimport java.util.Scanner;public class Main {public static void main(String[] args) {Scanner scanner = new Scanner(System.in);System.out.println("请输入字符串:");String input = scanner.nextLine();System.out.println("请输入字符及其权值(例如:a 2 b 3 c 5):"); String[] dataWeight = scanner.nextLine().split(" ");char[] data = new char[dataWeight.length / 2];int[] weight = new int[dataWeight.length / 2];for (int i = 0; i < dataWeight.length; i += 2) {data[i / 2] = dataWeight[i].charAt(0);weight[i / 2] = Integer.parseInt(dataWeight[i + 1]);}HuffmanTree huffmanTree = new HuffmanTree();HuffmanNode root = huffmanTree.buildHuffmanTree(data, weight); String code = huffmanTree.generateCode(root, "");System.out.println("编码结果:" + code);String decoded = huffmanTree.decode(code);System.out.println("解码结果:" + decoded);scanner.close();}}```3. 运行程序(1)编译并运行Main类,输入字符串和字符及其权值。
哈夫曼树实验报告哈夫曼树实验报告引言:哈夫曼树是一种经典的数据结构,广泛应用于数据压缩、编码和解码等领域。
本次实验旨在通过构建哈夫曼树,探索其原理和应用。
一、哈夫曼树的定义和构建方法哈夫曼树是一种特殊的二叉树,其叶子节点对应于待编码的字符,而非叶子节点则是字符的编码。
构建哈夫曼树的方法是通过贪心算法,即每次选择权值最小的两个节点合并,直到构建出完整的哈夫曼树。
二、哈夫曼编码的原理和实现哈夫曼编码是一种可变长度编码,即不同字符的编码长度不同。
其原理是通过构建哈夫曼树来确定字符的编码,使得频率较高的字符编码较短,频率较低的字符编码较长。
这样可以有效地减少编码的长度,从而实现数据的压缩。
三、实验过程和结果在本次实验中,我们选择了一段文本作为输入数据,通过统计每个字符的频率,构建了对应的哈夫曼树。
然后,根据哈夫曼树生成了字符的编码表,并将原始数据进行了编码。
最后,我们通过对编码后的数据进行解码,验证了哈夫曼编码的正确性。
实验结果显示,通过哈夫曼编码后,原始数据的长度明显减少,达到了较好的压缩效果。
同时,解码后的数据与原始数据完全一致,证明了哈夫曼编码的可靠性和正确性。
四、哈夫曼树的应用哈夫曼树在实际应用中有着广泛的用途。
其中,最典型的应用之一是数据压缩。
通过使用哈夫曼编码,可以将大量的数据压缩为较小的存储空间,从而节省了存储资源。
此外,哈夫曼树还被广泛应用于网络传输、图像处理等领域,提高了数据传输的效率和图像的质量。
五、对哈夫曼树的思考哈夫曼树作为一种经典的数据结构,其优势在于有效地减少了数据的冗余和存储空间的占用。
然而,随着技术的不断发展,现代的数据压缩算法已经不再局限于哈夫曼编码,而是采用了更为复杂和高效的算法。
因此,我们需要在实际应用中综合考虑各种因素,选择合适的压缩算法。
六、总结通过本次实验,我们深入了解了哈夫曼树的原理和应用。
哈夫曼编码作为一种重要的数据压缩算法,具有广泛的应用前景。
在实际应用中,我们需要根据具体情况选择合适的压缩算法,以达到最佳的压缩效果和性能。
哈夫曼树实验报告一、需求分析(1)输入输出形式输入数组的组数n: 整形变量组数(回车)请依次输入n组权值与字符, 中间用空格隔开。
如“2 a”:按右提示格式输入(回车)请输入待编译文本: 随机输入字符(回车)输出: 编译出的代码请输入待编译代码: 随机输入一串代码(回车)(2)输出: 编译出的代码(3)程序功能1. 用C语言实现二叉树的说明2. 输入n个权值, 并生成n个二叉树3. 对n个二叉树逐步生成Huffman树4. 对Huffman树的每个叶子结点生成编码5.用哈夫曼树编码。
6.解码哈夫曼编码。
(4)测试用例设计Example1: 输入325 a15 b60 cabbacc010*******输出010*******abbaccExample2: 输入510 a20 b30 c20 d10 eababcde10000100001101101输出10000100001101101ababcde二、概要设计1.根据给定的n个权值(w1, w2, …, wn)构成n棵二叉树的集合F={T1, T2, …, Tn}, 其中每棵二叉树Ti中只有一个带树为Ti的根结点在F中选取两棵根结点的权值最小的树作为左右子树构造一棵新的二叉树, 且置其根结点的权值为其左右子树权值之和3.在F中删除这两棵树, 同时将新得到的二叉树加入F中4.重复2, 3, 直到F只含一棵树为止三、 5.将给定的字符串通过程序编码成哈夫曼编码, 并打印结果在屏幕上。
四、 6.翻译给定的哈夫曼编码变成可读字符串, 并将结果打印在屏幕上。
五、详细设计四、调试分析(1)编译代码、运行代码所遇到的问题及其解决办法问题1: 编译代码过程中有遇到循环体的循环次数不对, 导致二叉树生成得不对解决办法:通过小数字的演算, 检验循环, 再进行更改(2)算法的时空分析(3)心得体会五、用户使用说明如上图所示, 依次输入组数、权值及全值所对应字符。
再根据用户自身需求输入需编译的文本及代码。
实验报告1、实验目的:(1)理解哈夫曼树的含义和性质。
(2)掌握哈夫曼树的存储结构以及描述方法。
(3)掌握哈夫曼树的生成方法。
(4)掌握哈夫曼编码的一般方法,并理解其在数据通讯中的应用。
2、实验内容:哈夫曼树与哈弗曼编码、译码a.问题描述:哈夫曼问题的提出可以参考教材P.145.利用哈弗曼编码进行通信可以大大提高通信利用率,缩短信息传输时间,降低传输成本。
但是,这要求在发送端通过一个编码系统对待传数据预先编码,在接收端将传来的数据进行译码。
b.算法提示:参见教材P.147-148算法6.12、6.13的描述。
3、实验要求:建立哈夫曼树,实现编码,译码。
○1.初始化(Initialization)。
从终端读入字符集大小n,以及n个字符和n个权值,建立哈夫曼树,并将它存于文件hfmTree中。
○2.编码(Encoding)。
利用已建好的哈夫曼树(如不在内存,则从文件hfmTree中读入),对文件ToBeTran中的正文进行编码,然后将结果存入文件CodeFile中。
○3.译码(Decoding )。
利用已建好的哈夫曼树将文件CodeFile中的代码进行译码,结果存入文件TextFile中。
○4.输出代码文件(Print)。
将文件CodeFile以紧凑格式显示在终端上,每行50个代码。
同时将此字符形式的编码文件写入文件CodePrint中。
○5.输出哈夫曼树(TreePrinting)。
将已在内存中的哈夫曼树以直观的方式(树或凹入表形式)显示在终端上,同时将此字符形式的哈夫曼树写入文件TreePrint中。
测试数据:设权值 c= (a, b, c, d , e, f, g, h)w=(5,29,7,8,14,23,3,11),n=8。
按照字符‘0’或‘1’确定找左孩子或右孩子,则权值对应的编码为:5:0001,29:11,7:1110,8:111114:110,23:01,3:0000,11:001。
四实验代码#include <iostream.h> #include <iomanip.h> #include <string.h> #include <malloc.h> #include <stdio.h> typedef struct {int weight,K;int parent,lchild,rchild;}HTNode,* HuffmanTree;typedef char **HuffmanCode;char str[50];int wa[50];HuffmanTree HT;HuffmanCode HC;int w[50],i,j,n=8;char z[50];int flag=0;int numb=0;// -----------------求哈夫曼编码-----------------------struct cou {char data;int count;}cou[50];void select(HuffmanTree HT,int j,int *s1,int *s2){int i;//找weight最小的结点for (i=1;i<=j;i++)if (HT[i].parent==0){*s1=i;break;}for (;i<=j;i++)if((HT[i].parent==0)&&(HT[i].weight<HT[*s1].w eight))*s1=i;HT[*s1].parent=1;//找weight次小的结点for (i=1;i<=j;i++)if (HT[i].parent==0){*s2=i;break;} for (;i<=j;i++)if((HT[i].parent==0)&&(i!=*s1)&&(HT[i].weight <HT[*s2].weight))*s2=i;}// --------------算法6.12--------------------------void HuffmanCoding(HuffmanTree &HT,HuffmanCode &HC,int *w,int n){int m,i,s1,s2,start;int c,f;HuffmanTree p;char *cd;if(n<=1)return;//检测结点数是否可以构成树m=2*n-1;HT=(HuffmanTree)malloc((m+1)*sizeof(HTNode) );for(p=HT+1,i=1;i<=n;i++,p++){p->weight=wa[i-1];p->parent=0;p->lchild=0;p->rchild=0;}for(;i<=m;++i,++p)p->parent=0;for(i=n+1;i<=m;++i) // 建哈夫曼树{select(HT,i-1,&s1,&s2);HT[s1].parent=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*)) ;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].par ent)if(HT[f].lchild==c) cd[--start]='0'; elsecd[--start]='1';HC[i]=(char*)malloc((n-start)*sizeof(char)) ;strcpy(HC[i],&cd[start]);}free(cd);}//---------------------获取报文并写入文件---------------------------------int InputCode() {FILE *tobetran;int i=0;if((tobetran=fopen("tobetran.txt","w"))==NULL){printf("不能打开文件\n");return 0;}printf("请输入你想要编码的字符\n");scanf("%s",&str);fputs(str,tobetran);printf("请输入你相应编码的权值\n");for(i=0;i<strlen(str);i++)scanf("%d",&wa[i]);while(wa[i]!='\0'){ fprintf(tobetran,"%d",wa[i++]);}printf("获取报文成功\n");fclose(tobetran);return strlen(str);}//--------------初始化哈夫曼链表---------------------------------void Initialization(){ int a,k,flag,len;a=0;len=InputCode();for(i=0;i<len;i++){k=0;flag=1;cou[i-a].data=str[i];cou[i-a].count=wa[i];while(i>k){if(str[i]==str[k]){a++;flag=0;}k++;if(flag==0)break;}if(flag){for(j=i+1;j<len;j++){if(str[i]==str[j])++cou[i-a].count;}}}n=len-a;for(i=0;i<n;i++){ printf("%c",cou[i].data);printf(" ");printf("%d\n",cou[i].count);}for(i=0;i<=n;i++){ *(z+i)=cou[i].data;*(w+i)=cou[i].count;}HuffmanCoding(HT,HC,w,8);//------------------------打印编码------------------------------------------- printf("字符对应的编码为\n:");for(i=1;i<=n;i++) {puts(HC[i]);}//-------------------------将哈夫曼编码写入文件------------------------printf("下面将哈夫曼编码写入文件\n");FILE *htmTree;char r[]={' ','\0'};if((htmTree=fopen("htmTree.txt","w"))==NULL ){printf("can not open file\n");return;}fputs(z,htmTree);for(i=0;i<n+1;i++){fprintf(htmTree,"%6d",*(w+i));fputs(r,htmTree);}for(i=1;i<=n;i++){fputs(HC[i],htmTree);fputs(r,htmTree);}fclose(htmTree);printf("已将字符与对应编码写入根目录下文件htmTree.txt中\n");}//---------------------编码函数---------------------------------void Encoding(){printf("下面对目录下文件tobetran.txt中的字符进行编码\n");FILE *tobetran,*codefile;if((tobetran=fopen("tobetran.txt","rb"))==N ULL){printf("不能打开文件\n"); }if((codefile=fopen("codefile.txt","wb"))==N ULL){printf("不能打开文件\n"); }char *tran;i=99;tran=(char*)malloc(100*sizeof(char));while(i==99){if(fgets(tran,100,tobetran)==NULL){printf("不能打开文件\n");break;}for(i=0;*(tran+i)!='\0';i++){for(j=0;j<=n;j++) {if(*(z+j-1)==*(tran+i)){ fputs(HC[j],codefile);if(j>n){printf("字符错误,无法编码!\n");break;}}}}}printf("编码工作完成,编码写入目录下的codefile.txt中\n");fclose(tobetran);fclose(codefile);free(tran);}//-----------------译码函数---------------------------------void Decoding(){ printf("下面对根目录下文件codefile.txt中的字符进行译码\n");FILE *codef,*txtfile;if((txtfile=fopen("txtfile.txt","w"))==NULL){printf("不能打开文件\n");}if((codef=fopen("codefile.txt","r"))==NULL){printf("不能打开文件\n");}char *work,*work2,i2;int i4=0,i,i3;unsigned long length=10000;work=(char*)malloc(length*sizeof(char)); fgets(work,length,codef);work2=(char*)malloc(length*sizeof(char)); i3=2*n-1;for(i=0;*(work+i-1)!='\0';i++){i2=*(work+i);if(HT[i3].lchild==0){*(work2+i4)=*(z+i3-1);i4++;i3=2*n-1;i--;}else if(i2=='0') i3=HT[i3].lchild;else if(i2=='1') i3=HT[i3].rchild;}*(work2+i4)='\0';fputs(work2,txtfile);printf("译码完成\n");printf("内容写入根目录下的文件txtfile.txt 中\n");free(work);free(work2);fclose(txtfile);fclose(codef);}//-----------------------打印编码的函数----------------------void Code_printing(){printf("下面打印根目录下文件CodePrin.txt中编码字符"); FILE * CodePrin,* codefile;if((CodePrin=fopen("CodePrin.txt","w"))==NU LL){printf("不能打开文件\n"); return;}if((codefile=fopen("codefile.txt","r"))==NU LL){printf("不能打开文件\n"); return;}char *work3;work3=(char*)malloc(51*sizeof(char));do{if(fgets(work3,51,codefile)==NULL){printf("不能读取文件\n"); break;}fputs(work3,CodePrin);puts(work3);}while(strlen(work3)==50);free(work3);printf("打印工作结束\n");fclose(CodePrin);fclose(codefile);}//------------------------------打印译码函数---------------------------------------------void Code_printing1(){Printf("下面打印根目录下文件txtfile.txt中译码字符");FILE * CodePrin1,* txtfile;if((CodePrin1=fopen("CodePrin1.txt","w"))== NULL){printf("不能打开文件\n"); return;}if((txtfile=fopen("txtfile.txt","r"))==NULL ){printf("不能打开文件\n"); return;}char *work5;work5=(char*)malloc(51*sizeof(char));do{if(fgets(work5,51,txtfile)==NULL){printf("不能读取文件\n");break;}fputs(work5,CodePrin1);puts(work5);}while(strlen(work5)==50); free(work5);printf("打印工作结束\n");fclose(CodePrin1);fclose(txtfile);}//------------------------打印哈夫曼树的函数-----------------------void coprint(HuffmanTree start,HuffmanTree HT){if(start!=HT){FILE * TreePrint;if((TreePrint=fopen("TreePrint.txt","a"))== NULL){printf("创建文件失败\n");return;}numb++;coprint(HT+start->rchild,HT);printf("%d",setw(5*numb));printf("%d",start->weight);fprintf(TreePrint,"%d\n",start->weight); coprint(HT+start->lchild,HT);numb--;fclose(TreePrint);}}void Tree_printing(HuffmanTree HT,int w) {HuffmanTree p;p=HT+w;printf("下面打印哈夫曼树\n");coprint(p,HT);printf("打印工作结束\n");}//------------------------主函数------------------------------------void main(){char choice;printf("******************************\n"); printf("欢迎使用哈夫曼编码解码系统\n");printf("******************************\n"); printf("(1)要初始化哈夫曼链表请输入'i'\n");printf("(2)编码请输入'e'\n");printf("(3)译码请输入'd'\n");printf("(4)打印编码请输入'p'\n");printf("(5)打印哈夫曼树请输入't'\n");printf("(6)打印译码请输入'y'\n");if(flag==0) printf("请先初始化哈夫曼链表,输入'i'\n");while(choice!='q'){printf("请输入下一个命令:"); scanf("%c",&choice);getchar();switch(choice){case 'i':Initialization();getchar();break;case 'e':Encoding();getchar();break;case 'd':Decoding();getchar();break;case 'p':Code_printing();getchar();break;case 't':Tree_printing(HT,2*n-1);getchar(); break;case 'y':Code_printing1();getchar();break;default:printf("input error\n");break;}}free(z);free(w);free(HT);}五、实验总结1、通过实验更好的掌握了哈夫曼树,并对哈夫曼树有了深一步的了解2、掌握了用getchar可以输入单个空格4、更进一步掌握有关类的操作5、由于算法推敲不足,使程序调试时费时不少6、本程序有些代码重复出现,从而减少了空间的利用率和增加了程序代码的杂乱性。