哈夫曼树的编写与输出
哈夫曼编码源程序与运行结果

源程序:#include<stdio.h>#include<stdlib.h>#include<string.h>#include<conio.h>/* Huffman 树的存储结构*/#define n 4 /*叶子数目根据需要设定*/#define m 2*n-1 /* Huffman 树中结点总数*/typedef struct{float weight; /*结点的权值*/int lchild,rchild,parent; /*左、右孩子及双亲的下标*/}htnode;typedef htnode huffmantree[m+1];/* huffmantree是结构数组类型,其0号单元不用,存储哈夫曼树*/typedef struct{char ch; /*存储字符*/char code[n+1]; /*存放编码位串*/}codenode;typedef codenode huffmancode[n+1];/*huffmancode是结构数组类型,其0号单元不用,存储哈夫曼编码*/void inithuffmantree(huffmantree ht) /*初始化哈夫曼树函数inithuffmantree()*/{int i;for(i=0;i<=m;i++){ht[i].weight=0;ht[i].lchild=ht[i].rchild=ht[i].parent=0;}}void inputweight(huffmantree ht) /*输入权值函数*/{int i;printf("请输入概率\n");for(i=1;i<=n;i++){scanf("%f",&ht[i].weight);}for(i=1;i<=n;i++){ht[i].weight=ht[i].weight*100;}}void selectmin(huffmantree ht, int i, int *p1, int *p2)/* 在ht[1..i]中选两个权值最小的根结点,其序号为*p1和*p2,*p1中放权值最小的根结点的序号,*p2中放权值次小的根结点的序号*/{int j,min1,min2; /* min1,min2分别是最小权值和次小权值*/min1=min2=32767;*p1=*p2=0;for(j=1;j<=i;j++){if(ht[j].parent==0) /* j 为根结点*/if(ht[j].weight<min1||min1==32767){if(min1!=32767) {min2=min1; *p2=*p1;}min1=ht[j].weight;*p1=j;}elseif(ht[j].weight<min2||min2==32767){min2=ht[j].weight;*p2=j;}}}void createhuffmantree(huffmantree ht) /*构造huffman树,ht[m]为其根结点*/{int i,p1,p2;inithuffmantree(ht); /* 将ht初始化*/inputweight(ht); /* 输入叶子权值至ht [1..n]的weight域*/for(i=n+1;i<=m;i++) /* 共进行n-1次合并,新结点依次存于ht[i]中*/ {selectmin(ht,i-1,&p1,&p2); /*在ht [1.. i-1]中选择两个权值最小的根结点,其序号分别为p1和p2*/ht[p1].parent=ht[p2].parent=i;ht[i].lchild=p1; /* 最小权值的根结点是新结点的左孩子*/ht[i].rchild=p2; /* 次小权值的根结点是新结点的右孩子*/ht[i].weight=ht[p1].weight+ht[p2].weight;}}void huffmancodes(huffmantree ht,huffmancode hcd) /*根据huffman树ht求huffman编码*/ {int c,p,i,num[n+1],j; /* c和p分别指示ht中孩子和双亲的位置*/ char cd[n+1]; /* 临时存放编码*/int start; /* 指示编码在cd 中的起始位置*/float l=0;cd[n]='\0'; /* 编码结束符*/printf("请输入字符\n");for(i=0;i<=n;i++) /* 依次求叶子ht [i]的编码*/{ hcd[i].ch=getchar(); /* 读入叶子ht [i]对应的字符*/start=n; /* 编码起始位置的初值*/c=i; /* 从叶子ht [i]开始上溯*/while((p=ht[c].parent)!=0) /* 直至上溯到ht [ c]是树根为止*/{ cd[--start]=(ht[p].lchild==c)?'0':'1'; /*若ht [ c]是ht[p]的左孩子,则生成代码0,否则生成代码1*/c=p; /* 继续上溯*/}strcpy(hcd[i].code,&cd[start]); /* 复制编码位串*/}printf("\n");printf("序号信源字母码字码字长\n");for(i=1;i<=n;i++)printf(" %d %c %s %d\n",i,hcd[i].ch,hcd[i].code,strlen(hcd[i].code));for(i=1;i<=n;i++)l=l+strlen(hcd[i].code)*(ht[i].weight/100);printf("平均码长=%f比特\n",l);}void main(){huffmantree t;huffmancode h;createhuffmantree(t); /* 构造huffman树*/huffmancodes(t,h); /* 构造huffman编码*/}。
c语言实现哈夫曼算法

c语言实现哈夫曼算法以下是C语言实现哈夫曼算法的示例代码:```cinclude <>include <>include <>// 定义哈夫曼树节点结构体typedef struct HuffmanNode {char data; // 节点存储的数据int freq; // 节点出现的频率struct HuffmanNode left, right; // 左右子树指针} HuffmanNode;// 定义创建哈夫曼树函数HuffmanNode createNode(char data, int freq) { HuffmanNode node =(HuffmanNode)malloc(sizeof(HuffmanNode));node->data = data;node->freq = freq;node->left = node->right = NULL;return node;}// 定义比较函数,用于按照频率从小到大排序int compare(const void a, const void b) {return ((HuffmanNode)b)->freq - ((HuffmanNode)a)->freq; }// 定义构建哈夫曼树函数HuffmanNode buildHuffmanTree(char data[], int freq[], int size) { if (size == 1) {return createNode(data[0], freq[0]);} else {HuffmanNode nodes[size]; // 存储所有节点指针的数组for (int i = 0; i < size; i++) {nodes[i] = createNode(data[i], freq[i]);}qsort(nodes, size, sizeof(HuffmanNode), compare); // 按频率从小到大排序return mergeNodes(nodes, size); // 合并两个最小的节点,直到只剩下一个节点}}// 定义合并两个最小节点函数HuffmanNode mergeNodes(HuffmanNode nodes[], int size) {if (size == 0) return NULL; // 空节点返回NULL指针if (size == 1) return nodes[0]; // 只剩下一个节点直接返回该节点指针 HuffmanNode root = createNode('$', nodes[0]->freq + nodes[1]->freq); // 创建根节点,频率为左右子树频率之和root->left = mergeNodes(nodes+1, size-1); // 递归合并剩余节点,左子树指向左子树数组中除第一个节点外的所有节点指针,右子树指向右子树数组中除最后一个节点外的所有节点指针return root; // 返回根节点指针}```。
数据结构课程设计(哈夫曼编码)

┊┊┊┊┊┊┊┊┊┊┊┊┊装┊┊┊┊┊订┊┊┊┊┊线┊┊┊┊┊┊┊┊┊┊┊┊┊目录目录 (1)1 课程设计的目的和意义 (2)2 需求分析 (3)3 系统设计 (4)(1)设计思路及方案 (4)(2)模块的设计及介绍 (4)(3)主要模块程序流程图 (6)4 系统实现 (10)(1)主调函数 (10)(2)建立HuffmanTree (10)(3)生成Huffman编码并写入文件 (13)(4)电文译码 (14)5 系统调试 (16)小结 (18)参考文献 (19)附录源程序 (20)┊┊┊┊┊┊┊┊┊┊┊┊┊装┊┊┊┊┊订┊┊┊┊┊线┊┊┊┊┊┊┊┊┊┊┊┊┊1 课程设计的目的和意义在当今信息爆炸时代,如何采用有效的数据压缩技术来节省数据文件的存储空间和计算机网络的传送时间已越来越引起人们的重视。
哈夫曼编码正是一种应用广泛且非常有效的数据压缩技术。
哈夫曼编码的应用很广泛,利用哈夫曼树求得的用于通信的二进制编码称为哈夫曼编码。
树中从根到每个叶子都有一条路径,对路径上的各分支约定:指向左子树的分支表示“0”码,指向右子树的分支表示“1”码,取每条路径上的“0”或“1”的序列作为和各个对应的字符的编码,这就是哈夫曼编码。
通常我们把数据压缩的过程称为编码,解压缩的过程称为解码。
电报通信是传递文字的二进制码形式的字符串。
但在信息传递时,总希望总长度尽可能最短,即采用最短码。
作为软件工程专业的学生,我们应该很好的掌握这门技术。
在课堂上,我们能过学到许多的理论知识,但我们很少有过自己动手实践的机会!课程设计就是为解决这个问题提供了一个平台。
在课程设计过程中,我们每个人选择一个课题,认真研究,根据课堂讲授内容,借助书本,自己动手实践。
这样不但有助于我们消化课堂所讲解的内容,还可以增强我们的独立思考能力和动手能力;通过编写实验代码和调试运行,我们可以逐步积累调试C程序的经验并逐渐培养我们的编程能力、用计算机解决实际问题的能力。
最优二叉树(哈夫曼树)的构建及编码

最优⼆叉树(哈夫曼树)的构建及编码参考:数据结构教程(第五版)李春葆主编⼀,概述1,概念 结点的带权路径长度: 从根节点到该结点之间的路径长度与该结点上权的乘积。
树的带权路径长度: 树中所有叶结点的带权路径长度之和。
2,哈夫曼树(Huffman Tree) 给定 n 个权值作为 n 个叶⼦结点,构造⼀棵⼆叉树,若该树的带权路径长度达到最⼩,则称这样的⼆叉树为最优⼆叉树,也称为哈夫曼树。
哈夫曼树是带权路径长度最短的树,权值较⼤的结点离根较近。
⼆,哈夫曼树的构建1,思考 要实现哈夫曼树⾸先有个问题摆在眼前,那就是哈夫曼树⽤什么数据结构表⽰? ⾸先,我们想到的肯定数组了,因为数组是最简单和⽅便的。
⽤数组表⽰⼆叉树有两种⽅法: 第⼀种适⽤于所有的树。
即利⽤树的每个结点最多只有⼀个⽗节点这种特性,⽤ p[ i ] 表⽰ i 结点的根节点,进⽽表⽰树的⽅法。
但这种⽅法是有缺陷的,权重的值需要另设⼀个数组表⽰;每次找⼦节点都要遍历⼀遍数组,⼗分浪费时间。
第⼆种只适⽤于⼆叉树。
即利⽤⼆叉树每个结点最多只有两个⼦节点的特点。
从下标 0 开始表⽰根节点,编号为 i 结点即为 2 * i + 1 和 2 * i + 2,⽗节点为 ( i - 1) / 2,没有⽤到的空间⽤ -1 表⽰。
但这种⽅法也有问题,即哈夫曼树是从叶结点⾃下往上构建的,⼀开始树叶的位置会因为⽆法确定⾃⾝的深度⽽⽆法确定,从⽽⽆法构造。
既然如此,只能⽤⽐较⿇烦的结构体数组表⽰⼆叉树了。
typedef struct HTNode // 哈夫曼树结点{double w; // 权重int p, lc, rc;}htn;2,算法思想 感觉⽐较偏向于贪⼼,权重最⼩的叶⼦节点要离根节点越远,⼜因为我们是从叶⼦结点开始构造最优树的,所以肯定是从最远的结点开始构造,即权重最⼩的结点开始构造。
所以先选择权重最⼩的两个结点,构造⼀棵⼩⼆叉树。
然后那两个最⼩权值的结点因为已经构造完了,不会在⽤了,就不去考虑它了,将新⽣成的根节点作为新的叶⼦节加⼊剩下的叶⼦节点,⼜因为该根节点要能代表整个以它为根节点的⼆叉树的权重,所以其权值要为其所有⼦节点的权重之和。
c语言哈夫曼树的构造及编码

c语言哈夫曼树的构造及编码一、哈夫曼树概述哈夫曼树是一种特殊的二叉树,它的构建基于贪心算法。
它的主要应用是在数据压缩和编码中,可以将频率高的字符用较短的编码表示,从而减小数据存储和传输时所需的空间和时间。
二、哈夫曼树的构造1. 哈夫曼树的定义哈夫曼树是一棵带权路径长度最短的二叉树。
带权路径长度是指所有叶子节点到根节点之间路径长度与其权值乘积之和。
2. 构造步骤(1) 将待编码字符按照出现频率从小到大排序。
(2) 取出两个权值最小的节点作为左右子节点,构建一棵新的二叉树。
(3) 将新构建的二叉树加入到原来排序后队列中。
(4) 重复上述步骤,直到队列只剩下一个节点,该节点即为哈夫曼树的根节点。
3. C语言代码实现以下代码实现了一个简单版哈夫曼树构造函数:```ctypedef struct TreeNode {int weight; // 权重值struct TreeNode *leftChild; // 左子节点指针struct TreeNode *rightChild; // 右子节点指针} TreeNode;// 构造哈夫曼树函数TreeNode* createHuffmanTree(int* weights, int n) {// 根据权值数组构建节点队列,每个节点都是一棵单独的二叉树TreeNode** nodes = (TreeNode**)malloc(sizeof(TreeNode*) * n);for (int i = 0; i < n; i++) {nodes[i] = (TreeNode*)malloc(sizeof(TreeNode));nodes[i]->weight = weights[i];nodes[i]->leftChild = NULL;nodes[i]->rightChild = NULL;}// 构建哈夫曼树while (n > 1) {int minIndex1 = -1, minIndex2 = -1;for (int i = 0; i < n; i++) {if (nodes[i] != NULL) {if (minIndex1 == -1 || nodes[i]->weight < nodes[minIndex1]->weight) {minIndex2 = minIndex1;minIndex1 = i;} else if (minIndex2 == -1 || nodes[i]->weight < nodes[minIndex2]->weight) {minIndex2 = i;}}}TreeNode* newNode =(TreeNode*)malloc(sizeof(TreeNode));newNode->weight = nodes[minIndex1]->weight + nodes[minIndex2]->weight;newNode->leftChild = nodes[minIndex1];newNode->rightChild = nodes[minIndex2];// 将新构建的二叉树加入到原来排序后队列中nodes[minIndex1] = newNode;nodes[minIndex2] = NULL;n--;}return nodes[minIndex1];}```三、哈夫曼编码1. 哈夫曼编码的定义哈夫曼编码是一种前缀编码方式,它将每个字符的编码表示为二进制串。
数据结构 哈夫曼编码实验报告

数据结构哈夫曼编码实验报告数据结构哈夫曼编码实验报告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 构建哈夫曼树根据字符频率构建哈夫曼树是哈夫曼编码的核心步骤。
我们可以使用最小堆(优先队列)来高效地构建哈夫曼树。
首先,将每个字符频率作为节点存储到最小堆中。
然后,从最小堆中取出频率最小的两个节点,将它们作为子树构建成一个新的节点,新节点的频率等于两个子节点频率的和。
将新节点重新插入最小堆,并重复该过程,直到最小堆中只剩下一个节点,即哈夫曼树的根节点。
哈夫曼编解码算法设计

哈夫曼编解码算法设计1.引言1.1 概述概述部分将对哈夫曼编解码算法进行简要介绍,包括该算法的产生背景、主要特点以及应用领域等方面的内容。
哈夫曼编解码算法是一种基于权重分布的压缩算法,它通过对输入的数据流进行编码和解码来实现数据的压缩和恢复。
该算法由大卫·哈夫曼(David A. Huffman)于1952年提出,是一种被广泛应用于信息论和数据压缩领域的有效算法。
该算法的主要特点是根据输入数据的权重分布构建一棵哈夫曼树,通过不等长的编码方式来表示输入数据中出现频率较高的字符或数据块。
编码时,出现频率较高的字符使用较短的二进制编码,而出现频率较低的字符则使用较长的二进制编码,以此来实现数据的压缩效果。
哈夫曼编码算法在数据压缩领域有着广泛的应用。
由于压缩后的数据长度较短,可以大大节省存储空间和传输带宽,因此被广泛应用于各种数据传输和存储场景中,如文件压缩、图像压缩、语音压缩等。
此外,哈夫曼编码算法的设计思想也对后续的数据压缩算法提供了重要的借鉴和参考价值。
本文将详细介绍哈夫曼编码算法的原理、设计与实现,并通过实例和实验验证算法的性能和效果。
通过对哈夫曼编码算法的研究与分析,可以更好地理解该算法的优势和不足,并为后续的算法改进和优化提供参考。
最后,本文将总结哈夫曼编码算法的主要特点和应用场景,并对未来的研究方向提出展望。
1.2 文章结构文章结构部分主要介绍本文的各个部分以及每个部分的内容安排。
在本文中,共包含引言、正文和结论三个部分。
引言部分主要介绍了整篇文章的背景和目的。
在概述部分,简要说明了哈夫曼编解码算法的概念和作用,以及该算法在通信领域的重要性。
然后,文章结构部分具体说明了本文的组织结构,以便读者能够清晰地了解文章的整体脉络。
正文部分是本文的主体,分为两个部分:哈夫曼编码算法原理和哈夫曼编码算法设计与实现。
在哈夫曼编码算法原理部分,将详细介绍哈夫曼编码算法的基本原理,包括频率统计、构建哈夫曼树和生成哈夫曼编码等步骤。
哈夫曼树的构造

哈夫曼树的构造关键思想: 依据哈弗曼树的定义,⼀棵⼆叉树要使其WPL值最⼩,必须使权值越⼤的叶⼦结点越靠近根结点,⽽权值越⼩的叶⼦结点越远离根结点。
哈弗曼根据这⼀特点提出了⼀种构造最优⼆叉树的⽅法,其基本思想如下:1。
根据给定的n个权值{w1, w2, w3 ... w n },构造n棵只有根节点的⼆叉树,令起权值为w j2。
在森林中选取两棵根节点权值最⼩的树作为左右⼦树,构造⼀颗新的⼆叉树,置新⼆叉树根节点权值为其左右⼦树根节点权值之和。
注意,左⼦树的权值应⼩于右⼦树的权值。
3。
从森林中删除这两棵树,同时将新得到的⼆叉树加⼊森林中。
(换句话说,之前的2棵最⼩的根节点已经被合并成⼀个新的结点了)4。
重复上述两步,直到只含⼀棵树为⽌,这棵树即是哈弗曼树以下演⽰了⽤Huffman算法构造⼀棵Huffman树的过程:考研题⽬:三、哈夫曼树的在编码中的应⽤在电⽂传输中,须要将电⽂中出现的每⼀个字符进⾏⼆进制编码。
在设计编码时须要遵守两个原则:(1)发送⽅传输的⼆进制编码,到接收⽅解码后必须具有唯⼀性,即解码结果与发送⽅发送的电⽂全然⼀样;(2)发送的⼆进制编码尽可能地短。
以下我们介绍两种编码的⽅式。
1. 等长编码这样的编码⽅式的特点是每⼀个字符的编码长度同样(编码长度就是每⼀个编码所含的⼆进制位数)。
如果字符集仅仅含有4个字符A,B,C,D,⽤⼆进制两位表⽰的编码分别为00,01,10,11。
若如今有⼀段电⽂为:ABACCDA,则应发送⼆进制序列:00010010101100,总长度为14位。
当接收⽅接收到这段电⽂后,将按两位⼀段进⾏译码。
这样的编码的特点是译码简单且具有唯⼀性,但编码长度并⾮最短的。
2. 不等长编码在传送电⽂时,为了使其⼆进制位数尽可能地少,能够将每⼀个字符的编码设计为不等长的,使⽤频度较⾼的字符分配⼀个相对照较短的编码,使⽤频度较低的字符分配⼀个⽐較长的编码。
⽐如,能够为A,B,C,D四个字符分别分配0,00,1,01,并可将上述电⽂⽤⼆进制序列:000011010发送,其长度仅仅有9个⼆进制位,但随之带来了⼀个问题,接收⽅接到这段电⽂后⽆法进⾏译码,由于⽆法断定前⾯4个0是4个A,1个B、2个A,还是2个B,即译码不唯⼀,因此这样的编码⽅法不可使⽤。