哈夫曼编译系统

  1 /*
  2  哈夫曼编码C语言实现
  3 */
  4 //    n个数字,对应n个权值
  5 //  n作为主输入参数,确定需要编码的数量
  6 //    输入n个权值,进行加权求解
  7 //    求解最小生成树
  8 //
  9 //    涉及数据成员:
 10 //        weight  权值
 11 //        parent  父节点
 12 //
 13 #include<stdio.h>
 14 #include<stdlib.h>
 15 #include<string>
 16 #define TREELEN 100
 17 #define MAXVALUE 99999
 18 struct HuffmanNode{
 19     int weight;
 20     int parent;
 21     int lchild;
 22     int rchild;
 23     public: HuffmanNode(int w=0,int p=-1):weight(w),parent(p)
 24     {lchild=-1;
 25     rchild=-1;}
 26 }Nodes[TREELEN];
 27 struct HuffmanResult{
 28     int weight;
 29     int *bit;
 30     int length;
 31 }* huffman;
 32 /*
 33 函数实现功能:完成哈夫曼树
 34               完成哈夫曼编码
 35 n 代表需要编码数据的个数
 36 huffman表示要存储最终结果的数组,其中Weight存放其权值,maxbit 存放其结果
 37             length表示编码长度
 38 */
 39 void HuffmanAnswer(int n)
 40 {
 41     //申请n个保存编码 的空间
 42     huffman=(HuffmanResult*)malloc(n*sizeof(HuffmanResult));
 43     int min1=0,min2=0;//每次寻找两个最小值,必须未访问,判断方式就是其父节点不为-1
 44     int added=0;
 45     int i=0,j=0;
 46     int del1=0,del2=0;
 47     int bitlen=0;
 48     int* maxbit=(int*)malloc(n*sizeof(int));
 49     for(i=0;i<n;i++)
 50     {
 51         huffman[i].weight=Nodes[i].weight;
 52     }
 53     while(true)
 54     {
 55         min2=min1=MAXVALUE;
 56         del1=del2=0;
 57         for(i=0;i<n+added;i++)
 58         {
 59             //min1保留最小值,min2保存仅比Min1大的值
 60             //del1 记录权值为min1的节点序号,del2记录权值为min2的节点序号
 61             if(Nodes[i].parent==-1&&Nodes[i].weight<min2)
 62             {
 63                 if(Nodes[i].weight<min1)
 64                 {
 65                     min2=min1;
 66                     del2=del1;
 67                     min1=Nodes[i].weight;
 68                     del1=i;
 69                 }
 70                 else{
 71                     min2=Nodes[i].weight;
 72                     del2=i;
 73                 }
 74             }
 75         }
 76         if(min2==MAXVALUE)break;//处理完毕,跳出循环
 77         Nodes[del1].parent=n+added;
 78         Nodes[del2].parent=n+added;
 79         Nodes[n+added].weight=min1+min2;
 80         Nodes[n+added].lchild=del1;
 81         Nodes[n+added].rchild=del2;
 82         added+=1;
 83     }
 84     int t=0;
 85     for(i=0;i<n;i++)
 86     {
 87         bitlen=0;
 88         j=i;
 89         while(Nodes[j].parent!=-1)
 90         {
 91             t=j;
 92             j=Nodes[j].parent;
 93             if(Nodes[j].lchild==t)
 94                 maxbit[bitlen]=0;
 95             else maxbit[bitlen]=1;
 96             bitlen++;
 97         }
 98         huffman[i].bit=(int*)malloc(bitlen*sizeof(int));
 99         for(j=0;j<bitlen;j++)
100         huffman[i].bit[bitlen-j-1]=maxbit[j];
101         huffman[i].length=bitlen;
102     }
103     printf("哈夫曼树及哈夫曼编码成功!\n");
104 }
105 //index 索引序号
106 //h    深度
107 /*
108 函数功能 :
109         打印空格
110 */
111 void printSpace(int cnt,FILE* fout)
112 {
113     for(int i=0;i<cnt;i++){
114     printf("    ");
115     fprintf(fout,"    ");
116     }
117 }
118 /*
119 函数功能:
120     打印哈夫曼树(凹陷法)
121 */
122 void printHuffTree(int index,int h,FILE* fout)
123 {
124     if(Nodes[index].lchild==-1&&Nodes[index].rchild==-1)
125     {
126         printSpace(h,fout);
127         fprintf(fout,"%d\n",index);
128         printf("%d\n",index);
129         return;
130     }
131     printSpace(h,fout);
132     printf("%d\n",index);
133     fprintf(fout,"%d\n",index);
134     printHuffTree(Nodes[index].lchild,h+1,fout);
135     printHuffTree(Nodes[index].rchild,h+1,fout);
136 }
137 /*
138     译码功能:
139         从文件中读取编码。
140         手动输入编码,需要知道长度
141 */
142 void HuffmanDecoding(int n)
143 {
144     int choice,i,len;
145     char codestore[1000];
146     char code;
147     int tcode;
148     char filename[60];
149     char savename[60];
150
151     FILE *fin;
152     FILE *fp;
153     printf("输入译码要保存的文件名(txt或bin文档):") ;
154     scanf("%s",savename);
155     if(!(fin=fopen(savename,"w")))
156     {
157         printf("保存文档路径打开失败!") ;
158         return;
159     }
160     printf("请选择获取编码的方式:\n");
161     printf("\t\t1--从文件中读取编码并翻译\n");
162     printf("\t\t2--手动输入编码并翻译\n");
163     scanf("%d",&choice);
164     if(choice==1)
165     {
166         printf("输入编码源文件名(txt或bin文档): ");
167         scanf("%s",filename);
168
169         if( !(fp=fopen(filename,"r")))
170         {
171             printf("源码文档打开失败!") ;
172             return;
173         }
174         tcode=2*n-2;
175         while(!feof(fp))
176         {
177             code=fgetc(fp);
178             if(code==‘0‘)
179                 tcode=Nodes[tcode].lchild;
180             else if(code==‘1‘)
181             tcode=Nodes[tcode].rchild;
182             if(Nodes[tcode].lchild==-1&&Nodes[tcode].rchild==-1)
183             {
184                 printf("%d ",tcode);//
185                 fprintf(fin,"%4d",tcode);
186                 tcode=2*n-2;
187             }
188         }
189         fclose(fp);
190         printf("\n译码成功!\n") ;
191     }
192     else if(choice==2)
193     {
194         printf("输入编码:\n");
195         scanf("%s",codestore);
196         len=strlen(codestore);
197         i=0;
198         tcode=2*n-2;
199         while(i<len)
200         {
201             if(codestore[i]==‘0‘)
202             tcode=Nodes[tcode].lchild;
203             else if(codestore[i]==‘1‘)tcode=Nodes[tcode].rchild;
204             if(Nodes[tcode].lchild==-1&&Nodes[tcode].rchild==-1)
205             {
206                 printf("%d ",tcode);//
207                 fprintf(fin,"%4d",tcode);
208                 tcode=2*n-2;
209             }
210             i++;
211         }
212     }
213     fclose(fin);
214     printf("\n译码成功!\n") ;
215 }
216 void PrintHuffCode(int n)
217 {
218     //输出所有权值所对应编码
219     int choice,i,j;
220     char savefile[60];
221     int flag=0;
222     FILE *fin;
223     printf("是否要保存到文件中?\n");
224     printf("\t\t1: 是\n\t\t2: 不\n");
225     scanf("%d",&choice);
226
227     if(choice==1)
228     {
229         printf("输入编码要保存到文件名:");
230         scanf("%s",savefile);
231         if(!(fin=fopen(savefile,"w"))){
232             printf("保存路径有误!\n");
233             return;
234         }
235         flag=1;
236     }
237     printf("权值\t编码长度\t编码\n");
238     if(flag==1)fprintf(fin,"权值\t编码长度\t编码\n");
239     for(i=0;i<n;i++)
240     {
241         printf("%3d\t%d\t\t",huffman[i].weight,huffman[i].length);
242     if(flag==1)    fprintf(fin,"%3d\t%d\t\t",huffman[i].weight,huffman[i].length);
243         for(j=0;j<huffman[i].length;j++)
244         {
245         printf("%d",huffman[i].bit[j]);
246     if(flag==1)    fprintf(fin,"%d",huffman[i].bit[j]);
247         }
248         printf("\n");
249     }
250     if(flag==1)
251     {
252         printf("保存到文件%s成功.\n",savefile);
253     }
254 }
255 void menu()
256 {
257     printf("\t\t\t哈夫曼编译码系统\n");
258     printf("\t\t1--输入权值并初始化数据\n");
259     printf("\t\t2--译码\n");
260     printf("\t\t3--打印哈夫曼树\n");
261     printf("\t\t4--打印哈夫曼编码\n");
262     printf("\t\t0--退出\n");
263 }
264 int main()
265 {
266
267     int n;//参数n,代表输入权值数量
268     int i=0,j=0;
269     FILE *fout;
270     char save[60];
271     menu();
272     int ce=-1;
273     while(ce!=0)
274     {
275         printf("输入功能选项: ");
276         scanf("%d",&ce);
277         switch(ce)
278         {
279             case 1: {
280             printf("输入数据数量:");
281             scanf("%d",&n);
282             //输入编码节点数据
283             printf("输入各权值\n");
284             for(;i<n;++i)
285             scanf("%d",&Nodes[i].weight);
286             HuffmanAnswer(n);}break;
287             case 2:{
288                 HuffmanDecoding(n);
289                 break;
290             }
291             case 3: {
292                 printf("输入哈夫曼树保存路径:");
293                  scanf("%s",save);
294                  fout=fopen(save,"w");
295                 printHuffTree(2*n-2,0,fout);
296                 printf("哈夫曼树打印到文件%s成功!\n",save);
297                 break;
298             }
299             case 4:{
300                 PrintHuffCode(n);
301                 break;
302             }
303             default: break;
304         }
305     }
306     return 0;
307 }
308 /*
309 输入数据数量:7
310 输入各权值
311 3 7 10 15 20 20 25
312 1 2  3 4   5  6  7
313 权值    编码长度        编码
314   3     4               0110
315   7     4               0111
316  10     3               010
317  15     3               110
318  20     3               111
319  20     2               00
320  25     2               10
321
322
323  输入数据数量:7
324 输入各权值
325 3 7 10 15 20 20 25
326
327 12
328     10
329         5
330         8
331             2
332             7
333                 0
334                 1
335     11
336         6
337         9
338             3
339             4
340
341 */
时间: 2024-10-13 21:16:57

哈夫曼编译系统的相关文章

赫夫曼编译码器实验报告

#include<stdio.h> #include<stdlib.h> #include<string.h> #include<math.h> #define MAX 100 #define MAXVALUE 10000 typedef struct{ char ch; int weight,flag; int parent,lchild,rchild; }HTNode; typedef struct{ char ch; int bit[MAX]; int

由二叉树构造赫夫曼树

赫夫曼树: 假设有n个权值{w1,w2,w3....},试构造一棵具有n个叶子节点的二叉树,每个叶子节点带权为wi,则其中带权路径长度最小的二叉树称为最优二叉树或者叫赫夫曼树. 构造赫夫曼树: 假设有n个权值,则构造出的赫夫曼树有n个叶子节点,n个权值分别设置为w1,w2,....wn,则赫夫曼树的构造规则为: 1.将w1,w2...看成是有n棵树的森林: 2.在森林中选择两个根节点的权值最小的树合并,作为一棵新树的左右子树,且新树的根节点权值为其左右子树根节点权值之和: 3.从森林中删除选取的

php 二叉树 与赫夫曼树

在学习图之前,中间休息了两天,感觉二叉树需要消化一下.所以中间去温习了下sql,推荐一本工具书<程序员的SQL金典>看名字不像一本好书,但是作为一个不错的SQL工具书还是可以小小备忘一下.涵盖内容不详细但是挺广,覆盖多种主流数据库 言归正传,以前知道折半查找,二叉树的概念也是感觉挺有意思,二叉树的实现有一个案例很不错,代码如下 class BiNode{ public $data; public $lchild; public $rchild; public function __constr

基于python的二元霍夫曼编码译码详细设计

一.设计题目 对一幅BMP格式的灰度图像(个人证件照片)进行二元霍夫曼编码和译码 二.算法设计 (1)二元霍夫曼编码: ①:图像灰度处理: 利用python的PIL自带的灰度图像转换函数,首先将彩色图片转为灰度的bmp图像,此时每个像素点可以用单个像素点来表示. ②:二元霍夫曼编码: 程序流程图: 详细设计: 统计像素点频率,首先通过python自带的PIL库的图像像素点读取函数read()获取灰度图像的所有像素点,通过循环遍历每个像素点,将每个出现的像素点值以及其次数以键值对的形式放入到pyt

霍夫曼编码求节省空间

霍夫曼编码将频繁出现的字符采用短编码,出现频率较低的字符采用长编码.具体的操作过程为:i)以每个字符的出现频率作为关键字构建最小优先级队列:ii)取出关键字最小的两个结点生成子树,根节点的关键字为孩子节点关键字之和,并将根节点插入到最小优先级队列中,直至得到一棵最优编码树. 霍夫曼编码方案是基于______策略的.用该方案对包含a到f6个字符的文件进行编码,文件包含100000个字符,每个字符的出现频率(用百分比表示)如表1-3所示,则与固定长度编码相比,该编码方案节省了______存储空间.

哈夫曼树与哈夫曼编码

哈夫曼树与哈夫曼编码 术语: i)路径和路径长度 在一棵树中,从一个结点往下可以达到的孩子或孙子结点之间的通路,称为路径. 路径中分支的数目称为路径长度.若规定根结点的层数为1,则从根结点到第L层结点的路径长度为L-1. ii)结点的权及带权路径长度 若对树中的每个结点赋给一个有着某种含义的数值,则这个数值称为该结点的权. 结点的带权路径长度为:从根结点到该结点之间的路径长度与该结点的权的乘积. iii)树的带权路径长度 树的带权路径长度:所有叶子结点的带权路径长度之和,记为WPL. 先了解一下

数据结构之哈夫曼树

#include <iostream> #include <iomanip> #include <string> using namespace std; typedef struct { string name; int weight; int parent, lchild, rchild; int visited; //设置visited选项来表示每次查找最小权值后的删除,0代表未删除,1表示删除 }HTNode,*HuffmanTree; int Min(Huff

Huffman tree(赫夫曼树、霍夫曼树、哈夫曼树、最优二叉树)

flyfish 2015-8-1 Huffman tree因为翻译不同所以有其他的名字 赫夫曼树.霍夫曼树.哈夫曼树 定义引用自严蔚敏<数据结构> 路径 从树中一个结点到另一个结点之间的分支构成两个结点之间的路径. 路径长度 路径上的分支数目称作路径长度. 树的路径长度 树的路径长度就是从根节点到每一结点的路径长度之和. 结点的带权路径长度 结点的带权路径长度就是从该结点到根节点之间的路径长度与结点上权的乘积. 树的带权路径长度 树的带权路径长度就是树中所有叶子结点的带权路径长度之和,通常记做

哈夫曼编码算法思想总结

1构建哈夫曼树. (利用队列的数据结构,不断获取最小的两个,退出队列并使之成为新节点的左右子树.然后将新节点插入队列.如此循环……) 根据用户输入的字符串,统计每个字符出现次数.设置权重.建立队列.队列中的节点是二叉树的节点(有左指针,和右指针). 建新的结点,左右指针指向队列的最后两个(那两个退出队列).然后插入队列.如此循环,就可以建立哈夫曼树. 2为每个字符编码. 节点的左为0,右为1. code(*node) { //叶节点 如果(node->left==null && no