哈夫曼树的编码与译码
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. 编码:
哈夫曼编码是一种变长编码方式,对于出现频率高的字符使用较短的编码,而对于出现频率低的字符使用较长的编码。
具体步骤如下:(1)根据字符出现的频率,构建哈夫曼树。
频率相同的字符,按照它们在文件中的出现顺序排列。
(2)从哈夫曼树的叶子节点开始,从下往上逐步进行编码。
对于每个节点,如果该节点有左孩子,那么左孩子的字符编码为0,右孩子的字符编码为1。
如果该节点是叶子节点,则该节点的字符就是它的编码。
(3)对于哈夫曼树中的每个节点,都记录下它的左孩子和右孩子的位置,以便后续的解码操作。
2. 解码:
解码过程与编码过程相反,具体步骤如下:
(1)从哈夫曼树的根节点开始,沿着路径向下遍历树,直到找到一个终止节点(叶节点)。
(2)根据终止节点的位置信息,找到对应的字符。
(3)重复上述步骤,直到遍历完整个编码序列。
需要注意的是,哈夫曼编码是一种无损压缩算法,解压缩后的数据与原始数据完全相同。
此外,由于哈夫曼编码是一种变长编码方式,因此在解码时需要从根节点开始逐个解码,直到解码完成。
基于哈夫曼编码的编码译码问题
基于哈夫曼编码的编码译码问题基于哈夫曼编码的编码译码问题相关问题:1.哈夫曼编码是什么?如何进行编码和译码?2.哈夫曼编码的原理是什么?3.哈夫曼编码的应用领域有哪些?4.如何生成哈夫曼编码树?5.哈夫曼编码的时间复杂度是多少?6.哈夫曼树的构建方法有哪些?7.哈夫曼编码在数据压缩中的作用是什么?8.哈夫曼编码存在的局限性是什么?9.哈夫曼编码与其他编码方法的比较有哪些特点?10.如何解决哈夫曼编码中的冲突问题?解释说明:1.哈夫曼编码是一种基于字符频率的可变长度编码方法。
它通过将出现频率高的字符用较短的编码来表示,出现频率低的字符用较长的编码来表示,以达到数据压缩的目的。
编码过程中,首先统计字符出现频率,然后构建哈夫曼树,根据树的结构生成编码表,最后对原始数据进行编码。
译码过程中,根据生成的编码表和编码数据,逐位解码还原原始数据。
2.哈夫曼编码的原理是基于贪心算法,通过构建哈夫曼树,将出现频率高的字符放在树的上层,出现频率低的字符放在树的下层,以实现最优的编码效果。
在编码过程中,使用了前缀码的特性,即任何一个编码不能是另一个编码的前缀,从而保证了译码的唯一性。
3.哈夫曼编码广泛应用于数据压缩领域,可以对文本、图像、音频等数据进行压缩和解压缩。
此外,哈夫曼编码也用于数据传输中的差错检测和纠正,以及编码理论的研究等领域。
4.生成哈夫曼编码树的方法主要有两种:静态生成和动态生成。
静态生成是根据给定的字符频率进行构建,而动态生成是根据实际数据的字符频率进行构建。
5.哈夫曼编码的时间复杂度为O(nlogn),其中n为字符的个数。
这是由于在构建哈夫曼树时需要进行n-1次合并操作,每次合并的时间复杂度为O(logn)。
6.哈夫曼树的构建方法主要有两种:霍夫曼算法和优先队列算法。
霍夫曼算法是经典的构建方法,通过反复选择权值最小的两个节点合并构建树,直到所有节点合并为一棵树。
优先队列算法则先将节点插入优先队列中,每次取权值最小的两个节点合并。
哈夫曼编码与解码
哈夫曼编码与解码
哈夫曼编码(Huffman coding)和哈夫曼解码(Huffman decoding)是一种用于数据压缩的技术,由美国计算机科学家 David A. Huffman 于 1952 年提出。
哈夫曼编码的基本思想是根据字符在文本中出现的频率来分配二进制编码的长度。
出现频率较高的字符将被分配较短的编码,而出现频率较低的字符将被分配较长的编码。
这样,通过使用较短的编码来表示常见字符,可以实现更有效的数据压缩。
哈夫曼编码的过程包括以下步骤:
1. 统计字符出现频率:对要编码的文本进行分析,统计每个字符出现的次数。
2. 构建哈夫曼树:根据字符出现频率构建一棵二叉树,其中频率较高的字符靠近树的根节点,频率较低的字符位于树的叶子节点。
3. 分配编码:从根节点开始,根据字符出现频率为每个字符分配二进制编码。
左子节点表示 0,右子节点表示 1。
4. 编码文本:将文本中的每个字符替换为其对应的哈夫曼编码。
哈夫曼解码是哈夫曼编码的逆过程,用于将已编码的数据还原为原始文本。
解码过程根据哈夫曼树的结构和编码规则,从编码中解析出原始字符。
哈夫曼编码与解码在数据压缩领域具有广泛的应用,例如图像、音频和视频压缩。
它通过有效地利用字符频率分布的不均匀性,实现了较高的压缩率,从而减少了数据传输和存储的开销。
需要注意的是,哈夫曼编码是一种无损压缩技术,意味着解码后可以完全还原原始数据。
但在实际应用中,可能会结合其他有损压缩技术来进一步提高压缩效果。
哈弗曼编码与译码
一个完整的系统应具有以下功能:(1) I:初始化(Initialization)。
从终端读入字符集大小n,以及n个字符和n个权值,建立赫夫曼树,并将它存于文件hfmTree中。
(2) E:编码(Encoding)。
利用已建好的赫夫曼树(如不在存,则从文件hfmTree中读入),对文件ToBeTran中的正文进行编码,然后将结果存入文件CodeFile中。
(3) D:译码(Decoding)。
利用已建好的赫夫曼树将文件CodeFile中的代码进行译码,结果存入文件Textfile中。
以下为选做:(4) P:印代码文件(Print)。
将文件CodeFile以紧凑格式显示在终端上,每行50个代码。
同时将此字符形式的编码文件写入文件CodePrin中。
(5) T:印赫夫曼树(Tree printing)。
将已在存中的赫夫曼树以直观的方式(比如树)显示在终端上,同时将此字符形式的赫夫曼树写入文件TreePrint 中。
2.测试要求(1) 已知某系统在通信联络中只可能出现八种字符,其频率分别为0.05,0.29,0.07,0.08,0.14,0.23,0.03,0.11,试设计赫夫曼编码。
(2) 用下表给出的字符集和频度的实际统计数据建立赫夫曼树,并实现以下报文的编码和译码:“THIS PROGRAME IS MY FAVORITE”。
3.实现提示(1) 编码结果以文本方式存储在文件Codefile中。
(2) 用户界面可以设计为“菜单”方式:显示上述功能符号,再加上“Q”,表示退出运行Quit。
请用户键入一个选择功能符。
此功能执行完毕后再显示此菜单,直至某次用户选择了“Q”为止。
(3) 在程序的一次执行过程中,第一次执行I,D或C命令之后,赫夫曼树已经在存了,不必再读入。
每次执行中不一定执行I命令,因为文件hfmTree可能早已建好。
#include <string.h>#include <stdio.h>#include <stdlib.h>#include <malloc.h>typedef struct {char letter;float wt;}hfm,*hfmlist;//*************************全局变量************************************ unsigned int s1,s2,n;char choose;int DEPTH=0;char a[20];//***************Huffman树和Huffman编码的存储表示********************** typedef struct{unsigned int weight;unsigned int code;unsigned int parent,lchild,rchild;}HTNode, *HuffmanTree; //动态分配数组存储Huffman树typedef char * *HuffmanCode; //动态分配数组存储Huffman编码表//***************************初始化Huffman树***************************void select(HuffmanTree HT,int l){int a,b,c,j;s1=s2=1;a=b=1000;for(j=1;j<=l;j++){if(HT[j].code==0){c=HT[j].weight;if(c<a){b=a;a=c;s2=s1;s1=j;}else if(c<b){b=c;s2=j;}}//if}//forHT[s1].code=HT[s2].code=1;}//selectvoid HuffmanCoding(HuffmanTree &HT,HuffmanCode &HC, hfmlist HL,unsigned int n){ //w存放n个权值(均>0),构造Huffman树HT,并求出n个字符的Huffman编码HC. unsigned int i,f,start,c,m;char*cd;if (n<=1) return;m =2*n-1;HT=(HuffmanTree)malloc((m+1)*sizeof(HTNode));for(i=1;i<=m;++i){HT[i].weight=HT[i].parent=HT[i].lchild=HT[i].rchild=HT[i].cod e=0;}for(i=1;i<=n;++i)HT[i].weight=HL[i].wt;for (i=n+1;i<=m;++i){select(HT,i-1);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*));cd=(char*)malloc(n*sizeof(char));cd[n-1]='\0';for(i=1;i<=n;++i){start=n-1;for(c=i,f=HT[i].parent;f!=0;c=f,f=HT[f].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);}//*************************文件操作*****************************void save (char *p){FILE *fp;int i;printf("input the name:");if((fp=fopen(gets(a),"w+"))==NULL){printf("cannot open the file!\n");exit(0);}//iffor(i=0;p[i]!='\0';i++){if(fwrite(p+i,sizeof(char),1,fp)!=1){//fwrite函数写数据块printf("File write error!\n");exit(0);}//if}//forfclose(fp);}//save//************************编码与译码操作********************************** void Decoding(HuffmanTree HT,hfmlist HL,char*size,int n)//这个函数是用来译码的 {int i,j,k;char p[130];printf("请输入需要译码的代码:");gets(p);//接受需要译码的字符串i=2*n-1;k=0;for(j=0;p[j]!='\0';j++){if(p[j]=='0'){ if(HT[i].lchild!=0)i=HT[i].lchild;else{ size[k++]=HL[i].letter;i=2*n-1;j--;}}else{ if(HT[i].rchild!=0)i=HT[i].rchild;else{ size[k++]=HL[i].letter;i=2*n-1;j--;}}}//forif( p[j-1]=='0')size[k++]=HL[i].letter;else size[k++]=HL[i].letter;size[k]='\0';}//decodingvoid Encoding(HuffmanCode HC,hfmlist HL,char *coding,int n){ int i,j,t,k=0;char p[100];printf("请再次输入需要编码的文本:");gets(p);for(i=0;p[i]!='\0';i++){if((p[i]>='A'&&p[i]<='Z')||p[i]==' ')for(j=1;j<=n;j++)if(p[i]==HL[j].letter)for(t=0;HC[j][t]!='\0';t++)coding[k++]=HC[j][t];}//forcoding[k]='\0';}//encoding//************************打印操作**************************** void Print(FILE *fp1,FILE *fp2){//将文件fp1中的代码以紧凑格式显示在终端上,每行50个代码//同时将此字符形式的编码文件写入文件fp2中char c[200];int i;fgets(c,200,fp1);for(i=0;c[i]=='0'||c[i]=='1';i++){printf("%c",c[i]);fprintf(fp2,"%c",c[i]);if((i+1)/50*50==(i+1)){printf("\n");fprintf(fp2,"\n");}}//forprintf("\n");}//Printvoid PreOrderTraverse(HuffmanTree HT,int k,FILE *fp){//先序遍历并打印树,结果存放于fp中,k为根结点的下标int i;for(i=1;i<=DEPTH-1;i++)fprintf(fp," ");for(;i<=DEPTH;i++)fprintf(fp,"|------");fprintf(fp,"%d\n",HT[k].weight);if(HT[k].lchild!=0){DEPTH++;PreOrderTraverse(HT,HT[k].lchild,fp);DEPTH--;}if(HT[k].rchild!=0){DEPTH++;PreOrderTraverse(HT,HT[k].rchild,fp);DEPTH--;}if(HT[k].lchild==0&&HT[k].rchild==0)return;return;} //PreOrderTraversevoid TreePrinting(HuffmanTree HT,int n,FILE *fp){//打印树HT,结果存于文件fp中,n为树的叶子结点数int i,k;for(i=1;i<=2*n;i++)if(HT[i].parent==0){k=i;break;}//寻找根结点PreOrderTraverse(HT,k,fp);return;}//TreePrinting//**************************主函数*********************************int main(){FILE *fp1,*fp2,*fp3,*fp4,*fp5;HuffmanTree HT;HuffmanCode HC;hfmlist HL;unsigned int i,n;char *b,c[100],cha,ch;b=(char *)malloc(100*sizeof(char));printf("请选择操作:\n");printf("i:初始化(Initialization)\ne:编码(Encoding)\nd:译码(Decoding)\n");printf("p:印代码文件(Print)\nt:印哈夫曼树(Tree printing)\nq:退出(Quit)\n");b=(char *)malloc(100*sizeof(char));HL=(hfmlist)malloc(30*sizeof(hfm));//存储字符与权值,线性表长30printf("\n");printf("选择操作(i,e,d,p,t,q):");ch=getchar();getchar();printf("\n");do{switch(ch){case 'i':printf("正在进行初始化……\n");printf("输入字符长度:");scanf("%d",&n);getchar();printf("\n");HC=(HuffmanCode)malloc((n+1)*sizeof(char));HT=(HuffmanTree)malloc((2*n)*sizeof(HTNode));for(i=1;i<=n;i++){printf("请输入第%d个字符及权值(格式:字符权值):",i);scanf("%c %f",&(HL+i)->letter, &(HL+i)->wt);getchar();}//forif((fp5=fopen("hfmTree.txt","w"))==NULL){printf("cannot open file!\n");exit(0);}//iffor(i=1;i<=n;i++){fprintf(fp5,"第%d个字符及权值:\t\t\t",i);fprintf(fp5,"%c %f\n",(HL+i)->letter,(HL+i)->wt);}//forfclose(fp5);HuffmanCoding(HT,HC,HL,n);printf("\n已经将Huffman树存入文件hfmTree.txt中\n\n");printf("初始化完毕,请选择操作:\n");printf("i:重新初始化(Initialization)\ne:编码(Encoding)\nd:译码(Decoding)\n");printf("p:印代码文件(Print)\nt:印哈夫曼树(Tree printing)\nq:退出(Quit)\n\n");break;case 'e':printf("请输入编码,以#结尾:");if((fp2=fopen("ToBeTran.txt","w"))==NULL){printf("cannot open file\n");exit(0);}//ifcha=getchar();while(cha!='#'){fputc(cha,fp2);cha=getchar();}//whilegetchar();fclose(fp2);printf("已经把编码存入文件ToBeTran.txt中\n\n");Encoding(HC,HL,b,n);printf("文本的哈夫曼编码是:");printf("%s\n",b);printf("下面进行保存:");save(b);printf("编码完毕,请选择操作:\n");printf("i:重新初始化(Initialization)\ne:编码(Encoding)\nd:译码(Decoding)\n");printf("p:印代码文件(Print)\nt:印哈夫曼树(Tree printing)\nq:退出(Quit)\n");break;case 'd':Decoding(HT,HL,c,n);printf("输入要译码的编码:");printf("正在进行译码……\n");printf("%s\n",c);save(c);printf("已经将结果存入文件%s中\n",a);printf("译码完毕,请选择操作:\n");printf("i:重新初始化(Initialization)\ne:编码(Encoding)\nd:译码(Decoding)\n");printf("p:印代码文件(Print)\nt:印哈夫曼树(Tree printing)\nq:退出(Quit)\n");break;case 'p':for(i=1;i<=n;i++)printf("字符:%c\t\t\t译码:%s\n",HL[i].letter,HC[i]);if((fp1=fopen("CodeFile.txt","w"))==NULL){printf("cannot open the file!\n");exit(0);}//ifif((fp4=fopen("CodeFile.txt","r"))==NULL){printf("cannot open the file!\n");exit(0);}//ifPrint(fp4,fp1);printf("该代码文件已经存在并命名为CodePrin.txt\n"); fclose(fp4);fclose(fp1);break;case 't':printf("打印树存在于文件TreePrin中\n");if((fp3=fopen("TreePrin.txt","w"))==NULL){printf("cannot open file\n");exit(0);}TreePrinting(HT,n,fp3);fclose(fp3);break;case 'q':exit(0);break;default :exit(0);break;}//switchprintf("\n请选择操作(i,e,d,p,t,q):");ch=getchar();getchar();}while(ch!='q');//doreturn 0 ;}//main。
哈弗曼编码与译码
一个完整的系统应具有以下功能:(1) I:初始化〔Initialization〕。
从终端读入字符集大小n,以及n个字符和n个权值,建立赫夫曼树,并将它存于文件hfmTree中。
(2) E:编码〔Encoding〕。
利用已建好的赫夫曼树〔如不在内存,则从文件hfmTree中读入〕,对文件ToBeTran中的正文进行编码,然后将结果存入文件CodeFile中。
(3) D:译码〔Decoding〕。
利用已建好的赫夫曼树将文件CodeFile中的代码进行译码,结果存入文件Textfile中。
以下为选做:(4) P:印代码文件〔Print〕。
将文件CodeFile以紧凑格式显示在终端上,每行50个代码。
同时将此字符形式的编码文件写入文件CodePrin中。
(5) T:印赫夫曼树〔Tree printing〕。
将已在内存中的赫夫曼树以直观的方式〔比方树〕显示在终端上,同时将此字符形式的赫夫曼树写入文件TreePrint 中。
2.测试要求(1) 已知某系统在通信联络中只可能出现八种字符,其频率分别为,试设计赫夫曼编码。
(2) 用下表给出的字符集和频度的实际统计数据建立赫夫曼树,并实现以下报文的编码和译码:“THIS PROGRAME IS MY FA VORITE”。
3.实现提示(1) 编码结果以文本方式存储在文件Codefile中。
(2) 用户界面可以设计为“菜单”方式:显示上述功能符号,再加上“Q”,表示退出运行Quit。
请用户键入一个选择功能符。
此功能执行完毕后再显示此菜单,直至某次用户选择了“Q”为止。
(3) 在程序的一次执行过程中,第一次执行I,D或C命令之后,赫夫曼树已经在内存了,不必再读入。
每次执行中不一定执行I命令,因为文件hfmTree可能早已建好。
#include <string.h>#include <stdio.h>#include <stdlib.h>#include <malloc.h>typedef struct {char letter;float wt;}hfm,*hfmlist;//*************************全局变量************************************unsigned int s1,s2,n;char choose;int DEPTH=0;char a[20];//***************Huffman树和Huffman编码的存储表示********************** typedef struct{unsigned int weight;unsigned int code;unsigned int parent,lchild,rchild;}HTNode, *HuffmanTree; //动态分配数组存储Huffman树typedef char * *HuffmanCode; //动态分配数组存储Huffman编码表//***************************初始化Huffman树*************************** void select(HuffmanTree HT,int l){int a,b,c,j;s1=s2=1;a=b=1000;for(j=1;j<=l;j++){if(HT[j].code==0){c=HT[j].weight;if(c<a){b=a;a=c;s2=s1;s1=j;}else if(c<b){b=c;s2=j;}}//if}//forHT[s1].code=HT[s2].code=1;}//selectvoid HuffmanCoding(HuffmanTree &HT,HuffmanCode &HC, hfmlist HL,unsigned int n){ //w存放n个权值〔均>0〕,构造Huffman树HT,并求出n个字符的Huffman编码HC. unsigned int i,f,start,c,m;char*cd;if (n<=1) return;m =2*n-1;HT=(HuffmanTree)malloc((m+1)*sizeof(HTNode));for(i=1;i<=m;++i){HT[i].weight=HT[i].parent=HT[i].lchild=HT[i].rchild=HT[i].code=0;} for(i=1;i<=n;++i)HT[i].weight=HL[i].wt;for (i=n+1;i<=m;++i){select(HT,i-1);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*));cd=(char*)malloc(n*sizeof(char));cd[n-1]='\0';for(i=1;i<=n;++i){start=n-1;for(c=i,f=HT[i].parent;f!=0;c=f,f=HT[f].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);}//*************************文件操作*****************************void save (char *p){FILE *fp;int i;printf("input the name:");if((fp=fopen(gets(a),"w+"))==NULL){printf("cannot open the file!\n");exit(0);}//iffor(i=0;p[i]!='\0';i++){if(fwrite(p+i,sizeof(char),1,fp)!=1){//fwrite函数写数据块printf("File write error!\n");exit(0);}//if}//forfclose(fp);}//save//************************编码与译码操作********************************** void Decoding(HuffmanTree HT,hfmlist HL,char*size,int n)//这个函数是用来译码的{int i,j,k;char p[130];printf("请输入需要译码的代码:");gets(p);//接受需要译码的字符串i=2*n-1;k=0;for(j=0;p[j]!='\0';j++){if(p[j]=='0'){ if(HT[i].lchild!=0)i=HT[i].lchild;else{ size[k++]=HL[i].letter;i=2*n-1;j--;}}else{ if(HT[i].rchild!=0)i=HT[i].rchild;else{ size[k++]=HL[i].letter;i=2*n-1;j--;}}}//forif( p[j-1]=='0')size[k++]=HL[i].letter;else size[k++]=HL[i].letter;size[k]='\0';}//decodingvoid Encoding(HuffmanCode HC,hfmlist HL,char *coding,int n){int i,j,t,k=0;char p[100];printf("请再次输入需要编码的文本:");gets(p);for(i=0;p[i]!='\0';i++){if((p[i]>='A'&&p[i]<='Z')||p[i]==' ')for(j=1;j<=n;j++)if(p[i]==HL[j].letter)for(t=0;HC[j][t]!='\0';t++)coding[k++]=HC[j][t];}//forcoding[k]='\0';}//encoding//************************打印操作**************************** void Print(FILE *fp1,FILE *fp2){//将文件fp1中的代码以紧凑格式显示在终端上,每行50个代码//同时将此字符形式的编码文件写入文件fp2中char c[200];int i;fgets(c,200,fp1);for(i=0;c[i]=='0'||c[i]=='1';i++){printf("%c",c[i]);fprintf(fp2,"%c",c[i]);if((i+1)/50*50==(i+1)){printf("\n");fprintf(fp2,"\n");}}//forprintf("\n");}//Printvoid PreOrderTraverse(HuffmanTree HT,int k,FILE *fp){//先序遍历并打印树,结果存放于fp中,k为根结点的下标int i;for(i=1;i<=DEPTH-1;i++)fprintf(fp," ");for(;i<=DEPTH;i++)fprintf(fp,"|------");fprintf(fp,"%d\n",HT[k].weight);if(HT[k].lchild!=0){DEPTH++;PreOrderTraverse(HT,HT[k].lchild,fp);DEPTH--;}if(HT[k].rchild!=0){DEPTH++;PreOrderTraverse(HT,HT[k].rchild,fp);DEPTH--;}if(HT[k].lchild==0&&HT[k].rchild==0)return;return;} //PreOrderTraversevoid TreePrinting(HuffmanTree HT,int n,FILE *fp){//打印树HT,结果存于文件fp中,n为树的叶子结点数int i,k;for(i=1;i<=2*n;i++)if(HT[i].parent==0){k=i;break;}//寻找根结点PreOrderTraverse(HT,k,fp);return;}//TreePrinting//**************************主函数*********************************int main(){FILE *fp1,*fp2,*fp3,*fp4,*fp5;HuffmanTree HT;HuffmanCode HC;hfmlist HL;unsigned int i,n;char *b,c[100],cha,ch;b=(char *)malloc(100*sizeof(char));printf("请选择操作:\n");printf("i:初始化(Initialization)\ne:编码(Encoding)\nd:译码(Decoding)\n");printf("p:印代码文件(Print)\nt:印哈夫曼树(Tree printing)\nq:退出(Quit)\n");b=(char *)malloc(100*sizeof(char));HL=(hfmlist)malloc(30*sizeof(hfm));//存储字符与权值,线性表长30printf("\n");printf("选择操作(i,e,d,p,t,q):");ch=getchar();getchar();printf("\n");do{switch(ch){case 'i':printf("正在进行初始化……\n");printf("输入字符长度:");scanf("%d",&n);getchar();printf("\n");HC=(HuffmanCode)malloc((n+1)*sizeof(char));HT=(HuffmanTree)malloc((2*n)*sizeof(HTNode));for(i=1;i<=n;i++){printf("请输入第%d个字符及权值(格式:字符权值):",i);scanf("%c %f",&(HL+i)->letter, &(HL+i)->wt);getchar();}//forif((fp5=fopen("hfmTree.txt","w"))==NULL){printf("cannot open file!\n");exit(0);}//iffor(i=1;i<=n;i++){fprintf(fp5,"第%d个字符及权值:\t\t\t",i);fprintf(fp5,"%c %f\n",(HL+i)->letter,(HL+i)->wt);}//forfclose(fp5);HuffmanCoding(HT,HC,HL,n);printf("\n已经将Huffman树存入文件hfmTree.txt中\n\n");printf("初始化完毕,请选择操作:\n");printf("i:重新初始化(Initialization)\ne:编码(Encoding)\nd:译码(Decoding)\n");printf("p:印代码文件(Print)\nt:印哈夫曼树(Tree printing)\nq:退出(Quit)\n\n");break;case 'e':printf("请输入编码,以#结尾:");if((fp2=fopen("ToBeTran.txt","w"))==NULL){printf("cannot open file\n");exit(0);}//ifcha=getchar();while(cha!='#'){fputc(cha,fp2);cha=getchar();}//whilegetchar();fclose(fp2);printf("已经把编码存入文件ToBeTran.txt中\n\n");Encoding(HC,HL,b,n);printf("文本的哈夫曼编码是:");printf("%s\n",b);printf("下面进行保存:");save(b);printf("编码完毕,请选择操作:\n");printf("i:重新初始化(Initialization)\ne:编码(Encoding)\nd:译码(Decoding)\n");printf("p:印代码文件(Print)\nt:印哈夫曼树(Tree printing)\nq:退出(Quit)\n");break;case 'd':Decoding(HT,HL,c,n);printf("输入要译码的编码:");printf("正在进行译码……\n");printf("%s\n",c);save(c);printf("已经将结果存入文件%s中\n",a);printf("译码完毕,请选择操作:\n");printf("i:重新初始化(Initialization)\ne:编码(Encoding)\nd:译码(Decoding)\n");printf("p:印代码文件(Print)\nt:印哈夫曼树(Tree printing)\nq:退出(Quit)\n");break;case 'p':for(i=1;i<=n;i++)printf("字符:%c\t\t\t译码:%s\n",HL[i].letter,HC[i]);if((fp1=fopen("CodeFile.txt","w"))==NULL){printf("cannot open the file!\n");exit(0);}//ifif((fp4=fopen("CodeFile.txt","r"))==NULL){printf("cannot open the file!\n");exit(0);}//ifPrint(fp4,fp1);printf("该代码文件已经存在并命名为CodePrin.txt\n");fclose(fp4);fclose(fp1);break;case 't':printf("打印树存在于文件TreePrin中\n");if((fp3=fopen("TreePrin.txt","w"))==NULL) {printf("cannot open file\n");exit(0);}TreePrinting(HT,n,fp3);fclose(fp3);break;case 'q':exit(0);break;default :exit(0);break;}//switchprintf("\n请选择操作(i,e,d,p,t,q):");ch=getchar();getchar();}while(ch!='q');//doreturn 0 ;}//main。
哈夫曼树、编码和译码的实现
creathfmt(t);
listBox1->Items->Clear();
String ^s,^s0=" ";
for(inti=0;i<2*n-1;i++)
{
if(i<10&&i>-1) s=i+": ";elses=i+" ";
if(t[i].parent<10&&t[i].parent>-1) s=s+" "; s=s+s0+t[i].parent;
日期:2013年12月29日
教务处制
了解哈夫曼树特点及有关概念,掌握哈夫曼树的各种基本操作算法思想及其实现。
1、初始化哈夫曼树
2、建立哈夫曼树
3、编码哈夫曼树
4、解码哈夫曼树
三、实验步骤
constintMAXLEN=100;
structhtnode
{
intweight,lchild,rchild,parent;
t[i].lchild=-1;
t[i].rchild=-1;
t[i].parent=-1;
}
}
voidselectmin(hfmt t,inti,int*p1,int*p2)
{
longmin1=999;
longmin2=999;
intj;
for(j=0;j<=i;j++)
if(t[j].parent==-1)
成绩教师签字
};
typedefhtnode hfmt[MAXLEN];
constintn=8;
哈夫曼编码与译码(附源码)
建立Huffman树进行编码和译码的设计郝萌 1100300423 哈尔滨工业大学电脑科学与技术学院 1003104班摘要:建立一个简易的系统,对于给定的一篇英文文章,统计字符出现的概率,并根据概率建立Huffman树,利用Huffman编码对文章进行编码和译码。
掌握Huffman树的建立与应用,并进一步熟练掌握程序的设计流程。
关键词:Huffman树Huffman编码文章译码文件压缩解压缩1.引言:给定一篇文章,统计字符出现的概率,根据概率建立哈夫曼树,并进行哈夫曼编码,进而可以利用哈夫曼编码对文章进行编码与译码和文件压缩、解压缩等操作。
2.程序设计流程(1)文字表述开始进入功能选择界面,包含五种操作:1.读取文章并对字符编码,2.哈夫曼编码信息,3.文章编码,4.文章译码,5.文件压缩,6.文件解压缩,7.退出程序。
操作1:给定一篇文章,统计字符出现的概率,并根据概率建立Huffman树,并利用Huffman树对字符进行Huffman编码。
操作2:显示Huffman编码信息,包括字符,字符出现的概率,Huffman编码。
操作3:对文章进行译码,显示译码信息,并保存。
操作4:对文章进行译码,显示并保存。
操作5:对文件进行压缩,每7位二进制序列对应一个ASCII码。
操作6:对文件进行解压缩。
(2)流程图(3)程序数据要求及功能实现主界面1.读取文件并对字符进行编码2.哈夫曼编码信息3.文件编码(1)显示文件编码(2)保存文件编码4.文件译码(1)显示文章编码的译码(2)保存文章编码的译码5.文件压缩6.文件解压缩附:程序源代码/** File: HUFFMANFUNCTION.h* Author: Administrator** Created on 2011年12月19日, 下午6:19 */#ifndef HUFFMANFUNCTION_H#define HUFFMANFUNCTION_H#include <cstdlib>#include<iostream>#include<fstream>#include<math.h>#define max1 150#define max2 50#define max3 256using namespace std;class Htnote {public:char name; //字符名double weight; //权重int lchild; //左孩子int rchild; //右孩子int parent; //父亲Htnote() {weight = 0;lchild = -1;parent = -1;rchild = -1;}};class Name {public:int num; //字符出现的次数char pname; //字符名double lweight; //权值Name() {num = 0;lweight = 0;}};class GetName {public:char namef[max2];int n; //字符的种类int sum; //字符的总数Name letter[max1]; //存储字符信息的类的数组GetName() {sum = 0;n = 0;}void GetWeight()//得到字符的权值{for (int i = 0; i < n; i++) {letter[i].lweight = (double) letter[i].num / sum; //出现的次数除总数得到权值}}int ReadLetter() {ifstream input;cout << "请输入文件名:" << endl;cin >> namef;input.open(namef); //打开文件if (input.fail()) {cout << "该文件不存在!" << endl;return 0;}char ch;ch = input.get();letter[0].pname = ch;letter[0].num++;sum++;while (!input.eof()) {//读取文件中的所有字符int tag = 0;ch = input.get();for (int i = 0; i < n + 1; i++) {if (letter[i].pname == ch) {letter[i].num++;sum++;tag = 1;}}if (tag == 0) {n++;letter[n].pname = ch;letter[n].num++;sum++;}}sum--;input.close();GetWeight(); //得到字符权值}};class CodeNode//编码类{public:char ch; //存储字符char bits[max1]; //存储编码};class Function {public:GetName L;int fn; //定义哈夫曼数组大小Htnote HuffmanT[max3]; //哈夫曼数组CodeNode Code[max1]; //字符编码数组Function() {fn = 0;}void CharHuffmanTCoding()//编码功能实现{int i, f, c;char cd[L.n + 1]; //暂时存储编码的数组int start; //编码读取起始位置cd[L.n] = '\0';for (i = 0; i < L.n; i++) {Code[i].ch = HuffmanT[i].name; //字符信息start = L.n; //起始位置c = i;while ((f = HuffmanT[c].parent) >= 0) {if (HuffmanT[f].lchild == c)//如果为左孩子,为‘0’{cd[--start] = '0';} else//如果为右孩子,为‘1’{cd[--start] = '1';}c = f;}strcpy(Code[i].bits, &cd[start]); //将结果存入对应的编码数组中}}void OutputHuffmanTCode() {cout << "哈夫曼编码:" << endl;cout << "——————————————————————" << endl;cout << "字符\t权值\t\t哈夫曼编码" << endl;for (int i = 0; i < L.n; i++)//输出字符,权值,哈夫曼编码{cout << "——————————————————————" << endl;cout << HuffmanT[i].name << "\t" << HuffmanT[i].weight << "\t";cout << Code[i].bits;cout << endl;}cout << "——————————————————————" << endl;}void InitHT()//哈夫曼初始化{L.ReadLetter();fn = (L.n)*2 - 1;for (int i = 0; i < fn; i++) {if (i < L.n) {HuffmanT[i].name = L.letter[i].pname;HuffmanT[i].weight = L.letter[i].lweight;}}}void SelectMin(int m, int &p1, int &p2)//选择最小的两个节点{int i, j;double m1, m2;m1 = m2 = 1;p1 = p2 = -1;for (i = 0; i < m; i++) {if (HuffmanT[i].parent == -1 && HuffmanT[i].weight < m1)//找出为访问过的最小权值节点{m2 = m1;p2 = p1;m1 = HuffmanT[i].weight;p1 = i;} else if (HuffmanT[i].parent == -1 && HuffmanT[i].weight < m2)//找出为访问的权值第二小结点{m2 = HuffmanT[i].weight;p2 = i;}}}void CreatHT()//建立哈夫曼树{int i, p1, p2;InitHT();for (i = L.n; i < fn; i++) {SelectMin(i, p1, p2);HuffmanT[p1].parent = HuffmanT[p2].parent = i;HuffmanT[i].lchild = p1;HuffmanT[i].rchild = p2;HuffmanT[i].weight = HuffmanT[p1].weight + HuffmanT[p2].weight;}}int OutArticleCode()//显示文章编码{//文章编码操作ifstream input;input.open(f);if (input.fail()) {cout << "文件不存在!" << endl;return 0;}char ch;cout << "文章编码如下:" << endl;while (!input.eof()) {ch = input.get();for (int i = 0; i < L.n; i++) {if (Code[i].ch == ch)cout << Code[i].bits;}}cout << endl;input.close();}int SaveArticleCode()//保存文章编码{ofstream output;ifstream input;char namef1[max2];input.open(f);if (input.fail()) {cout << "该文件不存在!" << endl;return 0;}cout << "请输入保存文章编码的文件名:" << endl;cin >> namef1;output.open(namef1);char ch;while (!input.eof()) {ch = input.get();for (int i = 0; i < L.n; i++) {if (Code[i].ch == ch) {for (int j = 0; j < strlen(Code[i].bits); j++) {output.put(Code[i].bits[j]);}}}}input.close();output.close();cout << "保存完毕!" << endl;}int OutTransCode() {//文章译码操作ifstream input;char namef[max2];cout << "请输入保存文章编码的文件名:" << endl;cin >> namef;input.open(namef);if (input.fail()) {cout << "该文件不存在!" << endl;return 0;}char ch;ch = input.get();int c = 2 * L.n - 2;while (!input.eof()) {if (ch == '0')//遇0搜索左子树{if (HuffmanT[c].lchild >= 0) {c = HuffmanT[c].lchild;}if (HuffmanT[c].lchild == -1)//判断是否到叶子{cout << HuffmanT[c].name; //输出字符c = 2 * L.n - 2; //返回根节点}}if (ch == '1')//遇1搜索右子树{if (HuffmanT[c].rchild >= 0) {c = HuffmanT[c].rchild;}if (HuffmanT[c].rchild == -1)//判断是否到叶子{cout << HuffmanT[c].name; //输出字符c = 2 * L.n - 2; //返回根节点}}ch = input.get();}cout << endl;input.close();}int SaveTransCode() {//保存文章译码ofstream output;ifstream input;char namef[max2];char namef1[max2];cout << "请输入文章编码所在的文件名:" << endl;cin >> namef;input.open(namef);if (input.fail()) {cout << "该文件不存在!" << endl;return 0;}cout << "请输入保存文章译码的文件名:" << endl;cin >> namef1;output.open(namef1);char ch;ch = input.get();int c = 2 * L.n - 2;while (!input.eof()) {if (ch == '0') {if (HuffmanT[c].lchild >= 0) {c = HuffmanT[c].lchild;}if (HuffmanT[c].lchild == -1) {output.put(HuffmanT[c].name);c = 2 * L.n - 2;}}if (ch == '1') {if (HuffmanT[c].rchild >= 0) {c = HuffmanT[c].rchild;}if (HuffmanT[c].rchild == -1) {output.put(HuffmanT[c].name);c = 2 * L.n - 2;}}ch = input.get();}input.close();output.close();cout << "保存完毕!" << endl;}int FileCompression() {//文件压缩功能CreatHT();CharHuffmanTCoding();//保存编码ofstream output;ifstream input;char namef1[] = {"temp.txt"};input.open(f);if (input.fail()) {cout << "该文件不存在!" << endl;return 0;}output.open(namef1);char ch;while (!input.eof()) {ch = input.get();for (int i = 0; i < L.n; i++) {if (Code[i].ch == ch) {for (int j = 0; j < strlen(Code[i].bits); j++) {output.put(Code[i].bits[j]);}}}}input.close();output.close();//压缩文件ofstream File1;ifstream File2;char namef2[max2];cout << "请输入压缩后的文件名:" << endl;cin >> namef2;File1.open(namef2);File2.open(namef1);if (File2.fail()) {cout << "该文件不存在!" << endl;return 0;}char sh;char th;int i = 0;char j = '0';int count = 0;while (!File2.eof()) {sh = File2.get();if (i < 7 && sh != EOF) {count = count + (sh - '0') * pow(2, i);if (sh == '0') {j++;} else {j = '0';}i++;}if (i == 7) {th = count;File1.put(th);i = 0;count = 0;}if (sh == EOF) {th = count;File1.put(th);File1.put(j);i = 0;count = 0;}}File1.close();File2.close();remove(namef1);cout << "文件压缩完毕!" << endl;}int FileDecompression() {//文件解压缩//保存编码fstream output;fstream input;char namef2[max2];char namef1[] = {"temp.txt"};cout << "请输入待解压缩的文件名:" << endl;cin >> namef2;input.open(namef2, ios::in | ios::binary);output.open(namef1, ios::out | ios::binary);if (input.fail()) {cout << "该文件不存在!" << endl;return 0;}char ch;input.read(reinterpret_cast<char*> (&ch), sizeof (ch));char sh;char th = ch;input.read(reinterpret_cast<char*> (&ch), sizeof (ch));int count;char num;char t = '0';char p = '1';while (!input.eof()) {sh = th;th = ch;input.read(reinterpret_cast<char*> (&ch), sizeof (ch));count = sh;if (ch != EOF) {for (int i = 0; i < 7; i++) {num = count % 2 + '0';output.write(reinterpret_cast<char*> (&num), sizeof (num));count = count / 2;}}if (ch == EOF) {for (int i = 0; i < 7; i++) {num = count % 2 + '0';output.write(reinterpret_cast<char*> (&num), sizeof (num));count = count / 2;if (count == 0) {break;}}for (int i = 0; i < th - '0'; i++) {output.write(reinterpret_cast<char*> (&t), sizeof (t));}}}output.close();input.close();//解压文件fstream File1;fstream File2;char namef3[max2];cout << "请输入解压后的文件名:" << endl;cin >> namef3;File2.open(namef1, ios::in | ios::binary);File1.open(namef3);if (File2.fail()) {cout << "该文件不存在!" << endl;return 0;}cout << "解压后的文件内容为:" << endl;File2.read(reinterpret_cast<char*> (&ch), sizeof (ch));int c = 2 * L.n - 2;while (!File2.eof()) {if (ch == '0') {if (HuffmanT[c].lchild >= 0) {c = HuffmanT[c].lchild;}if (HuffmanT[c].lchild == -1) {cout << HuffmanT[c].name;File1.write(reinterpret_cast<char*> (&HuffmanT[c].name), sizeof (HuffmanT[c].name));c = 2 * L.n - 2;}}if (ch == '1') {if (HuffmanT[c].rchild >= 0) {c = HuffmanT[c].rchild;}if (HuffmanT[c].rchild == -1) {cout << HuffmanT[c].name;File1.write(reinterpret_cast<char*> (&HuffmanT[c].name), sizeof (HuffmanT[c].name));c = 2 * L.n - 2;}}File2.read(reinterpret_cast<char*> (&ch), sizeof (ch));}cout << endl;File2.close();File1.close();remove(namef1);cout << "解压完毕!" << endl;}};#endif /* HUFFMANFUNCTION_H */====================================================================== /** File: main.cpp* Author: Administrator** Created on 2011年12月13日, 上午9:09*/#include <iostream>#include "HUFFMANFUNCTION.h"using namespace std;/***/int main(int argc, char** argv){Function *a = new Function;while (1){//主界面显示cout << endl << endl << endl;cout << "<<==================功能选择===============>>" << endl;cout << " 【1】读取文章并对字符编码" << endl;cout << " 【2】哈夫曼编码信息" << endl;cout << " 【3】文章编码" << endl;cout << " 【4】文章译码" << endl;cout << " 【5】压缩文件" << endl;cout << " 【6】解压缩文件" << endl;cout << " 【7】退出程序" << endl;cout << "=========================================================" << endl << endl;char ch;cout << "====>>请选择功能:";cin >> ch;switch (ch){case '1'://读取文章并对字符编码{delete a;a = new Function;system("cls");a->CreatHT();a->CharHuffmanTCoding();cout << "操作完毕!" << endl;system("pause");system("cls");break;}case '2'://哈夫曼编码信息{system("cls");a->OutputHuffmanTCode();system("pause");system("cls");break;}case '3'://文章编码{system("cls");while (1){cout << endl;cout << "========>>1.显示文章编码" << endl;cout << "========>>2.保存文章编码" << endl;cout << "========>>3.返回上一界面" << endl;char ch1;cout << endl << "===>>请选择功能:";cin >> ch1;switch (ch1){case '1'://显示文章编码{system("cls");a->OutArticleCode();system("pause");system("cls");continue;}case '2'://保存文章编码{system("cls");a->SaveArticleCode();system("pause");system("cls");continue;}case '3'://返回上一界面{break;}default:{system("cls");cout << "输入错误,请重新输入!" << endl;continue;}}system("cls");break;}break;}case '4'://文章译码system("cls");while (1){cout << endl;cout << "========>>1.显示文章编码的译码" << endl;cout << "========>>2.保存文章编码的译码" << endl;cout << "========>>3.返回上一界面" << endl;char ch1;cout << endl << "===>>请选择功能:";cin >> ch1;switch (ch1){case '1'://显示文章编码的译码{system("cls");a->OutTransCode();system("pause");system("cls");continue;}case '2'://保存文章编码的译码{system("cls");a->SaveTransCode();system("pause");system("cls");continue;}case '3'://返回上一界面{break;}default:{system("cls");cout << "输入错误,请重新输入!" << endl;continue;}}system("cls");break;}break;case '5':{delete a;a = new Function;system("cls");a->FileCompression();system("pause");system("cls");continue;}case '6':{system("cls");a->FileDecompression();system("pause");system("cls");continue;}case '7':{return 0;}default:{system("cls");cout << "功能选择错误,请重新输入!" << endl;break;}}}return 0;}。
简述哈夫曼编码译码过程
简述哈夫曼编码译码过程哈夫曼编码是一种用于数据压缩的无损编码方法,它基于字符出现频率的统计信息,将频率较高的字符用较短的二进制编码表示,而将频率较低的字符用较长的二进制编码表示。
在对数据进行解码时,需要使用相同的编码表来将编码转换回原始数据。
哈夫曼编码的过程可以分为两个主要步骤:构建哈夫曼树和生成编码表。
下面将详细介绍每个步骤的实现过程。
构建哈夫曼树:1. 统计字符的频率:遍历要编码的数据,统计每个字符出现的频率。
2. 创建叶节点列表:将每个字符及其频率作为一个叶节点,构建一个列表。
3. 构建哈夫曼树:重复执行以下操作,直到只剩下一个节点:a. 从叶节点列表中选择两个频率最低的节点作为左右子节点。
b. 创建一个新的节点,其频率为左右子节点频率之和,并将其设为左右子节点的父节点。
c. 将新的父节点添加到叶节点列表中。
d. 从叶节点列表中删除选择的两个节点。
4. 哈夫曼树的根节点即为构建完成的树。
生成编码表:1. 遍历哈夫曼树:从根节点开始,遍历哈夫曼树的每个节点。
a. 若当前节点为叶节点,记录该节点所表示字符的编码路径。
b. 若当前节点有左子节点,将路径标记为0,并继续遍历左子节点。
c. 若当前节点有右子节点,将路径标记为1,并继续遍历右子节点。
2. 将每个字符与其对应的编码路径关系保存在编码表中。
哈夫曼编码的过程中,编码表的生成是非常重要的一步。
通过遍历哈夫曼树,可以确定每个字符的唯一编码,从而在进行译码时能够将编码路径按照对应的编码表转换为原始数据。
译码过程:1. 读取编码数据:将压缩后的二进制数据按位读取。
2. 解码树的遍历:从哈夫曼树的根节点开始,按照读取的二进制位(0或1)依次向左或向右遍历。
3. 判断节点类型:若当前节点为叶节点,表示已找到对应的字符,记录该字符并重新从根节点开始遍历。
4. 判断读取结束:若读取的二进制数据已经全部解码完毕,则译码结束;否则继续读取下一位二进制数据进行遍历。
数据结构 哈夫曼编码与译码
数据结构哈夫曼编码与译码哈夫曼编码与译码是数据结构中的重要概念,它是一种可变长度编码的方法,用于压缩数据。
在本文中,我将详细介绍哈夫曼编码与译码的原理、步骤以及应用。
一、哈夫曼编码的原理哈夫曼编码是一种根据字符出现的频率来构建编码表的方法,使得频率较高的字符使用较短的编码,频率较低的字符使用较长的编码。
这样可以有效地减少数据的存储空间。
二、哈夫曼编码的步骤1. 统计字符频率:遍历待编码的文本,统计每个字符出现的频率。
2. 构建哈夫曼树:根据字符频率构建哈夫曼树。
首先将每个字符作为一个独立的树节点,然后合并频率最低的两个节点,生成一个新的节点,频率为这两个节点的频率之和。
重复此过程,直到所有节点都合并为一个根节点,得到哈夫曼树。
3. 生成编码表:从根节点开始遍历哈夫曼树,左子树路径为0,右子树路径为1,将路径上的0和1依次添加到对应字符的编码中,得到编码表。
4. 进行编码:根据编码表,将待编码的文本中的每个字符替换为对应的编码。
5. 完成编码:得到编码后的文本。
三、哈夫曼译码的步骤1. 根据编码表,将编码后的文本逐个字符地进行译码。
从根节点开始,根据字符是0还是1,选择左子树或右子树进行下一步操作。
2. 如果到达叶子节点,则找到对应的字符,并将该字符添加到译码结果中。
3. 重复上述步骤,直到译码结束,得到原始文本。
四、哈夫曼编码与译码的应用哈夫曼编码与译码广泛应用于数据压缩领域。
通过使用哈夫曼编码,可以大大减小数据的存储空间,提高数据传输的效率。
在图像、音频、视频等大数据文件的传输和存储中,哈夫曼编码被广泛使用。
总结:哈夫曼编码与译码是一种基于字符频率的编码方法,可以有效地压缩数据。
通过统计字符频率、构建哈夫曼树、生成编码表等步骤,可以实现对数据的编码和译码。
哈夫曼编码在数据压缩领域有着广泛的应用,可以大大减小数据的存储空间,提高数据传输的效率。
哈夫曼编码译码
哈夫曼编码译码哈夫曼编码译码编码与译码是信息传输的两个基本环节,哈夫曼编码是一种基于数据压缩的编码方式,能够有效减小数据传输时所需的带宽和存储空间,广泛应用于图像、音频、视频等大数据的传输和存储中。
本文将从哈夫曼编码的定义、算法及其应用等三个方面进行探讨。
一、哈夫曼编码的定义哈夫曼编码,又称为变长编码或最优编码,是一种通过树形结构来实现数据压缩的编码方式。
其算法的基本思想是:对于频率高的字符,分配较短的编码;对于频率低的字符,分配较长的编码。
这样,可以减小数据传输时所需要的带宽和存储空间。
二、哈夫曼编码的算法哈夫曼编码的算法分为两个步骤:建立哈夫曼树和生成编码。
1. 建立哈夫曼树:首先将每个字符看作独立的一个节点,然后根据字符出现的频率来构建哈夫曼树。
具体的方法是:对于给定的一组字符,计算其出现的频率,并将其按照频率的大小进行排序。
然后将频率最小的两个字符合并为一个节点,该节点的频率为两个字符的频率之和,并将该节点插入到集合中。
重复此过程,直到集合中只剩下一个节点,即构建出了哈夫曼树。
2. 生成编码:从根节点开始,遍历树的所有节点(左子树编码为0,右子树编码为1),并记录所有节点对应的字符编码。
这样,每个字符就可以表示为一串01序列,其中该序列的长度越小,表示该字符在原数据中出现的频率越高。
三、哈夫曼编码的应用哈夫曼编码在数据压缩、网络传输、存储优化等领域都有广泛的应用。
1. 数据压缩:哈夫曼编码可将文件的体积减小到原来的三分之一左右,从而有效地减小文件的传输和存储所需要的空间。
2. 网络传输:在网络传输中,带宽和传输速率是非常宝贵的资源。
哈夫曼编码可以将传输的数据压缩到最小,从而减小网络传输的时间和成本。
3. 存储优化:在资源有限的设备上,如手机、PDA等,存储空间通常是一个非常重要的考虑因素。
使用哈夫曼编码技术,可以减小存储所需的空间,从而为设备的其他功能留出更多的空间。
总之,哈夫曼编码是一种非常重要的编码方式,广泛被应用于数据传输和存储中。
哈夫曼编码和译码运行与调试分析
哈夫曼编码和译码运行与调试分析
哈夫曼编码和译码是一种常用的数据压缩算法,以下是其运行、调试和分析的步骤:
1. 运行:
- 首先,根据待压缩的数据,构建哈夫曼树。
- 根据哈夫曼树,生成编码表,即每个字符对应的二进制编码。
- 将待压缩数据按照编码表转换为二进制编码序列。
- 将二进制编码序列存储或传输,实现数据压缩。
2. 调试:
- 检查构建哈夫曼树的过程:确认权重和频率计算是否正确,检查树的构建过程是否存在错误。
- 核对编码表:确保每个字符的编码是否唯一且正确,检查编码表的生成过程是否存在错误。
- 验证压缩结果:按照编码表将压缩后的二进制编码序列还原为原始数据,与原始数据进行对比,确保压缩结果的正确性。
3. 分析:
- 计算压缩率:压缩率可以通过压缩前后数据的长度比值来计算,压缩率越高,表示算法的效果越好。
- 分析运行时间:可以根据输入数据的规模,通过调试工具或代码统计,对哈夫曼编码和译码的运行时间进行分析,评估其效率。
- 对比其他压缩算法:可以将哈夫曼编码与其他压缩算法进行对比,比如LZW算法或gzip 等,评估其压缩效果和性能。
以上是对哈夫曼编码和译码运行、调试和分析的一般步骤,具体实现还需根据算法的具体实现代码和环境进行适配。
- 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调试分析在写程序和调试的过程中,在对函数的理解及调用、参数的传递等方面遇到了很多的麻烦和困难;但最终在同学和老师的帮助下,我最终找出了程序中的错误并将其修改正确,通过分析,我学到了很多。