赫夫曼编码实现
来源:互联网 发布:域名在哪里购买 编辑:程序博客网 时间:2024/06/06 02:34
断断续续的用了两天时间,终于把传说中的赫夫曼树实现了,之前早都听说过,可是都被题目的难度给吓到了,这次有了前面的经验,决心要把赫夫曼编码实现。(当然其实应该也没有太大难度,但是对于我这么一个本科时候数据结构学的那么渣的人来说,能写出来还是有一点成就感的。)
首先,赫夫曼(Huffman)树:带权路径长度最小的二叉树。
赫夫曼算法:
1.根据给定的n个权值构成n棵二叉树的集合F,其中每棵二叉树只有一个带权为wi的根节点,其左右子树均空。
2.选择两棵根节点权值最小的树作为左右子树(这里有没有顺序?较小的靠左?为了统一规范,下面约定,较小的树为左子树)构造一棵新的二叉树,且置新的二叉树的根节点的权值为其左右子树根节点的权值之和。
3.在F中删除这两棵树,同时将新得到的二叉树加入F。
4.重复2和3,直到F只含一棵树为止。这棵树便是赫夫曼树。
下面给出赫夫曼编码的代码:
#include<stdio.h>#include<stdlib.h>#include<string.h>#define MAX 10000;typedef struct HTnode{ unsigned int weight; unsigned int parent,lchild,rchild;}HTNode,*HuffmanTree;typedef char* *HuffmanCode;HuffmanCode HC;char* cd;int SelectMin(int n,int *p){ int min=100; int *q; int m,i; q=p; /* for(i=0;i<n;i++) { printf("%d",i); // p=p+i;//这样赋值第三个值是错误的,不知为什么 printf("%d",*(p+i)); }*/ for( i=0;i<n;i++) { if(*(p+i)<min){ min=*(p+i);} } //printf("%d",min); for( i=0;i<n;i++) {// q=q+i;//不能这样写,否则最后一个会出问题,但不知为什么 if(*(q+i)==min){ m=i+1; break;} } return m;}void creatHuffmanTree(int n,int *w){ if(n<=1) return; int m=2*n-1;//有m个节点,要分配m个节点的空间 int i,c,f; int s1,s2,weight1,weight2,start; HuffmanTree HT,p,temp,s; int *q; q=w; HT=(HuffmanTree)malloc((m+1)*sizeof(HTNode));//第一个单元不用,从HT的下一个单元开始分配,每个节点对应一个 p=HT+1; s=HT+1; temp=HT; for( i=0;i<n;i++) { (s+i)->weight=*(w+i);(s+i)->lchild=0;(s+i)->rchild=0;(s+i)->parent=0; } for(i=n+1;i<=m;i++) { (s+i-1)->weight=0; (s+i-1)->lchild=0; (s+i-1)->rchild=0; (s+i-1)->parent=0; // p++;//此时p指向下一个未分配的单元 } for(i=n+1;i<=m;i++){ s1=SelectMin(m,q); for(int j=0;j<s1;j++) { temp++; q++; } temp->parent=i;temp->weight=*(q-1);weight1=temp->weight;*(q-1)=MAX;temp=HT;q=w;s2=SelectMin(m,q);for( j=0;j<s2;j++){ temp++; q++;}temp->parent=i;temp->weight=*(q-1);weight2=temp->weight;*(q-1)=MAX;temp=HT;q=w;for( j=0;j<i;j++){ temp++; q++;}temp->lchild=s1;temp->rchild=s2;temp->weight=weight1+weight2;*(q-1)=temp->weight;temp=HT;q=w;}//赫夫曼树构造完毕,从叶子节点逆向求每个字符的赫夫曼编码for(int k=1;k<=m;k++){ printf("%d",(HT+k)->weight); printf("%d",(HT+k)->parent); printf("%d",(HT+k)->lchild); printf("%d\n ",(HT+k)->rchild);}HC=(HuffmanCode)malloc((n+1)*sizeof(char*));//HC指向头指针cd=(char*)malloc(n*sizeof(char));//分配输入字符的内存cd[n-1]='\0';int j;for(i=1;i<=n;i++){ start=n-1;//每个字符对应编码的结束符位置 c=i; for( j=0;j<c;j++) { temp++; } f=temp->parent; temp=HT; while(f!=0) { for( j=0;j<f;j++) { temp++; } if(temp->lchild==c){ start--; cd[start]='0';}else{ start--; cd[start]='1';} c=f;f=temp->parent; temp=HT; } *(HC+i)=(char*)malloc((n-start)*sizeof(char)); strcpy(*(HC+i),&cd[start]); int k=0; while(*(*(HC+i)+k)!='\0') { printf("%c",*(*(HC+i)+k)); k++; } printf("\n");}}int main(){ int n,m,a; int *p,*q,*temp; printf("请输入字符个数"); scanf("%d",&n); m=2*n-1; p=(int *)malloc(m*sizeof(int)); q=p; for(int i=0;i<m;i++) {printf("请输入这个字符对应的权重"); scanf("%d",&a);*(p+i)=a; } creatHuffmanTree(n,p); return 0;}
通过这次代码的实现,其实有很多学习的地方:
1.strcpy函数的使用
2.分配完编码的工作空间后可以直接使用数组访问,如cd[n-1]
3.双重指针,有点绕
4.编码的规范和效率,细节问题,如题目中有一处赋值出错,导致调试了好半天
到这里,差不多工作也完成了,但是还是感觉有好多问题没有搞清楚,比如指针和数组的关系,比如指针赋值出错。最近的工作重心逐渐从Java,android转移到c过来了,不知道这样好不好,但每次完成一个算法,还是很有成就感的。
对待生活中的人和事要宽容,但是对待代码必须苛刻,认真谨慎,精益求精。现在可能还处在c的初级阶段,关于内存优化的问题还没有接触到,慢慢来吧,不要想太多结果,走好眼前的路就对了。
坚持跑步,坚持coding!
今天是618,各大网购网站又开始促销了,在京东上买了两百多东西,有满减100,一直没搞明白,这些电子网站是靠什么盈利的。
补充:
今天早上来回过头来看了一下,发现赫夫曼实现中有些地方实现复杂了,类似于:
HT=(HuffmanTree)malloc((m+1)*sizeof(HTnode));都可以直接用数组的形式HT[i]访问其第i+1个单元,以上代码中都用了指针的形式。其实数组和指针的关系还不是很清楚。
数组名就是首地址。一维数组名可以当做指针直接传递
- 赫夫曼编码和实现
- 赫夫曼编码实现
- hufuman 编码实现(赫夫曼编码)
- 【关于赫夫曼编码java实现】
- 赫夫曼编码原理与实现
- 赫夫曼编码C语言实现
- huffman(赫夫曼编码)之C/C++实现
- 赫夫曼树、赫夫曼编码和JAVA实现
- 赫夫曼编码(优先队列实现)
- 赫夫曼编码(基于赫夫曼树的实现)
- huffman编码实现
- c#实现escape编码
- Huffman编码的实现
- URL编码简单实现
- oracle实现PDU编码
- java实现密码编码
- Quoted-Printable编码实现
- 霍夫曼编码c++实现
- Ibatis
- C语言指针总结
- 计算最大公因数
- Android WebView不能显示图片问题
- 黑马day05 jsp语法相关知识
- 赫夫曼编码实现
- POJ3186:Treats for the Cows
- Uva - 712 - S-Trees
- java中包的命名
- cvLoadImage无法载入图像,返回空指针
- Windows 2008R2部署Win 7/2008R2+Office2010(+2013)+Win 8/2012(+win8.1/2012R2) KMS激活服务器
- JAVA五子棋项目总结
- Linux常用指令
- Java并发编程-26-异步运行任务