哈夫曼树的编码和译码

合集下载

C++哈夫曼树编码和译码的实现

C++哈夫曼树编码和译码的实现

C++哈夫曼树编码和译码的实现⼀.背景介绍: 给定n个权值作为n个叶⼦结点,构造⼀棵⼆叉树,若带权路径长度达到最⼩,称这样的⼆叉树为最优⼆叉树,也称为哈夫曼树(Huffman Tree)。

哈夫曼树是带权路径长度最短的树,权值较⼤的结点离根较近。

⼆.实现步骤: 1.构造⼀棵哈夫曼树 2.根据创建好的哈夫曼树创建⼀张哈夫曼编码表 3.输⼊⼀串哈夫曼序列,输出原始字符三.设计思想: 1.⾸先要构造⼀棵哈夫曼树,哈夫曼树的结点结构包括权值,双亲,左右孩⼦;假如由n个字符来构造⼀棵哈夫曼树,则共有结点2n-1个;在构造前,先初始化,初始化操作是把双亲,左右孩⼦的下标值都赋为0;然后依次输⼊每个结点的权值2.第⼆步是通过n-1次循环,每次先找输⼊的权值中最⼩的两个结点,把这两个结点的权值相加赋给⼀个新结点,,并且这个新结点的左孩⼦是权值最⼩的结点,右孩⼦是权值第⼆⼩的结点;鉴于上述找到的结点都是双亲为0的结点,为了下次能正确寻找到剩下结点中权值最⼩的两个结点,每次循环要把找的权值最⼩的两个结点的双亲赋值不为0(i).就这样通过n-1循环下、操作,创建了⼀棵哈夫曼树,其中,前n 个结点是叶⼦(输⼊的字符结点)后n-1个是度为2的结点3.编码的思想是逆序编码,从叶⼦结点出发,向上回溯,如果该结点是回溯到上⼀个结点的左孩⼦,则在记录编码的数组⾥存“0”,否则存“1”,注意是倒着存;直到遇到根结点(结点双亲为0),每⼀次循环编码到根结点,把编码存在编码表中,然后开始编码下⼀个字符(叶⼦)4.译码的思想是循环读⼊⼀串哈夫曼序列,读到“0”从根结点的左孩⼦继续读,读到“1”从右孩⼦继续,如果读到⼀个结点的左孩⼦和右孩⼦是否都为0,如果是说明已经读到了⼀个叶⼦(字符),翻译⼀个字符成功,把该叶⼦结点代表的字符存在⼀个存储翻译字符的数组中,然后继续从根结点开始读,直到读完这串哈夫曼序列,遇到结束符便退出翻译循环四.源代码:1/***************************************2⽬的:1.根据输⼊的字符代码集及其权值集,3构造赫夫曼树,输出各字符的赫夫曼编码42.输⼊赫夫曼码序列,输出原始字符代码5作者:Dmego 时间:2016-11-116****************************************/7 #include<iostream>8#define MAX_MA 10009#define MAX_ZF 10010using namespace std;1112//哈夫曼树的储存表⽰13 typedef struct14 {15int weight; //结点的权值16int parent, lchild, rchild;//双亲,左孩⼦,右孩⼦的下标17 }HTNode,*HuffmanTree; //动态分配数组来储存哈夫曼树的结点1819//哈夫曼编码表的储存表⽰20 typedef char **HuffmanCode;//动态分配数组存储哈夫曼编码2122//返回两个双亲域为0且权值最⼩的点的下标23void Select(HuffmanTree HT, int n, int &s1, int &s2)24 {25/*n代表HT数组的长度26*/2728//前两个for循环找所有结点中权值最⼩的点(字符)29for (int i = 1; i <= n; i++)30 {//利⽤for循环找出⼀个双亲为0的结点31if (HT[i].parent == 0)32 {33 s1 = i;//s1初始化为i34break;//找到⼀个后⽴即退出循环35 }36 }37for (int i = 1; i <= n; i++)38 {/*利⽤for循环找到所有结点(字符)权值最⼩的⼀个39并且保证该结点的双亲为0*/40if (HT[i].weight < HT[s1].weight && HT[i].parent == 0)41 s1 = i;42 }43//后两个for循环所有结点中权值第⼆⼩的点(字符)44for (int i = 1; i <= n; i++)45 {//利⽤for循环找出⼀个双亲为0的结点,并且不能是s146if (HT[i].parent == 0 && i != s1)47 {48 s2 = i;//s2初始化为i49break;//找到⼀个后⽴即退出循环50 }51 }5253for (int i = 1; i <= n; i++)54 {/*利⽤for循环找到所有结点(字符)权值第⼆⼩的⼀个,55该结点满⾜不能是s1且双亲是0*/56if (HT[i].weight < HT[s2].weight && HT[i].parent == 0 && i!= s1)57 s2 = i;58 }5960 }6162//构造哈夫曼树63void CreateHuffmanTree(HuffmanTree &HT, int n)64 {65/*-----------初始化⼯作-------------------------*/66if (n <= 1)67return;68int m = 2 * n - 1;69 HT = new HTNode[m + 1];70for (int i = 1; i <= m; ++i)71 {//将1~m号单元中的双亲,左孩⼦,右孩⼦的下标都初始化为072 HT[i].parent = 0; HT[i].lchild = 0; HT[i].rchild = 0;73 }74for (int i = 1; i <= n; ++i)75 {76 cin >> HT[i].weight;//输⼊前n个单元中叶⼦结点的权值77 }78/*-----------创建⼯作---------------------------*/79int s1,s2;80for (int i = n + 1; i <= m; ++i)81 {//通过n-1次的选择,删除,合并来构造哈夫曼树82 Select(HT, i - 1, s1, s2);83/*cout << HT[s1].weight << " , " << HT[s2].weight << endl;*/84/*将s1,s2的双亲域由0改为i85 (相当于把这两个结点删除了,这两个结点不再参与Select()函数)*/86 HT[s1].parent = i;87 HT[s2].parent = i;88//s1,与s2分别作为i的左右孩⼦89 HT[i].lchild = s1;90 HT[i].rchild = s2;91//结点i的权值为s1,s2权值之和92 HT[i].weight = HT[s1].weight + HT[s2].weight;93 }94 }9596//从叶⼦到根逆向求每个字符的哈夫曼编码,储存在编码表HC中97void CreatHuffmanCode(HuffmanTree HT, HuffmanCode &HC, int n)98 {99 HC = new char*[n + 1];//分配储存n个字符编码的编码表空间100char *cd = new char[n];//分配临时存储字符编码的动态空间101 cd[n - 1] = '\0';//编码结束符102for (int i = 1; i <= n; i++)//逐个求字符编码103 {104int start = n - 1;//start 开始指向最后,即编码结束符位置105int c = i;106int f = HT[c].parent;//f指向结点c的双亲107while (f != 0)//从叶⼦结点开始回溯,直到根结点108 {109 --start;//回溯⼀次,start向前指向⼀个位置110if (HT[f].lchild == c) cd[start] = '0';//结点c是f的左孩⼦,则cd[start] = 0; 111else cd[start] = '1';//否则c是f的右孩⼦,cd[start] = 1112 c = f;113 f = HT[f].parent;//继续向上回溯114 }115 HC[i] = new char[n - start];//为第i个字符编码分配空间116 strcpy(HC[i], &cd[start]);//把求得编码的⾸地址从cd[start]复制到HC的当前⾏中117 }118delete cd;119 }120121//哈夫曼译码122void TranCode(HuffmanTree HT,char a[],char zf[],char b[],int n)123 {124/*125 HT是已经创建好的哈夫曼树126 a[]⽤来传⼊⼆进制编码127 b[]⽤来记录译出的字符128 zf[]是与哈夫曼树的叶⼦对应的字符(叶⼦下标与字符下标对应)129 n是字符个数,相当于zf[]数组得长度130*/131132int q = 2*n-1;//q初始化为根结点的下标133int k = 0;//记录存储译出字符数组的下标134int i = 0;135for (i = 0; a[i] != '\0';i++)136 {//for循环结束条件是读⼊的字符是结束符(⼆进制编码)137//此代码块⽤来判断读⼊的⼆进制字符是0还是1138if (a[i] == '0')139 {/*读⼊0,把根结点(HT[q])的左孩⼦的下标值赋给q140下次循环的时候把HT[q]的左孩⼦作为新的根结点*/141 q = HT[q].lchild;142 }143else if (a[i] == '1')144 {145 q = HT[q].rchild;146 }147//此代码块⽤来判断HT[q]是否为叶⼦结点148if (HT[q].lchild == 0 && HT[q].rchild == 0)149 {/*是叶⼦结点,说明已经译出⼀个字符150该字符的下标就是找到的叶⼦结点的下标*/151 b[k++] = zf[q];//把下标为q的字符赋给字符数组b[]152 q = 2 * n - 1;//初始化q为根结点的下标153//继续译下⼀个字符的时候从哈夫曼树的根结点开始154 }155 }156/*译码完成之后,⽤来记录译出字符的数组由于没有结束符输出的157时候回报错,故紧接着把⼀个结束符加到数组最后*/158 b[k] = '\0';159 }160//菜单函数161void menu()162 {163 cout << endl;164 cout << " ┏〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓┓" << endl;165 cout << " ┃★★★★★★★哈夫曼编码与译码★★★★★★★┃" << endl;166 cout << " ┃ 1. 创建哈夫曼树┃" << endl;167 cout << " ┃ 2. 进⾏哈夫曼编码┃" << endl;168 cout << " ┃ 3. 进⾏哈夫曼译码┃" << endl;169 cout << " ┃ 4. 退出程序┃" << endl;170 cout << " ┗〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓┛" << endl;171 cout << " <><注意:空格字符⽤'- '代替><>" << endl;172 cout << endl;173 }174void main()175 {176int falg;//记录要编码的字符个数177char a[MAX_MA];//储存输⼊的⼆进制字符178char b[MAX_ZF];//存储译出的字符179char zf[MAX_ZF];//储存要编码的字符180 HuffmanTree HT = NULL;//初始化树为空数181 HuffmanCode HC = NULL;//初始化编码表为空表182 menu();183while (true)184 {185int num;186 cout << "<><请选择功能(1-创建 2-编码 3-译码 4-退出)><>: ";187 cin >> num;188switch (num)189 {190case1 :191 cout << "<><请输⼊字符个数><>:";192 cin >> falg;193//动态申请falg个长度的字符数组,⽤来存储要编码的字符194/*char *zf = new char[falg];*/195 cout << "<><请依次输⼊" << falg << "个字符:><>: ";196for (int i = 1; i <= falg; i++)197 cin >> zf[i];198 cout << "<><请依次输⼊" << falg << "个字符的权值><>: ";199 CreateHuffmanTree(HT, falg);//调⽤创建哈夫曼树的函数200 cout << endl;201 cout << "<><创建哈夫曼成功!,下⾯是该哈夫曼树的参数输出><>:" << endl;202 cout << endl;203 cout << "结点i"<<"\t"<<"字符" << "\t" << "权值" << "\t" << "双亲" << "\t" << "左孩⼦" << "\t" << "右孩⼦" << endl;204for (int i = 1; i <= falg * 2 - 1; i++)205 {206 cout << i << "\t"<<zf[i]<< "\t" << HT[i].weight << "\t" << HT[i].parent << "\t" << HT[i].lchild << "\t" << HT[i].rchild << endl; 207 }208 cout << endl;209break;210case2:211 CreatHuffmanCode(HT, HC, falg);//调⽤创建哈夫曼编码表的函数212 cout << endl;213 cout << "<><⽣成哈夫曼编码表成功!,下⾯是该编码表的输出><>:" << endl; 214 cout << endl;215 cout << "结点i"<<"\t"<<"字符" << "\t" << "权值" << "\t" << "编码" << endl; 216for (int i = 1; i <= falg; i++)217 {218 cout << i << "\t"<<zf[i]<< "\t" << HT[i].weight << "\t" << HC[i] << endl; 219 }220 cout << endl;221break;222case3:223 cout << "<><请输⼊想要翻译的⼀串⼆进制编码><>:";224/*这样可以动态的直接输⼊⼀串⼆进制编码,225因为这样输⼊时最后系统会⾃动加⼀个结束符*/226 cin >> a;227 TranCode(HT, a, zf, b, falg);//调⽤译码的函数,228/*这样可以直接把数组b输出,因为最后有229在数组b添加输出时遇到结束符会结束输出*/230 cout << endl;231 cout << "<><译码成功!翻译结果为><>:" << b << endl;232 cout << endl;233break;234case4:235 cout << endl;236 cout << "<><退出成功!><>" << endl;237 exit(0);238default:239break;240 }241 }242243//-abcdefghijklmnopqrstuvwxyz244//186 64 13 22 32 103 21 15 47 57 1 5 32 20 57 63 15 1 48 51 80 23 8 18 1 16 1245//000101010111101111001111110001100100101011110110246247 }哈夫曼编码译码五.运⾏截图:。

哈夫曼编码和译码

哈夫曼编码和译码
11
哈夫曼树的构造算法: 哈夫曼树的构造算法: 个结点的一维数组, (1)初始化哈夫曼树的 )初始化哈夫曼树的2n-1个结点的一维数组, 个结点的一维数组 即将各结点中的各个域均置0; 即将各结点中的各个域均置 ; 个权值存放到一维数组的前n个单元中 (2)读入 个权值存放到一维数组的前 个单元中, )读入n个权值存放到一维数组的前 个单元中, 它们即为初始森林中的n个只含根结点的权值 个只含根结点的权值; 它们即为初始森林中的 个只含根结点的权值; (3)对森林中的二叉树进行合并,产生 个新 )对森林中的二叉树进行合并,产生n-1个新 结点,依次存放到一维数组的第n+1个开始的单元中, 个开始的单元中, 结点,依次存放到一维数组的第 个开始的单元中 在这个过程中要注意对每个结点双亲域, 在这个过程中要注意对每个结点双亲域,左右孩子 域以及权值的修改. 域以及权值的修改.
13
s1=maxval;s2= maxval;/ 设maxval为float类型最大值 ; ;/*设 ;/ 为 类型最大值 */ for(j =1;j<=i;j+ +) ( ; ; ) if (ht[j].parent = =0) /*判断是否为根结点 判断是否为根结点*/ 判断是否为根结点 if (ht[j].weight<s1) { s2=s1;s1= ht[j].weight; p2=p1;p1=j; } ; ; ; ; else if (ht[j].weight <s2) { s2= ht[j].weight; p2=j; } ; ; ht[p1].parent=i;ht[p2].parent=i; ; ; ht[i].lchild =p1;ht[i].rchild=p2; ; ; ht[i].weight= ht[pl].weight+ht[p2].weight; ; } return (ht);} ;

哈夫曼编码和译码

哈夫曼编码和译码

哈夫曼编码和译码哈夫曼编码是一种用于数据压缩的编码方法,通过根据字符出现的频率对字符进行编码,以便能够用较少的位数来表示出现频率较高的字符。

编码过程中,根据频率最低的字符构建一棵哈夫曼树,将字符的编码表示为树的路径。

而哈夫曼译码则是将经过哈夫曼编码后的数据解码成原始数据的过程。

在给定的文本中,首先需要统计每个字符的出现频率。

然后使用这些频率构建哈夫曼树。

构建哈夫曼树的过程中使用最小堆数据结构,通过不断合并两个最小频率的字符节点来构建树。

合并两个节点的过程中,创建一个新的节点来作为它们的父节点,并将其频率设置为两个子节点频率之和。

在构建树的过程中,赋予左子节点编码为0,右子节点编码为1。

构建完成哈夫曼树后,将每个字符的编码表示为从根节点到该字符节点的路径,例如,向左走的路径可以表示为0,向右走的路径可以表示为1。

为了能够正确译码,需要将字符及其对应的编码存储在一个编码表中。

对于给定的文本数据,应用哈夫曼编码后,会得到一个压缩后的编码字符串。

在哈夫曼译码过程中,从根节点开始遍历编码字符串的每一位,如果是0,则向左子节点移动,如果是1,则向右子节点移动,直到到达叶子节点。

找到叶子节点后,将对应的字符输出,并回到根节点,继续下一位的译码,直到编码字符串结束。

哈夫曼编码可以实现无损压缩,即通过译码过程能够还原出原始数据,而不会丢失任何信息。

它是一种广泛应用于数据压缩领域的有效方法,用于减小数据存储和传输的大小。

在实际应用中,哈夫曼编码被广泛应用于图像、音频和视频等多媒体数据的压缩中。

总结起来,哈夫曼编码是一种用于数据压缩的编码方法,通过根据字符出现的频率对字符进行编码,以便用较少的位数来表示出现频率较高的字符。

哈夫曼译码则是将经过编码后的数据解码成原始数据的过程。

它通过构建哈夫曼树和编码表,实现了高效的数据压缩和解压缩。

哈夫曼编码被广泛应用于数据存储和传输领域,特别是在多媒体数据的压缩中。

哈夫曼树的编码与译码

哈夫曼树的编码与译码

#include<stdio.h>#include<stdlib.h>#define n 4#define m 2*n-1#define maxval 32769typedef struct{float weight;int lchild,rchild,parent;char ch;}huftree;typedef struct{char bits[n];int start;}codetype;codetype code[n];huftree tree[m];void hufman(huftree tree[])//创建哈夫曼树{int i,j,p1,p2;char ch;float small1,small2,f;for(i=0;i<m;i++)//初始化所有结点{tree[i].parent=0;tree[i].lchild=0;tree[i].rchild=0;tree[i].weight=0.0;}printf("请输入结点的权值:\n");for(i=0;i<n;i++)//输入n个结点的权值{scanf("%f",&f);tree[i].weight=f;}printf("请输入结点的字符:\n");scanf("%c",&ch);for(i=0;i<n;i++)//输入n个结点的权值{scanf("%c",&ch);tree[i].ch=ch;}for(i=n;i<m;i++)//进行n-1次合并,产生n-1个新结点{p1=0,p2=0;small1=maxval;small2=maxval;for(j=0;j<=i-1;j++)//找出权值最小的两个根结点{if(tree[j].parent==0){if(tree[j].weight<small1)//改变最小权与次小权的位置{small2=small1;small1=tree[j].weight;p2=p1;p1=j;//锁定最小权的位置}else{if(tree[j].weight<small2){small2=tree[j].weight;p2=j;//锁定次小权的位置}}}}tree[p1].parent=i+1;//生成的新结点为最小权与次小权的双亲tree[p2].parent=i+1;tree[i].lchild=p1+1;tree[i].rchild=p2+1;tree[i].weight=tree[p1].weight+tree[p2].weight;}}void creathufcode(codetype code[])//由哈夫曼数构建哈夫曼编码{int i,c,p;codetype cd;for(i=0;i<n;i++)cd.start=n;c=i+1;p=tree[i].parent;while(p!=0){cd.start--;if(tree[p-1].lchild==c){cd.bits[cd.start]='0';}elsecd.bits[cd.start]='1';c=p;p=tree[p-1].parent;}code[i]=cd;}}void decode(codetype code[],huftree tree[])//依次读入电文,根据哈夫曼树译码{int i,b;int flag=-1;i=m-1;printf("请输入电文编码:");scanf("%d",&b);while(b!=flag){if(b==0){i=tree[i].lchild-1;}elsei=tree[i].rchild-1;if(tree[i].lchild==0)//找到叶节点,输出对应字符{printf("译码后对应的字符:%c\n",tree[i].ch);printf("译码后字符对应的权值:%f",tree[i].weight);i=m-1;}scanf("%d",&b);}if(tree[i].lchild!=0)printf("\n error\n"); }void main(){hufman( tree);creathufcode( code);decode( code, tree);}。

哈夫曼编码与译码完整版

哈夫曼编码与译码完整版

《数据结构》哈夫曼编码与译码实验报告题目:哈夫曼编码与译码班级:xxxx学号:xxxxxxxxxxx姓名:xxx完成时间:2012年12月19日一、程序总体结构主程序main显示系统时间showtime() 给用户提供选择方式chioce1()显示界面告诉用户程序名称show()打开文件进行加密openfile()退出程序输入电文进行加密input()将输入(文件中)的电文进行哈夫曼编码CrtHuffmanCode(ht,hc,n)统计输入(文件中)字母的出现频率CrW(data,w,count)【fcount(alldata,data,count)】输出每一个字母所对应的哈夫曼编码Printf(hc,n,data,alldata,count)将输入(文件中)的电文创建成哈夫曼树CrtHuffmantree(ht,w,n)对输入(文件中)的文字进行哈夫曼加密showall(hc,alldata,count,data,n)下面有几个不同的程序供选着参考:程序源代码:#include <iostream.h>#include <fstream.h>#include <string.h>#include <stdlib.h>typedef struct{char data;int weight;int parent,lchild,rchild;}HTNode,*HuffmanTree;typedef char * * HuffmanCode;void Select(HuffmanTree &HT,int n,int m){HuffmanTree p=HT;int tmp;for(int j=n+1;j<=m;j++){int tag1,tag2,s1,s2;tag1=tag2=32767;for(int x=1;x<=j-1;x++){ if(p[x].parent==0&&p[x].weight<tag1){ tag1=p[x].weight;s1=x;}}for(int y=1;y<=j-1;y++){ if(p[y].parent==0&&y!=s1&&p[y].weight<tag2){ tag2=p[y].weight;s2=y;}}if(s1>s2) //将选出的两个节点中的序号较小的始终赋给s1 { tmp=s1; s1=s2; s2=tmp;}p[s1].parent=j;p[s2].parent=j;p[j].lchild=s1;p[j].rchild=s2;p[j].weight=p[s1].weight+p[s2].weight;}}void HuffmanCoding(HuffmanTree &HT,int n,char *w1,int*w2) {int m=2*n-1;if(n<=1) return;HT=(HuffmanTree)malloc((m+1)*sizeof(HTNode)); HuffmanTree p=HT;for(int i=1;i<=n;i++){ p[i].data=w1[i-1];p[i].weight=w2[i];p[i].parent=p[i].lchild=p[i].rchild=0;}for(;i<=m;i++){ p[i].weight=p[i].parent=p[i].lchild=p[i].rchild=0; }Select(HT,n,m);ofstream outfile; //生成hfmTree文件outfile.open("hfmTree.txt",ios::out);for (i=1;i<=m;i++){outfile<<HT[i].weight<<"\t"<<HT[i].parent<<"\t"<<HT[i].lchild<<"\t"<<HT[i].rchil d<<"\t"<<endl;}outfile.close();cout<<"初始化结果已保存在hfmTree文件中\n";}void ToBeTree() //将正文写入文件ToBeTree中{ofstream outfile;outfile.open("ToBeTree.txt",ios::out);outfile<<"THIS PROGRAM IS MYFAVORITE";outfile.close();}void Encoding(HuffmanTree &HT,int n) //编码{HuffmanCode HC;HC=(HuffmanCode)malloc((n+1)*sizeof(char *));char *cd;cd=(char *)malloc(n*sizeof(char));cd[n-1]='\0';for(int k=1;k<=n;k++){ int start=n-1;for(int c=k,f=HT[k].parent;f!=0;c=f,f=HT[f].parent){ if(HT[f].lchild==c) cd[--start]='0';else cd[--start]='1';}HC[k]=(char *)malloc((n-start)*sizeof(char));strcpy(HC[k],&cd[start]);}cout<<"输出哈夫曼编码:"<<endl;for(int h=1;h<=n;h++) //输出编码{ cout<<HT[h].data<<":";cout<<HC[h];cout<<" ";if (h%8==0) cout<<endl;}cout<<endl<<"输出正文编码:"<<endl;ToBeTree();//读取TOBETREE文件里的正文,并进行编码fstream infile;infile.open("ToBeTree.txt",ios::in);char s[80];while(!infile.eof()){infile.getline(s,sizeof(s));}infile.close();fstream outfile;outfile.open("CodeFile.txt",ios::out);int count=0;for (h=0;s[h]!='\0';h++){ for(k=1;k<=n;k++)if (s[h]==HT[k].data){ cout<<HC[k];cout<<" ";count++;outfile<<HC[k];break;}if (count%9==0) cout<<endl; //每输出7个换行}outfile.close();cout<<"\n编码结果已保存在文件CodeFile中."; cout<<endl;}void Decoding(HuffmanTree &HT,int n) //译码{int f=2*n-1;fstream infile;infile.open("CodeFile.txt",ios::in);char s[1000];while(!infile.eof()){infile.getline(s,sizeof(s));}infile.close();int i=0;int j=0;fstream outfile;outfile.open("TextFile.txt",ios::out);while(s[i]!='\0')while(HT[f].lchild!=0)//以f对应的节点的左孩子的值==0作为结束{if (s[j]=='0') f=HT[f].lchild;else f=HT[f].rchild;j++;}i=j;cout<<HT[f].data;outfile<<HT[f].data;}outfile.close();cout<<"\n译码结果已保存在文件TextFile中.";cout<<endl;}void Print() //印代码文件{ int count=0;fstream infile;infile.open("CodeFile.txt",ios::in);char s[1000];while(!infile.eof()){infile.getline(s,sizeof(s));for(int i=0;s[i]!='\0';i++){ cout<<s[i];count++;if (count%50==0) cout<<endl; //在终端上每行显示50个代码}}infile.close();cout<<endl;}char menu() //菜单函数{ cout<<"功能菜单如下:"<<endl;cout<<"* * * * * * * * * * * * * * * * * * * * *"<<endl;cout<<" I:初始化(Initialization) "<<endl;cout<<" E:编码(Encoding) "<<endl;cout<<" D:译码(Decoding) "<<endl;cout<<" P:印代码文件(Print) "<<endl;cout<<" Q:退出(Exit) "<<endl;cout<<"* * * * * * * * * * * * * * * * * * * * *"<<endl;cout<<"请输入功能字符:";char ch;cin>>ch;return ch;}{ int n;int Array[100];char cArray[100];HuffmanTree HT;cout<<"输入n个字符:";cin.getline(cArray,100);n=strlen(cArray);cout<<"一共"<<n<<"个字符.\n";cout<<"依次输入各个字符的权值:"<<endl;for (int i=1;i<=n;i++) cin>>Array[i];int tag;char x=menu();while(1){ switch (x){case 'I':HuffmanCoding(HT,n,cArray,Array);break; case 'E':Encoding(HT,n);break;case 'D':Decoding(HT,n);break;case 'P':Print();break;case 'Q':tag=0;cout<<"结束"<<endl;break; default:cout<<"你输入错误!"<<endl;}if(tag==0) break;cout<<"y(继续) or n(退出)"<<endl;char ch;cin>>ch;if (ch=='y'){ cout<<"请输入功能字符:";char c;cin>>c;x=c;}else exit(1);}}源程序:#include<iostream>#include<fstream>#include<iomanip>#include<vector>using namespace std;typedef struct //节点结构{char data; //记录字符值long int weight; //记录字符权重unsigned int parent,lchild,rchild;}HTNode,*HuffmanTree; //动态分配数组存储哈夫曼树typedef char * *HuffmanCode; //动态分配数组存储哈夫曼编码表void Select(HuffmanTree &HT,int i,int &s1,int &s2) //在HT[1...t]中选择parent不为0且权值最小的两个结点,其序号分别为s1和s2{s1=0;s2=0;int n1=30000,n2=30000;for(int k=1;k<=i;k++){if(HT[k].parent==0){if(HT[k].weight<n1){n2=n1; n1=HT[k].weight;s2=s1; s1=k;}elseif(HT[k].weight<n2){n2=HT[k].weight;s2=k;}}}}void HuffmanCoding(HuffmanTree &HT,HuffmanCode &HC,int n)//将要编码的字符串存入空树中{ifstream fin1("zifu.txt");ifstream fin2("weight.txt");if(n<=1)return;int m=2*n-1;int i;HT=new HTNode[m+1];char *zifu;int *weight;zifu= new char[n+1];weight=new int[n+1];for(i=1;i<=n;i++)//将待编码的字符放在zifu数组中{char ch;ch=fin1.get();zifu[i]=ch;}for(i=1;i<=n;i++)//将带编码字符对应的权值放在weight数组中{fin2>>weight[i];}for( i=1;i<=n;i++){HT[i].data=zifu[i];HT[i].weight=weight[i];}for(i=n+1;i<=m;i++){HT[i].data='@';}for(i=1;i<=m;i++){HT[i].parent=HT[i].lchild=HT[i].rchild=0;}for(i=n+1;i<=m;++i){int s1,s2;Select(HT,i-1,s1,s2);HT[s1].parent=i; 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*));开辟一个求编码的工作空间char *cd;cd=(char *)malloc(n*sizeof(char));//开辟空间存放权值cd[n-1]='\0';for(i=1;i<=n;i++){int start=n-1;int c,f;for( c=i, f=HT[i].parent;f!=0;c=f,f=HT[f].parent)//从叶子到根逆向求编码{if(HT[f].lchild==c)cd[--start]='0';//若是左孩子编为'0'elsecd[--start]='1';//若是右孩子编为'1'}HC[i]=(char *)malloc((n-start)*sizeof(char)); //为第i个编码分配空间strcpy(HC[i],&cd[start]);}delete []cd; //释放工作空间}void printHuffmanTree(HuffmanTree HT,int n) //显示有n个叶子结点的哈夫曼树的编码表{ ofstream fout("hfmtree.txt"); //将对应字符的的哈弗曼树存入cout<<"NUM"<<" "<<"data"<<" "<<"weight"<<" "<<"parent"<<" "<<"lchild"<<" "<<"rchlid"<<endl;for(int i=1;i<=2*n-1;i++){fout<<HT[i].weight<<setw(3)<<HT[i].parent<<setw(3)<<HT[i].lchild<<setw(3) <<HT[i].rchild<<endl;cout<<i<<setw(5)<<HT[i].data<<setw(3)<<HT[i].weight<<setw(3)<<HT[i].pare nt<<setw(3)<<HT[i].lchild<<setw(3)<<HT[i].rchild<<endl;}}void printHuffmanCoding(HuffmanTree HT,HuffmanCode HC,int n)//输出字符的对应哈弗曼编码并存入code.txt文件{cout<<"Huffman code is:"<<endl;ofstream fout("code.txt");for(int i=1;i<=n;i++){cout<<HT[i].data<<" --> ";cout<<(HC[i])<<endl;fout<<(HC[i])<<endl;}}void code_file(HuffmanTree HT,HuffmanCode HC,int n)//对文件tobetran.txt进行编码,并将编码存入codefile文件中{ifstream fin("tobetran.txt");ofstream fout("codefile.txt");vector<char> a;char ch;while((ch=fin.get())!='*')a.push_back(ch);cout<<"待编码的字符串为:";for(int k=0;k<a.size();k++)cout<<a[k];cout<<endl;cout<<"\n编码结果:"<<endl;for(int i=0;i<a.size();i++){for(int j=1;j<=n;j++){if(a[i]==HT[j].data){fout<<HC[j];break;}}}fin.close();fout.close();}void Decoding(HuffmanTree HT,HuffmanCode HC,int n)//打开codefile文件并对文件内容进行译码{int const m=2*n-1;ifstream fin("codefile.txt");ofstream fout("textfile.txt");vector<char> a;for(char c;fin>>c;)a.push_back(c);int count=0;for(int k=0;k<a.size();k++){cout<<a[k];count++;if(count%50==0)cout<<endl;}int i=0;int p; //用p来记住m的值cout<<endl;cout<<"\n译码结果:"<<endl;while(i<a.size()){p=m; //从哈弗曼数的根开始遍历while(HT[p].lchild){if(a[i]=='1')p=HT[p].rchild;elsep=HT[p].lchild;i++;}fout<<HT[p].data;cout<<HT[p].data;}}void main(){int n;cout<<"输入权值个数:"; //设置权值数值cin>>n;printf("\n");HuffmanTree HT; //哈夫曼树HTHuffmanCode HC; //哈夫曼编码表HCHuffmanCoding(HT,HC,n); //进行哈夫曼编码printHuffmanCoding(HT,HC,n); //显示编码的字符printf("\n");code_file(HT,HC,n); //显示要编码的字符串,并把编码值显示出来Decoding(HT,HC,n); //译码并显示译码后的字符串printf("\n\n\n");system("pause");}主要程序代码://HuffmanCode1.h#ifndef HUFFMAMCODE_H#define HUFFMAMCODE_H#include<iostream>#include<fstream>using namespace std;struct HuffmanNode //定义哈夫曼树各结点{int weight;int parent;int lchild,rchild;int flag;};class HuffmanCode1 //哈夫曼编码类{public:char Info[100];int Start;char Leaf;};class HuffmanTree1 //建立哈夫曼树类{private:HuffmanNode *Node;public:int f;HuffmanCode1 *hf;HuffmanTree1();~HuffmanTree1();void TranslatedCode();void CodeHuf(HuffmanNode a[],HuffmanCode1 b[],int n);void CreateHfmTree(char Str[],int m[],int n);void TransCode(HuffmanCode1 b[],int n) ;void TranslateArtcle(HuffmanCode1 b[],int n) ;};#endif //HUFFMAMCODE_HHuffmanCode.cpp#include "iostream"#include<stdio.h>#include "math.h"#include "stdlib.h"#include"HuffmanCode1.h"#include<string>using namespace std;#define MAXDA TA 10000 //最长字符串#define MAXSIZE 150 //最多子叶数//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////第一部分功能(W)实现的代码$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$ HuffmanTree1::HuffmanTree1(){ Node=NULL; } //将树结点初始化为空HuffmanTree1::~HuffmanTree1(){ delete[] Node; } //释放结点空间void HuffmanTree1::CreateHfmTree(char Str[],int m[],int n)//建立哈夫曼树{int i,j,m1,m2,x1,x2;HuffmanNode *HfmNode=new HuffmanNode[2*n-1];HuffmanCode1 *HfmCode=new HuffmanCode1[n];for(i=0;i<2*n-1;i++){HfmNode[i].weight=0;HfmNode[i].parent=0;HfmNode[i].flag=0;HfmNode[i].lchild=-1;HfmNode[i].rchild=-1;}for(i=0;i<n;i++){HfmNode[i].weight=m[i];HfmCode[i].Leaf=Str[i];}for(i=0;i<n-1;i++){m1=m2=32767;x1=x2=0;for(j=0;j<n+i;j++){if(HfmNode[j].weight<=m1&&HfmNode[j].flag==0){m2=m1;x2=x1;m1=HfmNode[j].weight;x1=j;}else if(HfmNode[j].weight<=m2&&HfmNode[j].flag==0){m2=HfmNode[j].weight;x2=j;}}HfmNode[x1].parent=n+i;HfmNode[x2].parent=n+i;HfmNode[x1].flag=1;HfmNode[x2].flag=1;HfmNode[n+i].weight=HfmNode[x1].weight+HfmNode[x2].weight;HfmNode[n+i].lchild=x1;HfmNode[n+i].rchild=x2;}CodeHuf(HfmNode,HfmCode,n);TransCode(HfmCode,n);//TranslateArtcle(HfmCode,n);hf=HfmCode; f=n;}void HuffmanTree1::CodeHuf(HuffmanNode a[],HuffmanCode1 b[],int n) //对哈夫曼树进行编码{HuffmanCode1 Hfd;int c,p;for(int i=0;i<n;i++){Hfd.Start=n-1;c=i;p=a[c].parent;while(p!=0){if(a[p].lchild==c)[Hfd.Start]='0';else[Hfd.Start]='1';Hfd.Start--;c=p;p=a[c].parent;}printf("%c :",b[i].Leaf);for(int j=Hfd.Start+1;j<n;j++){b[i].Info[j]=[j];printf("%c",[j]);}printf("\n");b[i].Start=Hfd.Start;}}void HuffmanTree1::TransCode(HuffmanCode1 b[],int n) //对文章进行翻译并保存{ifstream ifs("WData.txt");ofstream ofs("WCode.txt");char s[1000];int t=0;char ch;cout<<"************************************************************** *****************"<<endl;printf("报文的编码为:\n");while(ifs.get(ch)){if(ch!='\n')s[t]=ch;for(int i=0;i<n;i++){if(s[t]==b[i].Leaf)for(int j=b[i].Start+1;j<n;j++){printf("%c",b[i].Info[j]);ofs<<b[i].Info[j];}}t++;}printf("\n");printf("报文的编码已经保存在WCode.txt中\n");cout<<"*********************************************************** ********************"<<endl;}void HuffmanTree1::TranslateArtcle(HuffmanCode1 b[],int n) //将所译的码翻译成文章并保存{int t=0;ifstream ifs("WCode.txt");ofstream ofs("TransWData.txt");string s;getline(ifs,s);for(t=0;s[t]!='\0';t++);int l=0;int j=0;printf("报文的译码结果为:\n");while(l<t){while(j<n){int hu=b[j].Start+1;int k=0;while(hu<n){if(s[l]==b[j].Info[hu]){l++;hu++;k++;}else{break;}}if(hu==n){printf("%c",b[j].Leaf);ofs<<b[j].Leaf;j=0;break;}else{l=l-k;j++; continue;}}}printf("\n");printf("译码的结果已经保存到TransWData.txt中\n");cout<<"*********************************************************** ********************"<<endl;}void HuffmanTree1::TranslatedCode(){ifstream ifs("WData.txt");char str[1000];char Str[100];int i=0,j,m[100],h,k=0;int n=0;cout<<"*********************************************************** ********************"<<endl;printf("文件中提取的文章字符串是:\n");char ch;while(ifs.get(ch)){printf("%c",ch);if(ch!='\n'){str[n++]=ch;}}printf("\n");printf("字符串中共含有字符%d个\n",n);for(i=0;i<n;i++){j=0;h=0;while(str[i]!=str[j])j++;if(j==i){Str[k]=str[i];printf("字符%c出现",Str[k]);}elsecontinue;for(j=i;j<n;j++){if(str[i]==str[j])h++;}printf("%d次\n",h);m[k]=h;k++;}cout<<"*********************************************************** ********************"<<endl;printf("字符串中字符种类有%d种\n",k);cout<<"*********************************************************** ********************"<<endl;printf("每个字符对应的哈夫曼编码是:\n");CreateHfmTree(Str,m,k);cin.get();// printf("\n");}//main.cpp//#include"HuffmanCode1.h"//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////第二部分功能实现的代码$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$ typedef struct //哈弗曼树节点的结构体{char info; //关联字符信息unsigned int weight; //每个节点的权职unsigned int parent, lchild, rchild;}HTNode,*HuffmanTree;typedef char **HuffmanCode; //存储哈弗曼编码void Select(HuffmanTree HT, int j,int &s1,int &s2){ //选择双亲节点为0,并且最小的两个子叶节点int i=1,m;while(HT[i].parent!=0)i++; //找第一个双亲节点为0的子叶结点for(s2=s1=i;i<j;i++){ /保证s1中的权值最小,s2次小if(HT[i].parent==0 && HT[i].weight<HT[s1].weight){s2=s1;s1=i;}else if(HT[i].parent==0 && HT[i].weight>=HT[s1].weight &&HT[i].weight<=HT[s2].weight)s2=i;while(HT[i].parent==0 && s1==s2){m=i;m++;while(HT[m].parent!=0)m++;s2=m;}}}void HuffmanCoding(HuffmanTree &HT, HuffmanCode &HC, int *w, int n, char *info){ //哈弗曼编码int i,m;HuffmanTree p;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,++w,++info){ //初始化所有已存在的子叶信息p->info = *info;p->weight = *w;p->parent = 0;p->lchild = 0;p->rchild = 0;}//forfor(; i<=m;++i,++p){ //构造所需要的过度根节点p->weight = 0;p->parent = 0;p->lchild = 0;p->rchild = 0;}//forfor(i=n+1;i<=m;++i){ //建立哈弗曼树int s1,s2;Select(HT,i-1,s1,s2);HT[s1].parent =i;HT[s2].parent =i;HT[i].lchild = s2;HT[i].rchild = s1;HT[i].weight = HT[s1].weight+HT[s2].weight;}//for//哈弗曼编码HC = (HuffmanCode)malloc((n+1)*sizeof(char *));char* cd = (char*)malloc(n*sizeof(char));cd[n-1] = '\0';for(i=1;i<=n;++i){int f;unsigned int c;int 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';}HC[i]=(char*)malloc((n-start)*sizeof(char));strcpy(HC[i], &cd[start]);}//forfree(cd);}//HuffmanCoding//Y功能实现输出并保存字符串的二进制编码void CheckCoding(HuffmanTree HT, HuffmanCode HC, char *strcheck, int m,int k) { ofstream ofs("BCode.txt"); //查询哈弗曼编码信息int p;for(int i=0; i<m; i++){for(int j=1; HT[j].info != strcheck[i]; j++);cout<<HC[j]; //输出并保存字符串的二进制编码ofs<<HC[j];}cout<<endl;cout<<"字符串的二进制编码已经保存在“BCode.txt”中"<<endl;//cout<<"译码翻译得到的文章已保存在“Data.txt”中"<<endl;cout<<"************************************************************** *****************"<<endl;cout<<"各字符对应的编码为:"<<endl; //输出各字符对应的哈夫曼编码for( p=1;p<=k;p++){cout<<HT[p].info <<": "<<HC[p]<<endl;}}//CheckCoding//对键盘输入的二进制代码进行译码void HuffmanTranslateCoding(HuffmanTree HT, int n,char*c){ ofstream ofs("TransBData.txt"); //译码过程int m=2*n-1;int i,j=0;cout<<"译码翻译得到的文章已保存在“TransBData.txt”中"<<endl;cout<<"译码翻译得到的文章为:";while(c[j]!='\0'){i=m;while(HT[i].lchild && HT[i].rchild){if(c[j]=='0')i=HT[i].lchild;else if(c[j]=='1')i=HT[i].rchild;j++;}cout<<HT[i].info; //翻译成字符串并输出和保存ofs<<HT[i].info;}}//译码过程、、对"BCode.txt"的编码进行译码void HuffmanTranslateCoding2(HuffmanTree HT, int n){ ifstream ifs("BCode.txt");ofstream ofs("TransBData2.txt");string c;int m=2*n-1;int i,j=0;getline(ifs,c);cout<<"译码翻译得到的文章已保存在“TransBData2.txt”中"<<endl;cout<<"译码翻译得到的文章为:";while(c[j]!='\0'){i=m;while(HT[i].lchild && HT[i].rchild){if(c[j]=='0')i=HT[i].lchild;else if(c[j]=='1')i=HT[i].rchild;j++;}cout<<HT[i].info; //翻译成字符串并输出和保存ofs<<HT[i].info;}}void Menushow(){cout<<"||******************************************************************** ****||"<<endl;cout<<" || HuffmanCode and HUffmanTranslate System ||"<<endl;cout<<" || ***********哈夫曼编码/译码系统************* ||"<<endl;cout<<" || *************欢迎使用本系统**************** ||"<<endl;cout<<" || 东北电力大学信息工程学院计机093班兴趣小组||"<<endl;cout<<" || 制作人:范辉强(组长)李哲周兴宇||"<<endl;cout<<"||******************************************************************** ****||"<<endl;cout<<" ||在本系统中您可以进行如下操作:||"<<endl;cout<<" ||第一部分功能:||"<<endl;cout<<" || A :从文件提取字符串,然后对提取的字符串进行编码||"<<endl;cout<<" || B :根据W操作对“WCode.txt”里的二进制编码进行译码||"<<endl;cout<<" ||第二部分功能:||"<<endl;cout<<" || C :对您输入的字符串进行编码||"<<endl;cout<<" || D:对BCode.txt里的编码进行译码||"<<endl;cout<<" || E :对您输入的二进制编码进行译码||"<<endl;cout<<" ||第三部分功能:||"<<endl;cout<<" || F :退出本系统||"<<endl;cout<<"||******************************************************************** ****||"<<endl;cout<<" ||温馨提示:||"<<endl;cout<<" || 执行A,请将您的数据存储在同目录下名为“WData”文本文档里||"<<endl;cout<<" || 在执行C操作时务必在您输入的字符串后加上“#”||"<<endl;cout<<" || B与A是对应的B在A后运行||"<<endl;cout<<" || D/E与C是对应的,即B/C是根据C来进行译码的||"<<endl;cout<<" || 译码D/E应在编码C后才能进行||"<<endl;cout<<" ||*********************** Copyright by FanFan ********************||"<<endl;}//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ///main().cppint main(){int n=0,i=0,k=0,j,h,*w;FILE *fp;char ch2,str[MAXDA TA],choose,name[]="BData.txt";w=new int[MAXSIZE];char *info;char *strcheck=str;info=new char[MAXSIZE];char *ch=new char[MAXSIZE];HuffmanTree HT=new HTNode[MAXSIZE];HuffmanCode HC=NULL;HuffmanTree1 HuffmanNode;Menushow();while(1){cout<<endl;cout<<"************************************************************** *****************"<<endl;cout<<"*********************************************************** ********************"<<endl;cout<<"请输入您要进行的操作(W/F/B/C/Y/T)(不区分大小写):"<<endl;cin>>choose;cout<<"************************************************************** *****************"<<endl;switch(choose){case 'A':case 'a':HuffmanNode.TranslatedCode();break;case 'B':case 'b':HuffmanNode.TranslateArtcle(HuffmanNode.hf,HuffmanNode.f);case 'D':case 'd':HuffmanTranslateCoding2( HT,n);break;case 'E':case 'e'://进行译码操作cout<<"请您输入您要编译的二进制编码: "<<endl;cin>>ch;HuffmanTranslateCoding(HT,n,ch);break;case 'T':case 't'://退出系统return 0;case 'C':case 'c'://进行编码操作cout<<"请输入您要编码的字符串:"<<endl;//从键盘输入字符串存放在字符数组str[1000]中/*if ((fp=fopen(name,"w"))==NULL){cout<<"cannot open file"<<endl;exit(0);}*/fp=fopen(name,"w");ch2=getchar();//接收上一次键盘输入的换行符ch2=getchar();while(ch2!='#'){fputc(ch2,fp);str[n++]=ch2;putchar(str[n-1]);ch2=getchar();}putchar(10);fclose(fp);cout<<endl;cout<<"输入的数据已经保存在“BData.txt”中"<<endl;cout<<"*******************************************************************************"<<endl;cout<<"字符串中共含有字符"<<n<<"个"<<endl;cout<<"*********************************************************** ********************"<<endl;for(i=0;i<n;i++) // 统计从键盘输入的字符串的信息{j=0;h=0;while(str[i]!=str[j])j++;if(j==i){info[k]=str[i];cout<<"字符"<<info[k]<<"出现";}elsecontinue;for(j=i;j<n;j++){if(str[i]==str[j])h++;}cout<<h<<"次"<<endl;w[k]=h;k++;}cout<<"************************************************************** *****************"<<endl;cout<<"字符串中字符种类有"<<k<<"种"<<endl;cout<<"************************************************************** *****************"<<endl;HuffmanCoding( HT, HC, w, n,info);//对输入的字符串进行编码*strcheck=str[0];cout<<"您输入的字符串编码为:"<<endl;CheckCoding(HT,HC,strcheck,n,k);break;default:cout<<"对不起,您的输入不正确!请重新输入"<<endl;}//switch}//while}//main程序清单.cpp#include<iostream>#include<stdio.h>#include<stdlib.h>#include<string>#include"Hh1.h"using namespace std;FILE * f1=fopen("d:\\pra1.txt","r");FILE * f2=fopen("d:\\pra2.txt","w");FILE * f3=fopen("d:\\pra4.huf","w");int main(){init(SN); //初始化字符数据库// input(f1); //读入初始文件的字符//for(int i=0;forest[i]!=NULL;i++)cout<<forest[i]->c<<":"<<forest[i]->weight<<endl; //输出字符及出现次数// cout<<"出现字符种类"<<count<<endl; //输出字符种类//HFM huffman(count); //创建哈夫曼树实例// huffman.creat(); //创建哈夫曼树// count=0;huffman.hufcode(); //哈夫曼编码,此时为逆向//exchange(); //调整首尾对调哈夫曼编码// huffman.savewithhufcode(f1,f2); //用哈夫曼编码存储原文件//cout<<endl;cout<<"1.查看哈夫曼编码"<<endl;cout<<"2.哈夫曼解码"<<endl;cout<<"3.查看压缩率"<<endl;int choice;cin>>choice;while(choice>=1&&choice<=3){switch(choice){case 1:{for(i=0;hufNode[i].sig!=NULL;i++){cout<<"字符"<<hufNode[i].sig->c<<"的哈夫曼编码:"; //输出哈夫曼编码//for(int j=0;j<hufNode[i].size;j++)cout<<hufNode[i].code[j];cout<<endl;}cout<<"最大列数:"<<huffman.maxc()<<endl;break;}case 2:{fclose(f2);f2=fopen("d:\\pra2.txt","r");huffman.hufdecode(f2,f3); //哈夫曼解码//cout<<endl;break;}case 3:{compress(); //查看压缩情况//cout<<endl;}}cout<<"1.查看哈夫曼编码"<<endl;cout<<"2.哈夫曼解码"<<endl;cout<<"3.查看压缩率"<<endl;cin>>choice;}cout<<"*谢谢使用*"<<endl; //退出操作//return 0;}.h#include<iostream>using namespace std;struct signode{ //signode节点,哈夫曼树节点//char c; //字符//int weight; //权重//bool b; //文章中是否出现//。

哈夫曼编码和译码

哈夫曼编码和译码

哈夫曼编码和译码哈夫曼编码和译码是一种常用的数据压缩算法,它通过将出现频率较高的字符用较短的编码表示,从而减小数据的存储空间。

本文将介绍哈夫曼编码和译码的原理和应用。

哈夫曼编码是由美国数学家大卫·哈夫曼于1952年提出的一种编码方法。

它的基本思想是根据字符出现的频率来构建一棵二叉树,出现频率较高的字符位于树的较低层,而出现频率较低的字符位于树的较高层。

通过这种方式,出现频率较高的字符可以用较短的编码表示,而出现频率较低的字符则用较长的编码表示。

具体来说,哈夫曼编码的过程如下:首先,统计待编码的字符出现的频率,并根据频率构建一个字符频率表。

然后,根据字符频率表构建哈夫曼树,其中每个字符对应一个叶子节点,而非叶子节点的权值为其子节点权值之和。

接下来,通过遍历哈夫曼树,给每个字符赋予对应的编码,其中左子树路径上的编码为0,右子树路径上的编码为1。

最后,将编码后的字符序列存储起来,即完成了哈夫曼编码的过程。

哈夫曼译码是哈夫曼编码的逆过程,它通过已知的哈夫曼编码和字符频率表来将编码还原为原始的字符序列。

具体来说,哈夫曼译码的过程如下:首先,根据已知的字符频率表构建哈夫曼树。

然后,从根节点开始,根据编码的0和1进行遍历,直到叶子节点。

每次遍历到叶子节点时,将对应的字符输出,并重新回到根节点,继续下一次遍历,直到所有的编码都被译码为字符。

哈夫曼编码和译码在数据压缩领域有着广泛的应用。

由于哈夫曼编码可以将出现频率较高的字符用较短的编码表示,从而减小了数据的存储空间。

在传输大量文本、图像、音频等数据时,可以使用哈夫曼编码将数据进行压缩,从而减少传输的时间和带宽消耗。

而哈夫曼译码则可以将压缩后的数据还原为原始的数据,保证了数据的完整性和准确性。

除了数据压缩,哈夫曼编码和译码还有其他的应用。

在通信领域,哈夫曼编码可以用于错误检测和纠正,通过添加冗余信息来检测和纠正传输过程中的错误。

在图像和音频处理领域,哈夫曼编码可以用于图像和音频的压缩和解压缩,从而减小存储空间和提高传输效率。

哈夫曼树的编码和解码

哈夫曼树的编码和解码

哈夫曼树的编码和解码是哈夫曼编码算法的重要部分,下面简要介绍其步骤:
1. 编码:
哈夫曼编码是一种变长编码方式,对于出现频率高的字符使用较短的编码,而对于出现频率低的字符使用较长的编码。

具体步骤如下:(1)根据字符出现的频率,构建哈夫曼树。

频率相同的字符,按照它们在文件中的出现顺序排列。

(2)从哈夫曼树的叶子节点开始,从下往上逐步进行编码。

对于每个节点,如果该节点有左孩子,那么左孩子的字符编码为0,右孩子的字符编码为1。

如果该节点是叶子节点,则该节点的字符就是它的编码。

(3)对于哈夫曼树中的每个节点,都记录下它的左孩子和右孩子的位置,以便后续的解码操作。

2. 解码:
解码过程与编码过程相反,具体步骤如下:
(1)从哈夫曼树的根节点开始,沿着路径向下遍历树,直到找到一个终止节点(叶节点)。

(2)根据终止节点的位置信息,找到对应的字符。

(3)重复上述步骤,直到遍历完整个编码序列。

需要注意的是,哈夫曼编码是一种无损压缩算法,解压缩后的数据与原始数据完全相同。

此外,由于哈夫曼编码是一种变长编码方式,因此在解码时需要从根节点开始逐个解码,直到解码完成。

哈夫曼编码与解码

哈夫曼编码与解码

哈夫曼编码与解码
哈夫曼编码(Huffman coding)和哈夫曼解码(Huffman decoding)是一种用于数据压缩的技术,由美国计算机科学家 David A. Huffman 于 1952 年提出。

哈夫曼编码的基本思想是根据字符在文本中出现的频率来分配二进制编码的长度。

出现频率较高的字符将被分配较短的编码,而出现频率较低的字符将被分配较长的编码。

这样,通过使用较短的编码来表示常见字符,可以实现更有效的数据压缩。

哈夫曼编码的过程包括以下步骤:
1. 统计字符出现频率:对要编码的文本进行分析,统计每个字符出现的次数。

2. 构建哈夫曼树:根据字符出现频率构建一棵二叉树,其中频率较高的字符靠近树的根节点,频率较低的字符位于树的叶子节点。

3. 分配编码:从根节点开始,根据字符出现频率为每个字符分配二进制编码。

左子节点表示 0,右子节点表示 1。

4. 编码文本:将文本中的每个字符替换为其对应的哈夫曼编码。

哈夫曼解码是哈夫曼编码的逆过程,用于将已编码的数据还原为原始文本。

解码过程根据哈夫曼树的结构和编码规则,从编码中解析出原始字符。

哈夫曼编码与解码在数据压缩领域具有广泛的应用,例如图像、音频和视频压缩。

它通过有效地利用字符频率分布的不均匀性,实现了较高的压缩率,从而减少了数据传输和存储的开销。

需要注意的是,哈夫曼编码是一种无损压缩技术,意味着解码后可以完全还原原始数据。

但在实际应用中,可能会结合其他有损压缩技术来进一步提高压缩效果。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

#include"stdafx.h"#include"stdio.h"#include"conio.h"#include<iostream>#include<string>#include<fstream>using namespace std;#define maxbit 100#define Maxvalue 2000//最大权值整数常量#define Maxleaf 100//最大叶子结点数#define size 300//0、串数组的长度static int n;//实际的叶子结点数struct HNodeType{int weight;int parent;int lchild;int rchild;int ceng;//结点相应的层数char ch;//各结点对应的字符};struct HCodeType{int bit[maxbit];//存放编码的数组int start;//编码在数组中的开始位置};static HNodeType *HuffNode;//定义静态指针HNodeType *init()//初始化静态链表{HuffNode=new HNodeType[2*n-1];for(int i=0;i<2*n-1;i++){HuffNode[i].weight=0;HuffNode[i].parent=-1;HuffNode[i].lchild=-1;HuffNode[i].rchild=-1;HuffNode[i].ceng=-1;HuffNode[i].ch='0';}return HuffNode;}void HaffmanTree()//建立哈夫曼树{int i,j;int m1,m2,x1,x2;cout<<"请输入叶子结点对应的权值"<<endl;for(i=0;i<n;i++){cin>>HuffNode[i].weight;}flushall();//清除缓存cout<<"请输入叶子结点对应的字符"<<endl;for(i=0;i<n;i++){cin.get(HuffNode[i].ch);}for(i=0;i<n-1;i++){m1=m2=Maxvalue;x1=x2=0;for(j=0;j<n+i;j++){if(HuffNode[j].parent==-1&&HuffNode[j].weight<m1)//找最小值{m2=m1;x2=x1;m1=HuffNode[j].weight;x1=j;}elseif(HuffNode[j].parent==-1&&HuffNode[j].weight<m2)//找次小值{m2=HuffNode[j].weight;x2=j;}}HuffNode[x1].parent=n+i;//在相应的位置重新赋值HuffNode[x2].parent=n+i;HuffNode[n+i].weight=HuffNode[x1].weight+HuffNode[x2].weight;HuffNode[n+i].lchild=x1;HuffNode[n+i].rchild=x2;HuffNode[x1].ceng=n-i;HuffNode[x2].ceng=n-i;HuffNode[n+i].ceng=n-i-1;}ofstream outfile("hfmtree.dat",ios::out|ios::binary);//建立文件存入哈夫曼树if(!outfile)cerr<<"open file error!"<<endl;for(i=0;i<2*n-1;i++)outfile.write((char*)(&HuffNode[i]),sizeof(HuffNode[i]));outfile.close();}void HaffmanCode()//哈夫曼编码{int i,j,k,m,c,p,flag=0;HCodeType HuffCode[Maxleaf],cd;ifstream infile("hfmtree.dat",ios::in|ios::binary);//打开文件读取数据if(!infile)cerr<<"open file error!"<<endl;for( i=0;i<2*n-1;i++){infile.read((char*)(&HuffNode[i]),sizeof(HuffNode[i]));}infile.close();for(i=0;i<n;i++)//编码过程{cd.start=n-1;c=i;p=HuffNode[c].parent;while(p!=-1){if(HuffNode[p].lchild==c)cd.bit[cd.start]=0;elsecd.bit[cd.start]=1;cd.start--;c=p;p=HuffNode[c].parent;}for(j=cd.start+1;j<n;j++)HuffCode[i].bit[j]=cd.bit[j];HuffCode[i].start=cd.start;}cout<<"叶子结点所对应的字符及编码(形如:A--100):"<<endl;for(i=0;i<n;i++){cout<<HuffNode[i].ch<<"--";for(j=HuffCode[i].start+1;j<n;j++)cout<<HuffCode[i].bit[j];cout<<endl;}ofstream outfile("codefile.dat",ios::out|ios::binary);//存取字符串的编码结果if(!outfile)cerr<<"open file error!"<<endl;cout<<"请输入需要编码的字符串:"<<endl;flushall();string s;getline(cin,s);for(k=0;k<=s.length();k++)//进行字符匹配,输出对应的、串{for(j=0;j<n;j++){if(HuffNode[j].ch==s[k])for(m=HuffCode[j].start+1;m<n;m++){flag=1;outfile.write((char*)(&HuffCode[j].bit[m]),sizeof(HuffCode[j].bit[m]));cout<<HuffCode[j].bit[m];}}if(j==n&&flag==0)cout<<"该字符不存在,无法进行编码!";cout<<" ";}outfile.close();cout<<endl;}void Haffmantran()//哈夫曼译码{int i,j,top=-1,m,p;char c[size];cout<<"请输入需要编译的0和1代码串(以字符‘s'作为结束标志):"<<endl;do//输入并存取需要编译的代码串{top++;cin>>c[top];while(c[top]!='0'&&c[top]!='1'&&c[top]!='s'){cout<<"输入错误!只能输入'0','1','s'三个字符!"<<endl;cin>>c[top];}}while(c[top]!='s');m=2*n-2;i=0;cout<<"译码结果如下:"<<endl;for(j=0;j<top;j++)cout<<c[j];cout<<"--";ofstream outfile("textfile.dat",ios::out|ios::binary);//建立文件存取译码结果if(!outfile)cerr<<"open file error!"<<endl;while(i!=top){while(HuffNode[m].lchild!=-1&&HuffNode[m].rchild!=-1){if(c[i]=='0')p=HuffNode[m].lchild;elseif(c[i]=='1')p=HuffNode[m].rchild;m=p;i++;if(HuffNode[m].lchild!=-1&&HuffNode[m].rchild!=-1&&i==top){cout<<"根据编码规则只能部分译码,无法完整译码!"<<endl;break;}}if(HuffNode[m].lchild==-1&&HuffNode[m].rchild==-1){cout<<HuffNode[m].ch;outfile.write((char*)(&HuffNode[m].ch),sizeof(HuffNode[m].ch));//将译码结果存入文件}m=2*n-2;}cout<<endl;outfile.close();}void Haffmanprint()//以凹入图的形式输出哈夫曼树{int i,j,k;fstream infile,outfile;//读取哈弗曼树infile.open ("hfmTree.dat",ios::in|ios::binary);if(!infile)cout<<"hfmTree.txt文件不能打开"<<endl;for( i=0;infile.peek() != EOF;i++) //将文件中的数据读到相应的数组内{infile.read ((char*)&HuffNode[i],sizeof(HuffNode[i]));}infile.close ();//关闭文件cout<<"输出哈弗曼树的凹入图(重组的结点只有权值没有字符)"<<endl;for(i=0;i<n;i++)for(j=0;j<2*n-1;j++)//按层次查找遍历{if(HuffNode[j].ceng==i+1){for(k=0;k<HuffNode[j].ceng;k++){cout<<" ";}for(k=0;k<60-HuffNode[j].ceng-i;k++){cout<<"*";}cout<<"("<<HuffNode[j].weight<<")";if(j<n)cout<<HuffNode[j].ch;cout<<endl;}}}void showmain(){cout<<"********************主菜单********************"<<endl;cout<<"**************0.选择退出该程序**************"<<endl;cout<<"**************1.实现哈夫曼编码**************"<<endl;cout<<"**************2.实现哈夫曼译码**************"<<endl;cout<<"**************3.要打印哈夫曼树**************"<<endl;}int _tmain(int argc, _TCHAR* argv[]){char c;cout<<"********************开始建立哈夫曼树!********************"<<endl;cout<<"请输入叶子结点的个数(最大为):"<<endl;cin>>n;while(n>100){cout<<"请重新输入叶子结点的个数(最大为):"<<endl;cin>>n;}HuffNode=init();HaffmanTree();showmain();do{c=getche();cout<<endl;if(c=='1')HaffmanCode();elseif(c=='2')Haffmantran();elseif(c=='3')Haffmanprint();elseif(c=='0')break;showmain();}while(c!='0');return 0;}。

相关文档
最新文档