霍夫曼编码实验三.docx
- 文档编号:17695308
- 上传时间:2023-04-24
- 格式:DOCX
- 页数:14
- 大小:68.36KB
霍夫曼编码实验三.docx
《霍夫曼编码实验三.docx》由会员分享,可在线阅读,更多相关《霍夫曼编码实验三.docx(14页珍藏版)》请在冰豆网上搜索。
霍夫曼编码实验三
霍夫曼编码形式不唯一,但是编出来的码平均码长唯一,上述比较可以看出,平均码长相同,程序正确
C语言代码
//包含的头文件
#include
#include
#include
#include
#include
#include
structHTNode
{//压缩用Huffman树结点
unsignedlongweight;//字符频度(权值)
unsignedintparent,lchild,rchild;
};
typedefcharElemType;
typedefstruct
{
ElemTypeelem;
unsignedintm_weight;
unsignedintparent,lchild,rchild;
}HTNode,*HuffmanTree;//Huffman树对应结点
typedefchar**HuffmanCode;
typedefintStatus;
typedefstructweight
{
charelem;
unsignedintm_weight;
}Weight;//符号及其出现次数
intbits;//记录实际比特数,清空缓冲区
charchl;//字节
intlbits;
voidHuffmanCoding(HuffmanTree*,HuffmanCode*,Weight*,int);//Huffman编码算法
voidSelect(HuffmanTree,int,int*,int*);//选择结点
voidOutputHuffmanCode(HuffmanTree,HuffmanCode,int);//Huffman编码输出
intNToBits(unsignedintnum);//0~num之间的整数用二进位表示所需的最少位数
Statusmain(void)
{
HuffmanTreeHT;
HuffmanCodeHC;
Weight*w;
charc;//符号
unsignedinti;//用于循环
chary;
unsignedintn;//符号数
intwei;//符号对应的个数
inttotal=0;
intnum;
floattnum,xx;
printf("请输入Huffman树的符号数:
");
scanf("%d",&n);
w=(Weight*)malloc(n*sizeof(Weight));//为w分配连续的内存空间
printf("请输入符号及其个数:
");
for(i=0;i { scanf("%1s%d",&c,&wei); w[i].elem=c; w[i].m_weight=wei; total+=w[i].m_weight; } printf("压缩前源文件字符个数总数为: %d\n",total); HuffmanCoding(&HT,&HC,w,n);//进行Huffman编码 OutputHuffmanCode(HT,HC,n);//输出Huffman编码 num=0; for(i=0;i { num+=strlen(HC[i+1])*w[i].m_weight;//计算编码后的长度 } tnum=num; xx=tnum/total; num=ceil(tnum/8); printf("压缩后总字符字节数为: %d\n",num); printf("压缩后平均码长为: %f\n",xx); return1; } intNToBits(unsignedintnum)//0~num之间的整数用二进位表示所需的位数 { unsignedintl=0,power=1; while(power<=num){ l++;power=power*2; } returnl; } voidHuffmanCoding(HuffmanTree*HT,HuffmanCode*HC,Weight*w,intn)//Huffman编码算法 { inti,m,s1,s2,start,c,f; char*cd; //HuffmanTreep; if(n<=1) return; m=2*n-1; //在内存为*HT分配长度为m+1个HTNode结构体大小的连续空间 (*HT)=(HuffmanTree)malloc((m+1)*sizeof(HTNode)); //初始化HuffmanTree前n个节点 for(i=1;i<=n;++i) { (*HT)[i].elem=w[i-1].elem; (*HT)[i].m_weight=w[i-1].m_weight; (*HT)[i].parent=(*HT)[i].lchild=(*HT)[i].rchild=0; } //初始化HuffmanTree前n+1到m节点 for(;i<=m;++i) { (*HT)[i].elem='0'; (*HT)[i].m_weight=(*HT)[i].parent=(*HT)[i].lchild=(*HT)[i].rchild=0; } //构造Huffman for(i=n+1;i<=m;++i) { Select(*HT,i-1,&s1,&s2); (*HT)[s1].parent=i; (*HT)[s2].parent=i; (*HT)[i].lchild=s1; (*HT)[i].rchild=s2; (*HT)[i].m_weight=(*HT)[s1].m_weight+(*HT)[s2].m_weight; } //在内存为*HT分配长度为n个char大小的连续空间 (*HC)=(HuffmanCode)malloc(n*sizeof(char*)); cd=(char*)malloc(n*sizeof(char));//为cd分配n个char占的空间大小 cd[n-1]='\0'; //为每个叶子结点进行编码 for(i=1;i<=n;++i) { start=n-1; //从叶子结点开始向上搜索,如果它是其父结点的左孩子,则其编码为0,否则为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]);//将结点的编码首地址保存到HC中 } } //选择出权值最小并且父亲结点的权值为0的2个结点 voidSelect(HuffmanTreeHT,intn,int*s1,int*s2) { inti; (*s1)=(*s2)=0;//初始化s1和s2 for(i=1;i<=n;i++) { if(HT[i].m_weight =0) { if(HT[i].m_weight { (*s2)=(*s1); (*s1)=i; } else (*s2)=i; } if(((*s1)==0||(*s2)==0)&&HT[i].parent==0)//为s1和s2初始植入结点 { if((*s1)==0) (*s1)=i; elseif((*s2)==0) { if(HT[i].m_weight { (*s2)=(*s1); (*s1)=i; } else(*s2)=i; } } } if((*s1)>(*s2)) { i=(*s1); (*s1)=(*s2); (*s2)=i; } return; } //Huffman编码输出 voidOutputHuffmanCode(HuffmanTreeHT,HuffmanCodeHC,intn) { inti; printf("\n序号符号权重huffman编码\n"); for(i=1;i<=n;i++) { printf("%d%c%d%s\n",i,HT[i].elem,HT[i].m_weight,HC[i]); } } MATLAB验证 clearall; fid=fopen('d: \sy3\a.txt','r'); cc=fread(fid); fclose(fid); len=length(cc); %计算各字符出现的次数. R=zeros(2,256); R(1,: )=0: 255; fork=1: len count=cc(k); count=count+1; R(2,count)=R(2,count)+1; end %将字符与相应出现的次数对应存储. num=0; fork=1: 256 ifR(2,k)~=0 num=num+1; end end Q=zeros(2,num); ct=1; fork=1: 256 ifR(2,k)~=0 Q(1,ct)=R(1,k); Q(2,ct)=R(2,k); ct=ct+1; end end Q1=sort(Q) Q2=Q1(1,: )%输出统计字符个数 Q3=Q1(2,: ); Q4=char(Q3)%输出字符 p1=Q(2,: ); p1=sort(p1) p=p1/len%给出具体信源的概率分布p %--------PART1----------- if(length(find(p<0))~=0) error('Notaprob,negativecomopent'); end if(abs(sum(p)-1)>10e-10) error('Notaprob.vector,componentdonotaddto1') end %------------------------- %这部分主要是判断信源概率分布是否合法,及要求非负,相加和为1 %------------------------- %-------PART2------------- n=length(p);%n为信源长度及信源元素的个数 q=p; m=zeros(n-1,n);%构造(n-1)行,n列的m矩阵 fori=1: n-1 [q,l]=sort(q);%对信源概率从小到大排列 m(i,: )=[l(1: n-i+1),zeros(1,i-1)];%m矩阵的每行记录每次排序后的概率次序 q=[q (1)+q (2),q(3: n),1];%将概率最小的两项合并 end %------------------------------------- %这部分通过m矩阵记录了信源P及每次重新排序后缩减信源的概率分布情况 %即完成HUFFUMAN编码步骤中 (1)~(4) %-------------------------------- %-----------PART3---------------- fori=1: n-1 c(i,: )=blanks(n*n);%矩阵的第i行为N*N列的空矩阵 end %------------------------------- %c为(n-1)行,n*n列的空矩阵。 每个信源的编码长度不会超过信源符号的个数 %c记录了按反序得到编码的过程 %------------------------------------ %-----------PART4--------------------- c(n-1,n)='0'; c(n-1,2*n)='1'; fori=2: n-1 c(n-i,1: n-1)=c(n-i+1,n*(find(m(n-i+1,: )==1))... -(n-2): n*(find(m(n-i+1,: )==1))); c(n-i,n)='0'; c(n-i,n+1: 2*n-1)=c(n-i,1: n-1); c(n-i,2*n)='1'; forj=1: i-1 c(n-i,(j+1)*n+1: (j+2)*n)=c(n-i+1,... n*(find(m(n-i+1,: )==j+1)-1)+1: n*find(m(n-i+1,: )==j+1)); end end %-------------------------------- %这部分是具体的编码过程,也是程序的核心,及HUFFMAN编码步骤中的(5) %---------------------------------- %-----------PART5--------------------- fori=1: n h(i,1: n)=c(1,n*(find(m(1,: )==i)-1)+1: find(m(1,: )==i)*n); ll(i)=length(find(abs(h(i,: ))~=32)); end%得到各个信源对应的编码及码长 xx=sum(p.*ll)%得到并输出平均码长 h%输出信源对应的码 ll%输出信源对应的编码符号码长 hx=-p*log2(p')%输出信源的熵 At=hx/xx%输出编码效率 %------------------------------------
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 霍夫曼 编码 实验
![提示](https://static.bdocx.com/images/bang_tan.gif)