数据结构:哈夫曼树,哈夫曼编码与译码系统
2016-02-13 20:09
537 查看
1).结构体类型 HaffmanfT:
typedefstruct{
int weight;
char ch;
char chh[20];
int lchild;
int rchild;
int parent;
}HaffmanT;/*结点结构体*/
2). (字母部分用的结构体)结构体类型 HaffmanfN
typedefstruct
{
char ch;
char bits[MB + 1];
int start;//标志编码起始位
}HaffmanN;/*保存编码*/
3 ).单词部分的储存编码和权值用了三个数组(全局变量):
charstr2[MB][20];//单词字串
charstr3[MB][20];//输入串
intstrC[MB];//单词字串计数数组.对应每个单词串,拥有一个计算器
4). (全局变量)charmi[MAXPLUS];//存放的是字符串编码
charcha[MAXPLUS];//存放的是句子
2.
实验所用到的全部函数有:
1).voidstrCount();//统计字母并计算每个字母出现的次数即权值
2).intwordCount();//统计单词并计算每个单词出现的次数即权值,返回出现的不同单词个数
3).void init(intn);//初始化
4).voidgetHaff(int n,int p);//把字母(单词)及权值保存到结构体中,n决定单词还是字母,p决定了结构体数组的大小
5).int creat2(int n);//创建哈夫曼树
6).voidCharSetHuffmanEncoding(int n,int wh);//给每一个结点编码,n代表结点个数
7).void bianma(intwh,int p);//给从文件中读到的文章整体编码,即压缩
8).void wriIn();//将对文件的编码写入新的TXT文档
9).void yima(intn,int wh); //将哈夫曼编码解码为原文档
10).int main();//综合调用并计算压缩率
详细代码如下:
typedefstruct{
int weight;
char ch;
char chh[20];
int lchild;
int rchild;
int parent;
}HaffmanT;/*结点结构体*/
2). (字母部分用的结构体)结构体类型 HaffmanfN
typedefstruct
{
char ch;
char bits[MB + 1];
int start;//标志编码起始位
}HaffmanN;/*保存编码*/
3 ).单词部分的储存编码和权值用了三个数组(全局变量):
charstr2[MB][20];//单词字串
charstr3[MB][20];//输入串
intstrC[MB];//单词字串计数数组.对应每个单词串,拥有一个计算器
4). (全局变量)charmi[MAXPLUS];//存放的是字符串编码
charcha[MAXPLUS];//存放的是句子
2.
实验所用到的全部函数有:
1).voidstrCount();//统计字母并计算每个字母出现的次数即权值
2).intwordCount();//统计单词并计算每个单词出现的次数即权值,返回出现的不同单词个数
3).void init(intn);//初始化
4).voidgetHaff(int n,int p);//把字母(单词)及权值保存到结构体中,n决定单词还是字母,p决定了结构体数组的大小
5).int creat2(int n);//创建哈夫曼树
6).voidCharSetHuffmanEncoding(int n,int wh);//给每一个结点编码,n代表结点个数
7).void bianma(intwh,int p);//给从文件中读到的文章整体编码,即压缩
8).void wriIn();//将对文件的编码写入新的TXT文档
9).void yima(intn,int wh); //将哈夫曼编码解码为原文档
10).int main();//综合调用并计算压缩率
详细代码如下:
//#include "stdafx.h" #include "stdio.h" #include "stdlib.h" #include "string.h" #include "io.h" #define MB 300//最大编码的值 #define MAXPLUS 100000 typedef struct{ int weight; char ch; char chh[20]; int lchild; int rchild; int parent; }HaffmanT;/*结点结构体*/ HaffmanT T[MB]; HaffmanT TW[MB]; typedef struct { char ch; char bits[MB + 1]; int start;//标志编码起始位 }HaffmanN; HaffmanN N[MB]; char str2[MB][20];//单词字串结果存放数组 char str3[MB][20];//输入串或者用char *str2也可,这样可以 int strC[MB];//单词字串计数数组.对应每个单词串,拥有一个计算器 char mi[MAXPLUS];//存放的是字符串编码 char cha[MAXPLUS];//存放的是句子 void strCount();//统计字母并计算每个字母出现的次数即权值 int wordCount();//统计单词并计算每个单词出现的次数即权值,返回出现的不同单词个数 void init(int n);//初始化 void getHaff(int n,int p);//把字母(单词)及权值保存到结构体中,n决定单词还是字母,p决定了结构体数组的大小 int creat2(int n);//创建哈夫曼树 void CharSetHuffmanEncoding(int n,int wh);//给每一个结点编码,n代表结点个数 void bianma(int wh,int p);//给从文件中读到的文章整体编码,即压缩 void wriIn();//将对文件的编码写入新的TXT文档 void yima(int n,int wh); //将哈夫曼编码解码为原文档 int main() { int t,k,cho; strCount(); k=wordCount(); int n = 29; printf("请选择编码:0,单词,1字母\n"); scanf("%d",&cho); if(cho==0) { printf("你输入了”0“,将给出单词的频率及相应的哈夫曼编码\n"); getHaff(cho,k); creat2(k); CharSetHuffmanEncoding(k-1,cho);//k-1 printf("是否压缩:1:是,0:否:\n"); scanf("%d",&cho); if(cho==0) return 0; if(cho==1) { printf("接下来是压缩环节\n"); bianma(cho,k); wriIn(); } printf("是否解压缩:1:是,0:否:\n"); scanf("%d",&cho); if(cho==0) return 0; if(cho==1) { yima(k,cho); } printf("\n"); printf("计算压缩率:\n"); double ee=(double)strlen(mi)/(strlen(cha)*8); ee=1-ee; printf("压缩率为%.2f",ee*100); printf("%%"); } if(cho==1) { printf("你输入了”1“,将给出字符的频率及相应的哈夫曼编码\n"); getHaff(cho,n); creat2(n); CharSetHuffmanEncoding(n,cho); printf("是否压缩:1:是,0:否:\n"); scanf("%d",&cho); if(cho==0) return 0; if(cho==1) { printf("接下来是压缩环节\n"); bianma(cho,n); wriIn(); } printf("是否解压缩:1:是,0:否:\n"); scanf("%d",&cho); if(cho==0) return 0; if(cho==1) { yima(n,cho); } printf("\n"); printf("计算压缩率:\n"); double ee=(double)strlen(mi)/(strlen(cha)*8); ee=1-ee; printf("压缩率为%.2f",ee*100); printf("%%"); } } //先是统计字符的功能 void strCount(){ FILE * fp; char str1; if((fp=fopen("F:\\untitled\\DataStructure\\实验\\实验二\\aaa.txt","r"))==NULL) { printf("file cannot be opened\n"); exit(1); } int x;//数组下标 for(x=0;x<29;x++) { TW[x].ch='a'+x; TW[x].weight=0; // printf("%c",N[x].ch); } TW[26].ch=' '; TW[27].ch=','; TW[28].ch='.'; x=0; while((str1=fgetc(fp))!=EOF) { //cha[x]+=str1; if(isalpha(str1)) { str1=tolower(str1); ++TW[str1-'a'].weight;//直接用数组的ascii做下标 } else if((int)str1==32) ++TW[26].weight;//这个是空格 else if((int)str1==44) ++TW[27].weight; else if((int)str1==46) ++TW[28].weight; cha[x]=str1; x++; } //fgets(cha,10000,fp); printf("我的句子是:%s\n",&cha); fclose(fp); } //统计单词 int wordCount() { int i=0,j=0,k=0,x,y=0; while(j<strlen(cha)+1) { for(;cha[j]==32||cha[j]==44||cha[j]==46;j++); while(k<20&&cha[j]!=32&&cha[j]!=44&cha[j]!=46) str2[i][k++]=cha[j++]; str3[y][k++]=cha[j++]; str2[i][k]='\0'; strC[i]=1; // strcpy(str3[j],str2[j]); y++; for(x=0;x<i;x++) if(strncmp(str2[i],str2[x],20)==0) { strC[x]++; i--; break; } i++; k=0; //printf("i是%d,值是%s\n",i,str2[i]); } str2[i+1][0]=' '; str2[i+2][0]=','; str2[i+3][0]='.'; return i; } //创建树之前赶紧把权值给搞好 void getHaff(int n,int p)//n是操作符,p是数组大小 { int i=n; int k=p; int c=0; if(i==1) { for(;c<p;c++){ T[c].weight=TW[c].weight; T[c].ch=TW[c].ch;} } if(i==0) { for(c=0;c<p-1;c++) T[c].weight=strC[c]; // strcpy(T[c].chh,str2[c]); // printf("%s,不输出啊吗",T[c].chh); } } //接下来构造一棵哈夫曼树 void init(int n) { int i; for (i = 0; i<2 * n - 1; i++) { //T[i].weight = 0;//权值 T[i].parent = -1; T[i].lchild = -1; T[i].rchild = -1; } } int creat2(int n) { int i, j, p1, p2, w1, w2;//p1,p2分别是最小权值的位置,w1,w2代表最小权值 //初始化结点 int num = n; init(n); //循环构造哈夫曼树 for (i = 0; i<num - 1; i++) { w1 = w2 = 10000; p1 = p2 = 0; for (j = 0; j<num + i; j++)//循环条件 { if (T[j].weight<w1&&T[j].parent == -1) { w2 = w1; p2 = p1; w1 = T[j].weight; p1 = j; } else if (T[j].weight<w2&&T[j].parent == -1) { w2 = T[j].weight; p2 = j; } }//找到了p1,p2两个最小的位置 //printf("%d %d我要看看p的值!\n",p1,p2); T[p1].parent = T[p2].parent = num + i; //找到当前最小的两个节点 确定父节点 T[num + i].lchild = p1; //设置父节点的左右子树和权值 T[num + i].rchild = p2; T[num + i].weight = T[p1].weight + T[p2].weight;//特别注意一下是num+i } return i; } void CharSetHuffmanEncoding(int n,int wh)//n表示多少个节点 { //根据树求编码表 //int n=init(); int c, p, i, j; HaffmanN cd;//临时变量来存放求解编码时的信息 for (i = 0; i < n; i++) { cd.start = n - 1; c = i; while ((p = T[c].parent) != -1) /* 父结点存在 */ { cd.bits[cd.start] = (T[p].lchild == c) ? '0' : '1'; cd.start--; /* 求编码的低一位 */ c = p; } /* end while */ /* 保存求出的每个叶结点的哈夫曼编码和编码的起始位 */ for (j = cd.start + 1; j<n; j++) N[i].bits[j] = cd.bits[j]; N[i].start = cd.start; } /* end for */ /* 输出已保存好的所有存在编码的哈夫曼编码 */ int n1; char temp; for (i = 0; i<n; i++) { if(wh==1){ N[i].ch = T[i].ch; printf("%c 出现的次数是%d,它的编码是: ", T[i].ch,T[i].weight);} //for (n=0) if(wh==0) printf("第%d项,%s 出现的次数是%d,它的编码是: ", i,str2[i],T[i].weight); for (j = N[i].start + 1,n1=0; j < n; j++,n1++) { temp = N[i].bits[j]; N[i].bits[n1] = temp; // printf("%c对比", N[i].bits[j]); printf("%c", N[i].bits[n1]); } //printf(" start:%d", N[i].start); printf("\n"); } } //接下来是给字符串编码 void bianma(int wh,int p) { int n1=strlen(cha); int n2=strlen(str3); int i,j; if(wh==1) { for(i=0;i<=n1;i++) { for(j=0;j<29;j++) { if(cha[i]==N[j].ch) { //mi[i].bits=gets(N[j].bits); printf("%s",N[j].bits); strcat (mi,N[j].bits); break; } } } }else if(wh==0) { for(i=0;i<=n2;i++) { for(j=0;j<p;j++) { if(strncmp(str3[i],T[j].chh,20)==0) { //mi[i].bits=gets(N[j].bits); printf("%s",N[j].bits); strcat (mi,N[j].bits); break; } } } } printf("\n"); } //然后把字符串的码写到文件中 void wriIn() { FILE *pFile = fopen("F:\\untitled\\DataStructure\\实验\\实验二\\aab.txt", //打开文件的名称 "w"); // 文件打开方式 如果原来有内容也会销毁 //向文件写数据 fwrite (mi, //要输入的文字 1,//文字每一项的大小 strlen(mi),//单元个数 pFile //我们刚刚获得到的地址 ); // printf("测试下mi的值%c:\n",mi[0]); fflush(pFile); } //译码的实现 void yima(int n,int wh) { int m = 2*n - 2;//原来是这里!!!!!!!!!! int temp = m; int i = 0; printf("译码:\n"); /*char str[MAXPLUS]; gets(str);*/ //printf("weisheme "); //char str[3]={'0','1'}; //for () while (mi[i] != '\0') { //挨个读入电文 //printf("看一下有没有出粗哦%c第几位%d\n", str[i], i); if (mi[i] == '0') //如果是0进入左子树 如果是1进入右子树 { // printf("is0do"); temp = T[temp].lchild; //printf("现在我的值是:%c\n", T[temp].ch); } else if (mi[i] == '1') temp = T[temp].rchild; if (T[temp].lchild == -1 && T[temp].rchild == -1) { if(wh==1)//如果该节点左右均为空 即到达字母结点 输出 printf("%c", T[temp].ch); else if(wh==0) printf("%s", T[temp].chh); temp = m; //重新回到根节点 进行下一字符的译码 } i++; } getchar(); }
相关文章推荐
- Java数据结构与算法之单链表及简单操作
- 数据结构实验之链表八:Farey序列
- hash(哈希散列) 数据结构-9
- 微软公司数据结构+算法面试题
- 树状数组 (数据结构)
- 数据结构循环队列
- Trie树
- 数据结构 栈和队列
- 数据结构实验之链表七:单链表中重复元素的删除
- 数据结构实验之链表六:有序链表的建立
- 学习笔记------数据结构(C语言版)串的定长顺序存储表示
- 数据结构
- C++自制Redis 数据库(十)数据结构类
- 数据结构实验之链表五:单链表的拆分
- 【数据结构实验】校园游览导图系统
- socket编程 -- 网络字节序、IP地址转换、sockaddr数据结构
- 【LA7402】colorful tree 数据结构
- [数据结构与算法分析] 二叉查找树的基础概念,插入以及删除
- 9.数据结构之二叉树
- 数据结构之三讲--表、栈、队列