1.首先图片压缩编码对不同文件的压缩效率是不一样的
这也是我在最后发现自己的压缩比率超高(类似于未压缩)发现的。多次确认算法无误后终于在以为大佬的博客中找到了答案。此处感谢下面这位大佬的博客。
哈夫曼编码压缩解压缩实现&不同类型文件压缩比的测试
https://blog.csdn.net/to_be_better/article/details/50431352
2.为什么要用haffman
对于一组具有确定权值的叶子结点,可以构造出多个具有不
同带权路径长度的二叉树,我们把其中最小带权路径长度的二叉树称为哈夫曼树。(最优二叉树)。
哈夫曼树可以用于构造代码长度最短的编码,所以使用哈夫曼树。
3.生成haffman及haffman编码
haffman生成:
其中x1,x2用于存放权值最小的两个节点。
int cHuffmanTree(HTNode pHT[],int w[],int n){
int i,j,m1,m2,x1,x2,t;
//初始化
for(i=0;i<(2*n-1);i++){
if(i<n){
(pHT[i]).weight=w[i];
}
else{
(pHT[i]).weight=0;
}
(pHT[i]).parent=-1;
(pHT[i]).lchild=-1;
(pHT[i]).rchild=-1;
}
//构造哈夫曼树的n-1个非叶子结点
for(i=0;i<n-1;i++){
m1=m2=1000000; //书上显示=MaxValue
x1=x2=0;
for(j=0;j<n+i;j++){
if(((pHT[j]).weight<m1)&&((pHT[j]).parent==-1)){
m2=m1;
x2=x1;
m1=(pHT[j]).weight;
x1=j;
}
else if(((pHT[j]).weight<m2)&&((pHT[j]).parent==-1)){
m2=(pHT[j]).weight;
x2=j;
}
}
//将找出两颗权值最小和次小的子树合并为一棵树
(pHT[x1]).parent=n+i;
(pHT[x2]).parent=n+i;
(pHT[n+i]).weight=(pHT[x1]).weight+(pHT[x2]).weight;
(pHT[n+i]).lchild=x1;
(pHT[n+i]).rchild=x2;
}
return 0;
}
haffman编码生成:
左0右1原则
int HuffmanCodeing(HTNode pHT[],Code pHC[]){
Code *cd=(Code *)malloc(sizeof(Code));
int i,j,child,parent;
int n=256;
//求n各节点的哈夫曼编码
for(i=0;i<n;i++){
cd->start=n-1;
cd->weight=pHT[i].weight;
child=i;
parent=pHT[child].parent;
//由节点向上直到根节点
while(parent!=-1)
{
if(pHT[parent].lchild==child)
cd->bit[cd->start]=0;
else
cd->bit[cd->start]=1;
cd->start--;
child=parent;
parent=pHT[child].parent;
}
for(j=cd->start+1;j<n;j++){
pHC[i].bit[j]=cd->bit[j];
pHC[i].start=cd->start+1;
pHC[i].weight=cd->weight;
}
}
return 0;
}
4.压缩并计算比率
int Compress(const char*pFilename){
int i;
int nSize=0;
HuffmanTree pHT=NULL;
HuffmanCode pHC=NULL;
char* pBuffer=NULL;
HEAD sHead;
int len;
int ch;
FILE* in;
char cd[SIZE]={0}; //工作区
int pos=0,j;
if(ERROR==InitHead(pFilename,&sHead)){
return ERROR;
}
printf("%d字节\n",sHead.length);
pHT=(HuffmanTree)malloc((sizeof(HTNode))*(2*256-1));
pHC=(HuffmanCode)malloc((sizeof(Code))*(256));
if(pHT==NULL){
printf("初始化失败!\n");
return ERROR;
}
if(pHC==NULL){
printf("初始化失败!\n");
return ERROR;
}
//....
cHuffmanTree(pHT,sHead.weight,256);
HuffmanCodeing(pHT,pHC);
free(pHT);
//
//计算编码缓冲区大小
in=fopen(pFilename,"rb");
if(in==NULL){
printf("文件为空\n");
return ERROR;
}
while((ch=fgetc(in))!=EOF){
//strcat(cd,pHC[ch].bit+'0');
i=0;
for(j=pHC[ch].start;j<256;j++){ //HC复制编码串到cd
cd[i]=pHC[ch].bit[j]+'0';
i++;
}
//压缩编码
while(strlen(cd)>=8){
//截取字符串左边的8个衣服,编码成字节
pos++;
//字符串正题左移八个字符
for(i=0;i<SIZE-8;i++){
cd[i]=cd[i+8];
}
}
}
fclose(in);
if(strlen(cd)>0){
pos++;
}
/*for(i=0;i<256;i++){
nSize+=pHC[i].weight*(256-pHC[i].start);
}
nSize=(nSize%8)?(nSize/8+1):nSize/8;*/
//对源文件进行压缩编码
nSize=pos;
pBuffer=Encode(pFilename,pHC,pBuffer,nSize);
free(pHC);
if(!pBuffer){
printf("失败");
return ERROR;
}
len=Write( pFilename, sHead, pBuffer, nSize);
free(pBuffer);
if(len<0){
return ERROR;
}
printf("%d字节\n",len);
printf("压缩比率:%f",(double)len/(double)sHead.length*100);
putchar('%');
printf("\n");
return 0;
}
特别要注意的是在对编码后的文件预算如果像如下所示会造成空间计算偏差,以至于压缩率变大(效率变低),也就是计算错误。经过改进后如上通过pos得出nSize,就可以达到目的。
/*for(i=0;i<256;i++){
nSize+=pHC[i].weight*(256-pHC[i].start);
}
nSize=(nSize%8)?(nSize/8+1):nSize/8;*/
关于文件的初始化和最重要的压缩码存放在缓冲字符数组的细节就不一一列举了。其实思想蛮简单的,就是:
1.将对各个字符进行编码。
2.从文件中再次依次按顺序读出字符,这时注意的是用编码替换文件中的字符。
3.再按顺序依次一个个八个位转码位字符放入缓冲字符数组中存放。
4.最后,写入文件,计算出压缩比率。