哈夫曼树的编码与译码
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 }哈夫曼编码译码五.运⾏截图:。
数据结构哈夫曼树编码及译码的实现实验报告

实验:哈夫曼树编码及译码的实现一.实验题目给定字符集的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)初始化哈夫曼树的 )初始化哈夫曼树的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,则向右子节点移动,直到到达叶子节点。
找到叶子节点后,将对应的字符输出,并回到根节点,继续下一位的译码,直到编码字符串结束。
哈夫曼编码可以实现无损压缩,即通过译码过程能够还原出原始数据,而不会丢失任何信息。
它是一种广泛应用于数据压缩领域的有效方法,用于减小数据存储和传输的大小。
在实际应用中,哈夫曼编码被广泛应用于图像、音频和视频等多媒体数据的压缩中。
总结起来,哈夫曼编码是一种用于数据压缩的编码方法,通过根据字符出现的频率对字符进行编码,以便用较少的位数来表示出现频率较高的字符。
哈夫曼译码则是将经过编码后的数据解码成原始数据的过程。
它通过构建哈夫曼树和编码表,实现了高效的数据压缩和解压缩。
哈夫曼编码被广泛应用于数据存储和传输领域,特别是在多媒体数据的压缩中。
哈弗曼树编码译码

for (k=hcd[j].start;k<=n;k++)
{
printf("%c",hcd[j].cd[k]);
}
break; //输出完成后跳出当前for循环
}
(5)显示部分源程序:
{
printf("\n");
printf(" ********************************");
printf("\n ** 1---------------显示编码 **");
printf("\n ** 2---------------进行编码 **");
{
int i,k;
printf(" 输出哈夫曼编码:\n");
for (i=0;i<n;i++) //输出data中的所有数据,即A-Z
{
printf(" %c:\t",ht[i].data);
}
}
}
(3)哈弗曼译码
void deHCode(HTNode ht[],HCode hcd[],int n) //译码函数
{
char code[MAXSIZE];
int i,j,l,k,m,x;
scanf("%s",code); //把要进行译码的字符串存入code数组中
printf("\n");
printf(" 请输入选择的编号:");
scanf("%c",&orz);
哈夫曼树的编码与译码

#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、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
目录一、摘要 (3)二、题目 (3)三、实验目的 (3)四、实验原理 (3)五、需求分析 (4)5.1实验要求 (4)5.2实验内容 (4)六、概要设计 (4)6.1所实现的功能函数 (4)6.2主函数 (5)6.3 系统结构图 (6)七、详细设计和编码 (6)八、运行结果 (12)九、总结 (15)9.1调试分析 (15)9.2 心得体会 (15)参考文献 (16)一、摘要二、题目哈夫曼树的编码与译码三、实验目的(1)熟悉对哈夫曼的应用以及构造方法,熟悉对树的构造方式的应用;(2)进一步掌握哈夫曼树的含义;(3)掌握哈夫曼树的结构特征,以及各种存储结构的特点以及使用范围;(4)熟练掌握哈夫曼树的建立和哈夫曼编码方法;(5)提高分析问题、解决问题的能力,进一步巩固数据结构各种原理与方法;(6)掌握一种计算机语言,可以进行数据算法的设计。
四、实验原理哈夫曼(Huffman)编码属于长度可变的编码类,是哈夫曼在1952年提出的一种编码方法,即从下到上的编码方法。
同其他码词长度一样,可区别的不同码词的生成是基于不同符号出现的不同概率。
生成哈夫曼编码算法基于一种称为“编码树”(coding tree)的技术。
算法步骤如下:(1)初始化,根据富豪概率的大小按由大到小顺序对符号进行排序;(2)把概率最小的两个符号组成一个新符号(节点),即新符号的概率等于这两个符号概率之和;(3)重复第(2)步,直到形成一个符号为止(树),其概率最后等于1;(4)从编码树的根开始回溯到原始的符号,并将每一下分支赋值1,上分支赋值0;译码的过程是分解电文中字符串,从根出发,按字符“0”或者“1”确定找做孩子或右孩子,直至叶子节点,便求得该子串相应的字符。
五、需求分析5.1实验要求(1)从终端读入字符集大小n,以及n个字符和n个权值,建立哈夫曼树的存储结构;(2)利用已经建好的哈夫曼树,对给定的n个字符正文进行编码,并输出结果。
(3)利用已建好的哈夫曼树,对给定的一个哈夫曼编码进行译码,判断此编码对应的字符,并输出结果。
5.2实验内容(1)定义哈夫曼树结构;(2)初始化哈夫曼树,存储哈夫曼树信息;(3)定义哈夫曼编码的函数;(4)定义哈夫曼译码的函数;(5)写出主函数;(6)测试系统;(7)运行程序。
六、概要设计6.1所实现的功能函数void initHuffmanTree();//初始化哈夫曼树int inputInit();//进行哈夫曼树的初始化int HuffmanCoding(int *w); //初始化哈夫曼数,按照哈夫曼规则建立二叉树。
此函数块调用了Select()函数。
void Select(int j,int &s1,int &s2); //选择parent为0,且weight最小的两个节点序号为s1,s2void encoding();//哈夫曼编码void inputEnco();//进行哈夫曼编码void decode();//哈夫曼译码void inputDeco();//进行哈夫曼译码6.2主函数int main(){int sel=0;cout<<"Xin Yun"<<endl;cout<<"Information Safety of 2"<<endl;cout<<"Welcome to use the coding and decode of Huffman!"<<endl;for(;;){cout<<"\t*\t"<<"1.init"<<endl;cout<<"\t*\t"<<"2.coding"<<endl;cout<<"\t*\t"<<"3.decode"<<endl;cout<<"\t*\t"<<"4.quit"<<endl;cout<<"Please input your choice(1-4)."<<endl<<" ";cin>>sel;if(sel==4) break;switch(sel){case 1:initHuffmanTree();break;case 2:encoding();break;case 3:decode();break;default:cout<<"Sorry!The number you have input is wrong!"<<endl;}}outstuf.close();cout<<"Thank you to use it!!!"<<endl;return 0;}解析:挑选需要实现的功能(1)当输入“1”时,调用initHuffmanTree()函数,进行哈夫曼树的初始化;(2)当输入“2”时,调用encoding()函数,进行哈夫曼树的编码;(3)当输入“3”时,调用decode()函数,进行哈夫曼树的译码;(4)当输入“4”时,退出程序;6.3 系统结构图七、详细设计和编码#include<iostream>#include<fstream>#include<cstring>using namespace std;ofstream outstuf;typedef struct{unsigned int weight;unsigned int parent,lchild,rchild; }HTNode,*HuffmanTree;typedef char** HuffmanCode;HuffmanTree HT=NULL;int n=0;HuffmanCode HC=NULL;char *ch=NULL;void initHuffmanTree();int inputInit();int HuffmanCoding(int *w);void Select(int j,int &s1,int &s2);void encoding();void inputEnco();void decode();void inputDeco();void initHuffmanTree(){inputInit();}int inputInit(){cout<<"Please input the number of the character(n).\t";cin>>n;int *w=(int *)malloc((n+1)*sizeof(int));if(!w) {cout<<"ERROR";return 0;}ch=(char *)malloc((n+1)*sizeof(char));if(!ch) {cout<<"ERROR";return 0;}cout<<" Please input the characters.\t";for(int i=1;i<=n;i++) cin>>ch[i];cout<<"Please input the numbers.\t";for(i=1;i<=n;i++) cin>>w[i];outstuf.open("hfmTree.txt",ios::out);for(i=1;i<=n;i++){outstuf<<ch[i]; outstuf<<w[i];};cout<<endl;HuffmanCoding(w);cout<<"The coding of every character is:";for(i=1;i<=n;i++) {cout<<" "<<ch[i]<<'\t';cout<<HC[i];} ;outstuf.close();outstuf.open("code.txt",ios::out);for(i=1;i<=n;i++){outstuf<<ch[i]; outstuf<<HC[i];};cout<<endl;outstuf.close();return 0;}int HuffmanCoding(int *w){if(n<=1) return 1;int m=2*n-1;HT=(HuffmanTree)malloc((m+1)*sizeof(HTNode));if(!HT) {cout<<"ERROR";return 0;}for(int i=1; i<=n; ++i){HT[i].weight=w[i];HT[i].parent=HT[i].lchild=HT[i].rchild=0;}for(;i<=m; ++i) HT[i].weight=HT[i].parent=HT[i].lchild=HT[i].rchild=0;int s1=0;int s2=0;for(i=n+1;i<=m; ++i){Select(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=(char*) malloc(n*sizeof(char));if(!cd) {cout<<"ERROR";return 0;}cd[n-1]='\0';int start;for(i=1;i<=n;++i){start=n-1;for(int c=i,unsigned int 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]);}free(cd);return 0;}void Select(int j,int &s1,int &s2){for(int h=1;h<=j;h++)if(HT[h].parent==0) {s1=h;break;}h++;for(;h<=j;h++)if(HT[h].parent==0) {s2=h;break;}int m;if(HT[s1].weight>HT[s2].weight) {m=s1;s1=s2;s2=m;}h++;for(;h<=j;h++)if(HT[s1].weight>HT[h].weight&&HT[h].parent==0) s1=h;for(m=1;m<=j;m++)if(HT[s2].weight>HT[m].weight&&m!=s1&&HT[m].parent==0) s2=m;}void encoding(){inputEnco();}void inputEnco(){cout<<"Please input the sentence that you want to coding.(Please end of the character of '$')"<<endl;char *file=(char *)malloc(200*sizeof(char));for(int i=1;i<200;i++){cin>>file[i];if(file[i]=='$') break;}if(i==200) {file=(char *)realloc(file,(200+80)*sizeof(char));for(;i<280;i++){cin>>file[i];if(file[i]=='$') break;}}int m=i;cout<<"The result of the coding is:"<<endl;outstuf.open("CodeFile.txt",ios::out);for(i=1;i<m;i++){for(int j=1;j<=n;j++)if(file[i]==ch[j]) {cout<<HC[j];outstuf<<HC[j]; break;}if(j==(n+1)) {cout<<endl<<"The sentence is wrong and it can't coding! "<<endl; break;}cout<<endl;outstuf.close();}void decode(){inputDeco();}void inputDeco(){int m=2*n-1;char *password=(char *)malloc(200*sizeof(char));cout<<"Please input the sentence you want to decode.(Please end of the character of '$')"<<endl;for(int i=1;i<200&&password[i-1]!='$';i++) cin>>password[i];if(i==200) {password=(char *)realloc(password,(200+80)*sizeof(char));for(;i<280&&password[i]!='$';i++) cin>>password[i];}cout<<"The result of decode is:"<<endl;outstuf.open("TextFile.txt",ios::out);for(i=1;password[i]!='$';){char record[20];for(int j=0,q=i;password[q]!='$';j++,q++){if(password[q]=='0') {record[j]='0';m=HT[m].lchild;}else {record[j]='1';m=HT[m].rchild;}if(HT[m].rchild==0) {record[j+1]='\0';break;}}if(HT[m].rchild!=0) {cout<<endl<<"The sentence is wrong and it can't decode!"<<endl;break;}for(int p=1;p<=n;p++){if(!strcmp(record,HC[p])) {outstuf<<ch[p]; cout<<ch[p];break;}}i=i+strlen(record);m=2*n-1;}cout<<endl;outstuf.close();}int main(){int sel=0;cout<<"Xin Yun"<<endl;cout<<"Information Safety of 2"<<endl;cout<<"Welcome to use the coding and decode of Huffman!"<<endl;for(;;){cout<<"\t*\t"<<"1.init"<<endl;cout<<"\t*\t"<<"2.coding"<<endl;cout<<"\t*\t"<<"3.decode"<<endl;cout<<"\t*\t"<<"4.quit"<<endl;cout<<"Please input your choice(1-4)."<<endl<<" ";cin>>sel;if(sel==4) break;switch(sel){case 1:initHuffmanTree();break;case 2:encoding();break;case 3:decode();break;default:cout<<"Sorry!The number you have input is wrong!"<<endl;}}outstuf.close();cout<<"Thank you to use it!!!"<<endl;return 0;八、运行结果图表1开始界面图表2哈夫曼树的初始化图表3哈夫曼树的编码图表4哈夫曼树的译码图表5退出界面图表6全部九、总结9.1调试分析在写程序和调试的过程中,在对函数的理解及调用、参数的传递等方面遇到了很多的麻烦和困难;但最终在同学和老师的帮助下,我最终找出了程序中的错误并将其修改正确,通过分析,我学到了很多。