哈夫曼编码
来源:互联网 发布:linux 安装nginx 编辑:程序博客网 时间:2024/06/11 22:34
这是我第一篇,之前写这个真是一脸懵,只记得我9点写到第二天四点 我不喜欢我的程序因为用户输入了一些特殊的情况就挂 所以一个程序无论多小我都会加上排错的函数。
这个代码可以输出哈夫曼形成的二叉树(好像不能称为树,管他呢)。感觉还是不错的··~
不多说上代码:
# include <stdio.h># include <stdlib.h># include <string.h># define N 1001 //如果想录入x个字节那么就把N的数值改成x+1 x>3# define M 13 //哈夫曼树编码的长度typedef struct ptree //定义二叉树结点类型{struct ptree *lchild; //左0右1子结点指针struct ptree *rchild; //右子结点指针int w; //w[2]存储节点权值char zha[2]; }Ptree,*Optree; //optimum tree typedef struct pforest //每个此类结构体连接一个二叉树与另一个此类结构体{struct pforest *link; //连接每个叶子节点节点权值由大到小排列struct ptree *root; //指向叶子节点}Forest,*forest;int gainchar(char *a,int min,int max);//返回字符长度int jianyan(char *ch,int type[3]);//检验字符串是否合法合法的话type[0]=大写字母个数,type[1]=小写字母个数,type[2]=数字字符个数int BFS(char *a,char *b);//字符串匹配返回匹配的个数//我还有返回所有匹配的下表的函数int zhengli(char b[],char *p,int *q);//整理字符串,所有可以出现的字符整理到p里,p[i]的次数储存在q[i]中,返回字符串中不同的个数Optree hafman(int n,char m[],int w[]);//构造哈夫曼树,权值存在w[]中,返回树根pforest *inforest(forest f,Optree t);//将每个二叉树连接起来.根据每个二叉树的根节点的权值大小,将二叉树权值由大到小相接void shuxing(Optree &p,int len);//输出树的形状,形参len=0;void tiaozheng(int a);//根据位数调整枝杈长度,嵌套在shu函数里,主函数中不调用int bianma(Optree p,int a,char b[]);//对哈夫曼树进行编码,返回哈夫曼树的权值void main(){ int a=0,d,k;char b[N],*p=NULL;char kkk[M]={"\0"};int type[3]={0,0,0},*q=NULL;//type[0]=大写字母个数type[1]=小写字母个数type[2]=数字字符个数 Optree head; do{printf("输入字符串<只录入字母或数字>(2--%d)字节:",N-1);d=gainchar(b,2,N); //d=b的字符长度}while(!jianyan(b,type)); //检验不合法时返回0q=(int *)calloc(d,sizeof(int)); //申请 p=(char *)calloc(d+1,sizeof(char)); //申请k=zhengli(b,p,q); //整理字符串printf("大写字母:%d小写字母:%d数字:%d 共%d个字符 字符种类%d 种\n注:X<<Y+<< X为出现的次数 Y为字符!\n",type[0],type[1],type[2],d,k);head=hafman(k,p,q); //构造哈夫曼树printf("①--②--③--④--⑤--⑥--⑦--⑧--⑨--⑩--①--②\n");shuxing(head,0); //显示树的形状 printf("总权值WPL=%d",bianma(head,0,kkk));getchar();//暂停一下free(p);free(q); //此处可以改造一下bianma()函数让其释放哈夫曼树,我就不改了有时间再改}Optree hafman(int n,char m[],int w[])//构造哈夫曼树,权值存在w[]中,返回树根{forest p1,p2,froot;Optree leaves,t;froot=(forest)malloc(sizeof(Forest));//建立一个根节点froot->link=NULL; while(n-->0) //产生n个叶子{leaves=(Optree)malloc(sizeof(Ptree));//开辟新的叶子结点leaves->w=w[n]; //给叶子结点赋权值leaves->zha[0]=m[n]; //将字符存在叶子节点里leaves->rchild=leaves->lchild=NULL; //叶子初始化froot=inforest(froot,leaves); //按权值从大到小的顺序将叶子结点从froot树根向下排列,权值小的放在最后 }while(((froot->link)->link)!=NULL)//上面将叶子进行了初步排列,之后要对叶子进行合并,从树根开始两个两个的进行合并{p1=froot->link; //p1指向第一片叶子p2=p1->link; //p2指向第二片叶子 经过inforest排列后权值p1>=p2froot->link=p2->link; //froot指向第三片叶子t=(Optree)malloc(sizeof(Ptree)); //开辟新的结点t->w=(p1->root->w)+(p2->root->w); //权相加t->lchild=p1->root; //将叶子整合到t上t->zha[0]='<';t->rchild=p2->root; //产生新二叉树froot=inforest(froot,t); //将新的二叉树t整合到树干上free(p1); //释放p1所指的内存free(p2); //释放p2}t=froot->link->root; //当froot指向的最后一个节点link时此时的link节点已经是全部排列好的hafuman树free(froot); //去掉froot留下树叉return(t); //返回二叉树的树根}pforest *inforest(forest f,Optree t)//将每个二叉树连接起来.根据每个二叉树的根节点的权值大小,将二叉树权值由大到小相接{ forest p,q,r;r=(forest)malloc(sizeof(Forest)); //开辟新的树干结点r->root=t; //将其叶子指针指向新加入的叶子tq=f; //q指向根p=f->link; //p指向根的下一个位置 while (p!=NULL) //当整个树干没有到头时{if(t->w> p->root->w) //如果t的权值大于ti的权值{q=p; //q移到p的位置p=p->link; //p向后寻找}elsep=NULL; //新插入的t<=某个位置的权,将在位置插入此节点,跳出while循环}r->link=q->link; //r的下个节点指向q的后序节点q->link=r; //r接在q的后面return(f); //返回树根f}void shuxing(Optree &p,int len)//输出树的形状,形参len=0;{int i;if (p!=NULL){shuxing(p->rchild,len+1); //递归for (i=1;i<=4*len;i++) printf("%c",i%4-1?' ':'|');printf("%d<%c",p->w,p->zha[0]); //输出数据tiaozheng(p->w); //根据数据的大小调整树叉的长度shuxing(p->lchild,len+1); //递归}}void tiaozheng(int a)//根据位数调整枝杈长度,嵌套在shu函数里{char cha[4][6]={"<--+<","<+<","<<","<"};int k=0;while(a){ a/=10; k++;}printf("%s\n",cha[k]);}int gainchar(char *a,int min,int max)//对*a输入范围[min,max-1]{ int c,k;do{c=-1;k=0;fgets(a,max,stdin); while(a[++c]);c=a[c-1]=='\n'&&c<max?c-1:c;if(c>=max-1)while(getchar()!='\n') //判断缓冲区是否还有未读取的字符k++;elsea[c]='\0'; if(k||c&&c<min)printf("输入长度有误,请重新输入!\n注:只录入(%d--%d)字节:\n",min,max-1);}while(k||c<min); return c;}int jianyan(char *ch,int type[3])//判断字符是否合法,合法返回1,不合法返回0{char a[][3]={"AZ","az","09"};//对可能出现的字符进行判断int b[2]={0,0},i,j;b[0]=strlen(ch);for(i=0;i<b[0];i++){for(j=0;j<3;j++)if(ch[i]<=a[j][1]&&ch[i]>=a[j][0]){b[1]++; type[j]++;}if(!b[1]){printf("输入的字符中有除字母和数字以外的字符!\n请重新");type[0]=type[1]=type[2]=0;return 0;}else b[1]=0;}return 1;}int BFS(char *a,char *b)//a为主串,b为被检验的串,d为匹配的下标,经典算法,不再写注释{ int c[2];int i=0,j=0,k=0;c[0]=strlen(a);c[1]=strlen(b); //c[0]c[1]存长度while (i <=c[0])if(a[i]==b[j]&&j<c[1]){i++;j++;}else{ if(j==c[1]) k++; elsei-=j-1; j=0;}return k; //返回匹配的个数k}int zhengli(char b[],char *p,int *q) //对重复的进行整理{int i,k,length;char spot[2]={"\0"}; length=strlen(b); for(i=0,k=0;i<length;i++){ spot[0]=b[i]; //每个字符串复制到spot中进行字符串匹配if(!BFS(p,spot)) //如果匹配失败,则说明此字符串第一次出现,就将其放在数组p里 {q[k]=BFS(b,spot); p[k++]=spot[0]; }}return k; //返回不相同的总个数}int bianma(Optree p,int a,char b[]) //初始化a=c=0;{ int static c=0; //设置静态变量c if(p) { if(p->lchild) //是左侧{b[a]='0'; //左零右一 bianma(p->lchild,a+1,b); //继续遍历} if(p->rchild){b[a]='1'; //左零右一 bianma(p->rchild,a+1,b); //继续遍历} if(p->zha[0]!='<') //如果是树叶{ b[a]='\0'; printf("%-13s\"%c\" %03d次\n",b,p->zha[0],p->w); //输出编码和字符c+=a*p->w; //计算权值} } return c; //返回静态变量}/*制作者zha good well输入一段字符串对字符串的字符种类和个数进行整理,并输出编码值哈夫曼编码*/
3 0
- 信源编码---哈夫曼编码
- 哈夫曼编码
- 哈夫曼编码
- 哈夫曼编码
- 哈夫曼编码
- 哈夫曼编码
- 哈夫曼编码
- 哈夫曼编码
- 哈夫曼编码
- 哈夫曼编码
- 哈夫曼编码
- 哈夫曼编码
- 哈夫曼编码
- 哈夫曼编码
- 哈夫曼编码
- 哈夫曼编码
- 哈夫曼编码
- 哈夫曼编码
- FFMpeg 解码标准电影文件 时间计算方式
- 【资源分享】Axure.RP.v8.0.0 界面原型设计软件
- Android 屏幕适配和版本适配
- 跨浏览器的事件处理程序
- Toolbar使用小结
- 哈夫曼编码
- 希尔排序
- C动态字符串,动态开辟内存空间相关 malloc realloc 用法
- HttpURLConnection用法详解
- [jQuery知识]jQuery之知识十一-动画高级
- 第21篇 ninja的安装(二)周日
- Android 读取doc文件
- C动态字符串,动态开辟内存空间相关 malloc realloc 用法
- 在windows运行python