五种数据压缩算法.docx
- 文档编号:6861182
- 上传时间:2023-01-11
- 格式:DOCX
- 页数:52
- 大小:97.80KB
五种数据压缩算法.docx
《五种数据压缩算法.docx》由会员分享,可在线阅读,更多相关《五种数据压缩算法.docx(52页珍藏版)》请在冰豆网上搜索。
五种数据压缩算法
⏹哈弗曼编码
A method for the construction of minimum-re-dundancy codes,
耿1数据结构1:
高等教育,2005:
182—190
严蔚敏,吴伟民.数据结构(C语言版)[M].:
清华大学,1997.
桂,林其伟,东华.信息论与编码技术[M].:
清华大学,2007.
大有,唐海鹰,舒,等.数据结构[M].:
高等教育,2001
✧压缩实现
速度要求
为了让它(huffman.cpp)快速运行,同时不使用任何动态库,比如STL或者MFC。
它压缩1M数据少于100ms(P3处理器,主频1G)。
压缩过程
压缩代码非常简单,首先用ASCII值初始化511个哈夫曼节点:
CHuffmanNodenodes[511];
for(intnCount=0;nCount<256;nCount++)
nodes[nCount].byAscii=nCount;
其次,计算在输入缓冲区数据中,每个ASCII码出现的频率:
for(nCount=0;nCount nodes[pSrc[nCount]].nFrequency++; 然后,根据频率进行排序: qsort(nodes,256,sizeof(CHuffmanNode),frequencyCompare); 哈夫曼树,获取每个ASCII码对应的位序列: intnNodeCount=GetHuffmanTree(nodes); 构造哈夫曼树 构造哈夫曼树非常简单,将所有的节点放到一个队列中,用一个节点替换两个频率最低的节点,新节点的频率就是这两个节点的频率之和。 这样,新节点就是两个被替换节点的父节点了。 如此循环,直到队列中只剩一个节点(树根)。 //parentnode pNode=&nodes[nParentNode++]; //popfirstchild pNode->pLeft=PopNode(pNodes,nBackNode--,false); //popsecondchild pNode->pRight=PopNode(pNodes,nBackNode--,true); //adjustparentofthetwopopednodes pNode->pLeft->pParent=pNode->pRight->pParent=pNode; //adjustparentfrequency pNode->nFrequency=pNode->pLeft->nFrequency+pNode->pRight->nFrequency 注意事项 有一个好的诀窍来避免使用任何队列组件。 ASCII码只有256个,但实际分配了511个(CHuffmanNodenodes[511]),前255个记录ASCII码,而用后255个记录哈夫曼树中的父节点。 并且在构造树的时候只使用一个指针数组(ChuffmanNode*pNodes[256])来指向这些节点。 同样使用两个变量来操作队列索引(intnParentNode=nNodeCount;nBackNode=nNodeCount–1)。 接着,压缩的最后一步是将每个ASCII编码写入输出缓冲区中: intnDesIndex=0; //looptowritecodes for(nCount=0;nCount { *(DWORD*)(pDesPtr+(nDesIndex>>3))|= nodes[pSrc[nCount]].dwCode<<(nDesIndex&7); nDesIndex+=nodes[pSrc[nCount]].nCodeLength; } (nDesIndex>>3): >>3以8位为界限右移后到达右边字节的前面 (nDesIndex&7): &7得到最高位. 此外,在压缩缓冲区中,必须保存哈夫曼树的节点以及位序列,这样才能在解压缩时重新构造哈夫曼树(只需保存ASCII值和对应的位序列)。 解压缩 解压缩比构造哈夫曼树要简单的多,将输入缓冲区中的每个编码用对应的ASCII码逐个替换就可以了。 只要记住,这里的输入缓冲区是一个包含每个ASCII值的编码的位流。 因此,为了用ASCII值替换编码,我们必须用位流搜索哈夫曼树,直到发现一个叶节点,然后将它的ASCII值添加到输出缓冲区中: intnDesIndex=0; DWORDnCode; while(nDesIndex { nCode=(*(DWORD*)(pSrc+(nSrcIndex>>3)))>>(nSrcIndex&7); pNode=pRoot; while(pNode->pLeft) { pNode=(nCode&1)? pNode->pRight: pNode->pLeft; nCode>>=1; nSrcIndex++; } pDes[nDesIndex++]=pNode->byAscii; } ✧程序实现 费诺编码 #include #include #include #include #defineM100 typedefstructFano_Node { charch; floatweight; }FanoNode[M]; typedefstructnode { intstart; intend; structnode*next; }LinkQueueNode; typedefstruct { LinkQueueNode*front; LinkQueueNode*rear; }LinkQueue; //建立队列 voidEnterQueue(LinkQueue*q,ints,inte) { LinkQueueNode*NewNode; //生成新节点 NewNode=(LinkQueueNode*)malloc(sizeof(LinkQueueNode)); if(NewNode! =NULL) { NewNode->start=s; NewNode->end=e; NewNode->next=NULL; q->rear->next=NewNode; q->rear=NewNode; } else { printf("Error! "); exit(-1); } } //按权分组 voidDivide(FanoNodef,ints,int*m,inte) { inti; floatsum,sum1; sum=0; for(i=s;i<=e;i++) sum+=f[i].weight;// *m=s; sum1=0; for(i=s;i { sum1+=f[i].weight; *m=fabs(sum-2*sum1)>fabs(sum-2*sum1-2*f[i+1].weight)? (i+1): *m; if(*m==i)break; } } voidmain() { inti,j,n,max,m,h[M]; intsta,end; floatw; charc,fc[M][M]; FanoNodeFN; LinkQueueNode*p; LinkQueue*Q; //初始化队Q Q=(LinkQueue*)malloc(sizeof(LinkQueue)); Q->front=(LinkQueueNode*)malloc(sizeof(LinkQueueNode)); Q->rear=Q->front; Q->front->next=NULL; printf("\t***FanoCoding***\n"); printf("Pleaseinputthenumberofnode: "); //输入信息 scanf("%d",&n); //超过定义M,退出 if(n>=M) { printf(">=%d",M); exit(-1); } i=1;//从第二个元素开始录入 while(i<=n) { printf("%dweightandnode: ",i); scanf("%f%c",&FN[i].weight,&FN[i].ch); for(j=1;j { if(FN[i].ch==FN[j].ch)//查找重复 { printf("Samenode! ! ! \n");break; } } if(i==j) i++; } //排序(降序) for(i=1;i<=n;i++) { max=i+1; for(j=max;j<=n;j++) max=FN[max].weight j: max; if(FN[i].weight { w=FN[i].weight; FN[i].weight=FN[max].weight; FN[max].weight=w; c=FN[i].ch; FN[i].ch=FN[max].ch; FN[max].ch=c; } } for(i=1;i<=n;i++)//初始化h h[i]=0; EnterQueue(Q,1,n);//1和n进队 while(Q->front->next! =NULL) { p=Q->front->next;//出队 Q->front->next=p->next; if(p==Q->rear) Q->rear=Q->front; sta=p->start; end=p->end; free(p); Divide(FN,sta,&m,end);/*按权分组*/ for(i=sta;i<=m;i++) { fc[i][h[i]]='0'; ++h[i]; } if(sta! =m) EnterQueue(Q,sta,m); else fc[sta][h[sta]]='\0'; for(i=m+1;i<=end;i++) { fc[i][h[i]]='1'; ++h[i]; } if(m==sta&&(m+1)==end) //如果分组后首元素的下标与中间元素的相等, //并且和最后元素的下标相差为1,则编码码字字符串结束 { fc[m][h[m]]='\0'; fc[end][h[end]]='\0'; } else EnterQueue(Q,m+1,end); } for(i=1;i<=n;i++)/*打印编码信息*/ { printf("%c: ",FN[i].ch); printf("%s\n",fc[i]); } system("pause"); }[4] 编码解码 #include #include #include #defineN100 #defineM2*N-1 typedefchar*HuffmanCode[2*M];//haffman编码 typedefstruct { intweight;//权值 intparent;//父节节点 intLChild;//左子节点 intRChild;//右子节点 }HTNode,Huffman[M+1];//huffman树 typedefstructNode { intweight;//叶子结点的权值 charc;//叶子结点 intnum;//叶子结点的二进制码的长度 }WNode,WeightNode[N]; /***产生叶子结点的字符和权值***/ voidCreateWeight(charch[],int*s,WeightNodeCW,int*p) { inti,j,k; inttag; *p=0;//叶子节点个数 //统计字符出现个数,放入CW for(i=0;ch[i]! ='\0';i++) { tag=1; for(j=0;j if(ch[j]==ch[i]) { tag=0; break; } if(tag) { CW[++*p].c=ch[i]; CW[*p].weight=1; for(k=i+1;ch[k]! ='\0';k++) if(ch[i]==ch[k]) CW[*p].weight++;//权值累加 } } *s=i;//字符串长度 } /********创建HuffmanTree********/ voidCreateHuffmanTree(Huffmanht,WeightNodew,intn) { inti,j; ints1,s2; //初始化哈夫曼树 for(i=1;i<=n;i++) { ht[i].weight=w[i].weight; ht[i].parent=0; ht[i].LChild=0; ht[i].RChild=0; } for(i=n+1;i<=2*n-1;i++) { ht[i].weight=0; ht[i].parent=0; ht[i].LChild=0; ht[i].RChild=0; } for(i=n+1;i<=2*n-1;i++) { for(j=1;j<=i-1;j++) if(! ht[j].parent) break; s1=j;//找到第一个双亲为零的结点 for(;j<=i-1;j++) if(! ht[j].parent) s1=ht[s1].weight>ht[j].weight? j: s1; ht[s1].parent=i; ht[i].LChild=s1; for(j=1;j<=i-1;j++) if(! ht[j].parent) break; s2=j;//找到第二个双亲为零的结点 for(;j<=i-1;j++) if(! ht[j].parent) s2=ht[s2].weight>ht[j].weight? j: s2; ht[s2].parent=i; ht[i].RChild=s2; ht[i].weight=ht[s1].weight+ht[s2].weight;//权值累加 } } /***********叶子结点的编码***********/ voidCrtHuffmanNodeCode(Huffmanht,charch[],HuffmanCodeh,WeightNodeweight,intm,intn) { inti,c,p,start; char*cd; cd=(char*)malloc(n*sizeof(char)); cd[n-1]='\0';//末尾置0 for(i=1;i<=n;i++) { start=n-1;//cd串每次从末尾开始 c=i; p=ht[i].parent;//p在n+1至2n-1 while(p)//沿父亲方向遍历,直到为0 { start--;//依次向前置值 if(ht[p].LChild==c)//与左子相同,置0 cd[start]='0'; else//否则置1 cd[start]='1'; c=p; p=ht[p].parent; } weight[i].num=n-start;//二进制码的长度(包含末尾0) h[i]=(char*)malloc((n-start)*sizeof(char)); strcpy(h[i],&cd[start]);//将二进制字符串拷贝到指针数组h中 } free(cd);//释放cd存 system("pause"); } /*********所有字符的编码*********/ voidCrtHuffmanCode(charch[],HuffmanCodeh,HuffmanCodehc,WeightNodeweight,intn,intm) { inti,k; for(i=0;i { for(k=1;k<=n;k++)/*从weight[k].c中查找与ch[i]相等的下标K*/ if(ch[i]==weight[k].c) break; hc[i]=(char*)malloc((weight[k].num)*sizeof(char)); strcpy(hc[i],h[k]);//拷贝二进制编码 } } /*****解码*****/ voidTrsHuffmanTree(Huffmanht,WeightNodew,HuffmanCodehc,intn,intm) { inti=0,j,p; printf("***StringInformation***\n"); while(i { p=2*n-1;//从父亲节点向下遍历直到叶子节点 for(j=0;hc[i][j]! ='\0';j++) { if(hc[i][j]=='0') p=ht[p].LChild; else p=ht[p].RChild; } printf("%c",w[p].c);/*打印原信息*/ i++; } } /*****释放huffman编码存*****/ voidFreeHuffmanCode(HuffmanCodeh,HuffmanCodehc,intn,intm) { inti; for(i=1;i<=n;i++)//释放叶子结点的编码 free(h[i]); for(i=0;i free(hc[i]); } voidmain() { inti,n=0;/*n为叶子结点的个数*/ intm=0;/*m为字符串ch[]的长度*/ charch[N];/*ch[N]存放输入的字符串*/ Huffmanht;/*Huffman二叉数*/ HuffmanCodeh,hc;/*h存放叶子结点的编码,hc存放所有结点的编码*/ WeightNodeweight;/*存放叶子结点的信息*/ printf("\t***HuffmanCoding***\n"); printf("pleaseinputinformation: "); gets(ch);/*输入字符串*/ CreateWeight(ch,&m,weight,&n);/*产生叶子结点信息,m为字符串ch[]的长度*/ printf("***WeightInformation***\nNode"); for(i=1;i<=n;i++)/*输出叶子结点的字符与权值*/ printf("%c",weight[i].c); printf("\nWeight"); for(i=1;i<=n;i++) printf("%d",weight[i].weight); CreateHuffmanTree(ht,weight,n);/*产生Huffman树*/ printf("\n***HuffamnTreeInformation***\n"); printf("\ti\tweight\tparent\tLChild\tRChild\n"); for(i=1;i<=2*n-1;i++)/*打印Huffman树的信息*/ printf("\t%d\t%d\t%d\t%d\t%d\n",i,ht[i].weight,ht[i].parent,ht[i].LChild,ht[i].RChild); CrtHuffmanNodeCode(ht,ch,h,weight,m,n);/*叶子结点的编码*/ printf("***NodeCode***\n");/*打印叶子结点的编码*/ for(i=1;i<=n;i++) { printf("\t%c: ",weight[i].c); printf("%s\n",h[i]); } CrtHuffmanCode(ch,h,hc,weight,n,m);/*所有字符的编码*/ printf("***StringCode***\n");/*打印字符串的编码*/ for(i=0;i printf("%s",hc[i]); system("pause"); TrsHuffmanTree(ht,weight,hc,n,m);/*解码*/ FreeHuffmanCode(h,hc,n,m); system("pause"); }[5] Matlab实现 Matlab中简易实现Huffman编译码: n=input('Pleaseinputthetotalnumber: '); hf=zeros(2*n-1,5); hq=[]; forki=1: n hf(ki,1)=ki; hf(ki,2)=input('Pleaseinputthefrequency: '); hq=[hq,hf(ki,2)]; end forki=n+1: 2*n-1 hf(ki,1)=ki; mhq1=min(hq); m=size(hq); m=m(: 2); k=1; whilek<=m%delmin1 ifhq(: k)==mhq1 hq=[hq(: 1: (k-1))hq(: (k+1): m)]; m=m-1; break else k=k+1; end end k=1; whilehf(k,2)~=mhq1|hf(k,5)==1%findmin1location k=k+1; end hf(k,5)=1; k1=k; mhq2=min(hq); k=1; whilek<=m%delmin2 ifhq(: k)==mhq2 hq=[hq(: 1: (k-1))hq(: (k+1): m)]; m=m-1; break else k=k+1; end end k=1; whilehf(k,2)~=mhq2|hf(k,5)==1%findmin2location k=k+1; end hf(k,5)=1; k2=k; hf(ki,2)=mhq1+mhq2; hf(ki,3)=k1; hf(ki,4)=k2; hq=[hqhf(ki,2)]; end clc choose=input('Pleasechoosewhatyouwant: \n1: Encoding\n2: Decoding\n3: .Exit\n'); whilechoose==1|choose==2 ifchoose==1 a=input('PleaseinputtheletteryouwanttoEncoding: '); k=1; whilehf(k,2
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 种数 压缩 算法