编码方案设计:
实现最基本的哈夫曼编码,对文件进行两次扫描,第一次统计概率,第二次进行编码。压缩和解压缩时分别重新建立树,重新编码,以减小压缩后文件大小。
系统实现方案:
typedef struct HT
...{
        char ch;
        unsigned long weight;
        struct HT *pre;
        struct HT *next;
        struct HT *parent;
        struct HT *LChild;
        struct HT *RChild;
}HuffmanTree,RateTabNode;//树结点,同时也是双链表结点
统计概率(权):对文本进行扫描,统计字符种类和相应的权(数量),将结果保存在由以上结构构成的双链表中,返回头指针。
相关函数:
RateTabNode *Probability(FILE *ifp)//对字符作分类并统计数量(权)
...{
        char temp;
        RateTabNode *head,*p,*q;
        
        q=(RateTabNode *)malloc(sizeof(RateTabNode));
        head=p=q;
        q->next=NULL;
        head->pre=NULL;
        head->LChild=head->RChild=NULL;
        q->ch=temp=fgetc(ifp);
        q->weight=0;
        
        while(!feof(ifp))
        ...{
            
            if(!IsExisted(head,temp))//如果存在temp字符,则权加(IsExisted函数中);不存在,创建新结点
            ...{
                q=(RateTabNode *)malloc(sizeof(RateTabNode));
                p->next=q;
                q->pre=p;
                p=q;
                p->next=NULL;
                p->LChild=p->RChild=NULL;
                
                p->ch=temp;
                p->weight=1;
            }
            temp=fgetc(ifp);
        }
        return head;
}
int IsExisted(RateTabNode *head,char ch)//判断当前双链表中是否有ch字符,若有则数量加并返回真,否则返回假
...{
        RateTabNode *temp=head;
        while(temp!=NULL)
        ...{
            if(ch==temp->ch)
            ...{
                ++temp->weight;
                return 1;
            }
            temp=temp->next;
        }
        return 0;
}
递归建立Huffman树:
1.搜索双链表中权值最小和次小的结点(p1,p2),并将它们从双链表中移除,新建另一个结点(root),将p1和p2做为叶子链接到root结点,并把root结点添加到双链表,root的权为p1和p2权的和。
2.递归以上过程,直到双链表中剩下两个结点。
3.当剩下两个结点时,新建结点Root,两个结点分别为左右儿子,返回Root指针。
相关函数:

HuffmanTree *HTCreate(RateTabNode *head)//双链表形式创建Huffman树
{
 HuffmanTree *p1,*p2,*root;
    RateTabNode *temp,*p;

root=(HuffmanTree *)malloc(sizeof(HuffmanTree));
 //printf("%d/n",SizeAssure(head));
    if(SizeAssure(head)==2)//当只生剩下两个元素,直接将这两棵树作为子树,返回总根结点地址
 {
  root->ch='/0';
  root->LChild=head;
  head->parent=root;
  root->RChild=head->next;
  root->weight=head->weight+head->next->weight;
  head->next->parent=root;
  head=root;
        head->parent=NULL;

return head;
 }
 else
 {
   for(p=temp=head;p!=NULL;p=p->next)//找权最小的结点
   {
  if(temp->weight>p->weight)
   temp=p;
  
   }
   p1=temp;
   /****记下最小结点的地址,将它从链表中移除(分三种情况,头、尾和中间)***/
   if(p1->pre==NULL)//表头
   {
    head=head->next;
    head->pre=NULL;
   }
   else if(p1->next==NULL)//表尾
   {
    p1->pre->next=NULL;
   }
   else
   {
       p1->pre->next=p1->next;
    p1->next->pre=p1->pre;
   
   }//中间   
   p1->next=p1->pre=NULL;
   /*********寻找次小权结点,过程同上面完全相同,找去掉最小后的最小,即次小**********/
   for(temp=p=head;p!=NULL;p=p->next)
   {
  if(temp->weight>p->weight)
   temp=p;
   }
   p2=temp;
   if(p2->pre==NULL)
   {
    head=head->next;
    head->pre=NULL;
   }
   else if(p2->next==NULL)
   {
    p2->pre->next=NULL;
   }
   else
   {
       p2->pre->next=p2->next;
    p2->next->pre=p2->pre;
   
   }
   //取次小值
      p2->next=p2->pre=NULL;
   //printf("%d/n",SizeAssure(head));getch();
   /*********将两个最小值建立一棵子树,并将它们的根结点插入双链表**********/
   root->LChild=p1;
   root->RChild=p2;
   p1->parent=root;
   p2->parent=root;
    
   root->ch='/0';
   root->weight=p1->weight+p2->weight;
   root->next=head;
   head->pre=root;
   head=root;
   head->pre=NULL;

head=HTCreate(head);//递归,直到剩两个结点在双链表中
 }
}

编码:
采用自下向上的编码方式,从叶子开始,若当前结点是父结点的左儿子则在码序列末尾写0,否则写1,然后结点向上移动,直到结点的父结点(parent)为空即根结点结束。
相关函数:

void FindLeaf(RateTabNode *head,LeafNode *leafhead,int size)//递归查找叶子,记下地址到数组
{
 static int num=0;
 if(head->LChild==NULL&&head->RChild==NULL&&num<size)
 {
  leafhead[num].ch=head->ch;
  leafhead[num].leaf=head;
  ++num;
  return;
 }
 if(head==NULL)return;
 
 FindLeaf(head->LChild,leafhead,size);
 FindLeaf(head->RChild,leafhead,size);
 
}
void HFCoding(LeafNode *leafhead,CodeNode *codehead,int size)//自下向上编码,左0右1
{
     int i=0,j=CodeMaxLen;
  LeafNode *leaftmp=leafhead;
  while(i<size)
  {
   j=CodeMaxLen;
   codehead[i].ch=leaftmp[i].ch;
   codehead[i].code[--j]='/0';
      while(leaftmp[i].leaf->parent!=NULL&&j>=0)
      {
    if(leaftmp[i].leaf->parent->LChild==leaftmp[i].leaf)
     codehead[i].code[--j]='0';
    if(leaftmp[i].leaf->parent->RChild==leaftmp[i].leaf)
     codehead[i].code[--j]='1';
    leaftmp[i].leaf=leaftmp[i].leaf->parent;//向上
      }
   ++i;
  }
}

系统演示结果:
纯英文文档,压缩到原来的一半左右;中英文混合,效果差一些;纯中文效果不太好。
系统性能分析:
 递归建立Huffman树形结构,以及递归遍历树结点以寻找叶子,递归算法耗费系统资源较大,复杂度较高,但是现在的系统硬件条件优越,处理还是很迅速,基本不是问题。由于压缩时需要保留权信息,当原文件较小时,可能会存在“压大”的情况。
 系统总体性能优越,完美实现压缩和解压缩。
 改进:
 在建立Huffman树的同时完成编码,而不要再重新遍历自底向下的大费周折;Huffman压缩之后将产生大量的0和1,可以再用游程编码进行压缩,效果应该更好。
完整代码(gcc or C++ compiler):

/********************************************/

/*         Huffman编码的无损压缩V2.0       */

/*              2008.3.28                   */

/*            作者:付闯                 */

/********************************************/

#include<stdio.h>

#include<stdlib.h>

#include<conio.h>

#include<malloc.h>

#include<string.h>

#define MaxSize 65536

//定义缓冲区最大高度

#define CodeMaxLen 32

//定义Huffman编码最大长度

typedef struct HT

{

char ch;

unsigned long weight;

struct HT *pre;

struct HT *next;

struct HT *parent;

struct HT *LChild;

struct HT *RChild;

}HuffmanTree,RateTabNode;//树结点,同时也是双链表结点

typedef struct

{

char ch;//字符

char code[CodeMaxLen];//字符的编码

}CodeNode;//存储字符的Huffman编码

typedef struct

{

char ch;

HuffmanTree *leaf;

}LeafNode;//临时存储叶子结点的地址

typedef struct

{

char ch;

unsigned long weight;

}OFinal;//最后写入文件的单元

void compress(FILE *,FILE*);//压缩

void decompress(FILE *,FILE*);//解压缩

/*********************统计字符权并编码************************/

RateTabNode *Probability(FILE *);//建立双链表

int IsExisted(RateTabNode *,char);//统计文本中字符个数

int SizeAssure(RateTabNode *);//返回双链表大小,即字符的总个数

HuffmanTree* HTCreate(RateTabNode *);//创建Huffman树

void FindLeaf(RateTabNode *,LeafNode *,int);//找出所有叶子并记录地址

void HFCoding(LeafNode *,CodeNode *,int);//从叶子到根,从下向上的进行编码左0 右1

void buf_init(char (*)[8],int);//缓冲初始化

void wbuffer(FILE *,CodeNode *,char (*)[8],int,int);//从文件读取字节

//void bufprintf(char (*)[8],int);//打印缓冲,测试用

void zip(FILE *,char (*)[8],int);//最终将压缩编码写入输出文件

RateTabNode *RebuildLink(OFinal *,int);//双链表重建,从结构体数组

/********************以下是解压缩相关函数**********************/

void deWbuffer(FILE *,char (*)[8],int);//读文件数据到缓冲

char CodeMatch(CodeNode *,int,char *);//编码字符串的匹配

void deRbuffer(FILE *,CodeNode *,int,char (*)[8],int);//从缓冲计数据,解码写入文件

void chstract(char *,char);//将字符加入字符串末尾

int main()

{

FILE *ifp,*ofp,*ffp;

char choic;

char *ifilename,*ofilename;

ifilename=(char *)malloc(255);

ofilename=(char *)malloc(255);

printf("a.压 缩/nb.解压缩/n");

choic=getch();

if(choic=='a')

{

printf("请输入(compress)源文件名:");

scanf("%s",ifilename);

printf("请输入(compress)输出文件名:");

scanf("%s",ofilename);

if((ifp=fopen(ifilename,"rb"))==NULL)

{

printf("无法打开文件!");

getch();

return 1;

}

if((ofp=fopen(ofilename,"wb"))==NULL)

{

printf("无法创建文件!");

getch();

return 1;

}

compress(ifp,ofp);

printf("文件%s成功压缩为文件%s",ifilename,ofilename);

fclose(ifp);

fclose(ofp);

}

else

{

printf("请输入(decompress)源文件名:");

scanf("%s",ifilename);

printf("请输入(decompress)输出文件名:");

scanf("%s",ofilename);

if((ofp=fopen(ifilename,"rb"))==NULL)

{

printf("无法打开文件!");

getch();

return 1;

}

if((ffp=fopen(ofilename,"wb"))==NULL)

{

printf("无法创建文件!");

getch();

return 1;

}

decompress(ofp,ffp);

printf("文件%s成功解压缩为文件%s!",ifilename,ofilename);

fclose(ofp);

fclose(ffp);

}

getch();

return 0;

}

/*************************以下是压缩算法************************/

void compress(FILE *ifp,FILE *ofp)

{

RateTabNode *head,*temp;

HuffmanTree *root;

unsigned ArraySize;

int i=0;

LeafNode *leafhead;//存储叶子结点的地址,利于编码

CodeNode *codehead;//存储编码的数组首地址]

OFinal *ofinalhead;//把原始的字符和权信息输出文件

char buffer[MaxSize][8];//缓冲区,最大处理K数据

buf_init(buffer,MaxSize);//初始化缓冲区

head=Probability(ifp);//统计概率,建立双链表

ArraySize=SizeAssure(head);//叶子个数

ofinalhead=(OFinal *)malloc(ArraySize*sizeof(OFinal));

for(i=0,temp=head;temp!=NULL;temp=temp->next,++i)

{

ofinalhead[i].ch=temp->ch;

ofinalhead[i].weight=temp->weight;

}

root=HTCreate(head);//创建Huffman树,返回根结点

leafhead=(LeafNode *)malloc(ArraySize*sizeof(LeafNode));

codehead=(CodeNode *)malloc(ArraySize*sizeof(CodeNode));

for(i=0;i<ArraySize;++i)

{

int j=0;

for(j=0;j<CodeMaxLen;++j)

codehead[i].code[j]='#';

}

//初始化编码表全部为'#'

FindLeaf(root,leafhead,ArraySize);//找出所有叶子结点,记录地址

HFCoding(leafhead,codehead,ArraySize);//从叶子到根,从下向上进行编码

/***********以上两个函数完成编码***********/

for(i=0;i<ArraySize;++i)

printf("/n%c/t%s",codehead[i].ch,codehead[i].code);

fwrite(&ArraySize,sizeof(unsigned),1,ofp);//写入共有多少种字符

fwrite(ofinalhead,sizeof(OFinal),ArraySize,ofp);//写入编码表,以便解压

rewind(ifp);

while(!feof(ifp))

{

wbuffer(ifp,codehead,buffer,MaxSize,ArraySize);//读文件二进制,转换为或写入缓冲

zip(ofp,buffer,MaxSize);//转换成编码输出

if(feof(ifp))break;

}

}

RateTabNode *Probability(FILE *ifp)//对字符作分类并统计数量(权)

{

char temp;

RateTabNode *head,*p,*q;

q=(RateTabNode *)malloc(sizeof(RateTabNode));

head=p=q;

q->next=NULL;

head->pre=NULL;

head->LChild=head->RChild=NULL;

q->ch=temp=fgetc(ifp);

q->weight=0;

while(!feof(ifp))

{

if(!IsExisted(head,temp))//如果存在temp字符,则权加(IsExisted函数中);不存在,创建新结点

{

q=(RateTabNode *)malloc(sizeof(RateTabNode));

p->next=q;

q->pre=p;

p=q;

p->next=NULL;

p->LChild=p->RChild=NULL;

p->ch=temp;

p->weight=1;

}

temp=fgetc(ifp);

}

return head;

}

int IsExisted(RateTabNode *head,char ch)//判断当前双链表中是否有ch字符,若有则数量加并返回真,否则返回假

{

RateTabNode *temp=head;

while(temp!=NULL)

{

if(ch==temp->ch)

{

++temp->weight;

return 1;

}

temp=temp->next;

}

return 0;

}

int SizeAssure(RateTabNode *head)//测链表长度,即字符的种类数

{

RateTabNode *temp;

int num=1;

temp=head;

while(temp->next!=NULL)

{

++num;

if(temp->next==NULL)break;

temp=temp->next;

}

return num;

}

void wbuffer(FILE *ifp,CodeNode *codehead,char (*buffer)[8],int size,int ArraySize)//将字符用编码替换,写入缓冲

{

char temp;

int i=0;

unsigned long offset=0;

buf_init(buffer,MaxSize);

while(!feof(ifp)&&offset<8*size)

{

if(feof(ifp))break;

temp=fgetc(ifp);

for(i=0;i<ArraySize;++i)

{

int k=0;

if(temp==codehead[i].ch)

{

for(k=0;k<CodeMaxLen;++k)

if(codehead[i].code[k]!='#'&&codehead[i].code[k]!='/0')//不要忘记还有个'/0'

{

if(offset==8*size)break;

*(*buffer+offset)=codehead[i].code[k];

++offset;

}

}

}

}

}

/*void bufprintf(char (*buffer)[8],int size)

{

int i,j;

for(i=0;i<size;++i)

{

for(j=0;j<8;++j)

printf("%d",buffer[i][j]);

printf("/n");

}

}*/

void zip(FILE *ofp,char (*buffer)[8],int size)//写缓冲到文件

{

int i=0,j=0;

while(i<size)

{

char temp=0;

for(j=0;j<8&&buffer[i][j]!=-1;++j)

{

if(buffer[i][j]==-1)break;

temp+=(buffer[i][j]-48)<<(7-j);

}

fputc(temp,ofp);

if(buffer[i][j]==-1)break;

++i;

}

}

/**********************以下是解压缩算法************************/

void decompress(FILE *ifp,FILE *ofp)

{

int i=0;

unsigned ArraySize=0;

RateTabNode *head,*temp;

CodeNode *codehead,*codetmp;//存储编码的数组首地址]

OFinal *ofinalhead;

HuffmanTree *root;//树根

LeafNode *leafhead;//存储叶子结点的地址,利于编码

char buffer[MaxSize][8];

buf_init(buffer,MaxSize);

fread(&ArraySize,sizeof(unsigned),1,ifp);//读字符种类数

codehead=(CodeNode *)malloc(ArraySize*sizeof(CodeNode));

codetmp=(CodeNode *)malloc(ArraySize*sizeof(CodeNode));

ofinalhead=(OFinal *)malloc(ArraySize*sizeof(OFinal));

fread(ofinalhead,sizeof(OFinal),ArraySize,ifp);//读字符和权

head=RebuildLink(ofinalhead,ArraySize);

root=HTCreate(head);//创建Huffman树,返回根结点

leafhead=(LeafNode *)malloc(ArraySize*sizeof(LeafNode));

codehead=(CodeNode *)malloc(ArraySize*sizeof(CodeNode));

for(i=0;i<ArraySize;++i)

{

int j=0;

for(j=0;j<CodeMaxLen;++j)

codetmp[i].code[j]='#';

}

//初始化编码表全部为'#'

FindLeaf(root,leafhead,ArraySize);//找出所有叶子结点,记录地址

HFCoding(leafhead,codetmp,ArraySize);//从叶子到根,从下向上进行编码

/*******以下循环去除#在编码前,以便字符串的匹配********/

for(i=0;i<ArraySize;++i)

{

int j=0,k=0;

codehead[i].ch=codetmp[i].ch;

for(j=0,k=0;j<CodeMaxLen;++j)

{

if(codetmp[i].code[j]!='#')

{

codehead[i].code[k]=codetmp[i].code[j];

++k;

}

}

}

free(codetmp);

while(!feof(ifp))

{

deWbuffer(ifp,buffer,MaxSize);

deRbuffer(ofp,codehead,ArraySize,buffer,MaxSize);

}

}

RateTabNode *RebuildLink(OFinal *ofinalhead,int ArraySize)//恢复双链表结构

{

RateTabNode *head,*p,*q;

int i=0;

q=(RateTabNode *)malloc(sizeof(RateTabNode));

head=p=q;

q->next=NULL;

head->pre=NULL;

head->LChild=head->RChild=NULL;

for(i=0;i<ArraySize;++i)

{

p->ch=ofinalhead[i].ch;

p->weight=ofinalhead[i].weight;

if(i==ArraySize-1)break;

q=(RateTabNode *)malloc(sizeof(RateTabNode));

p->next=q;

q->pre=p;

p=q;

p->next=NULL;

p->LChild=p->RChild=NULL;

}

return head;

}

void deWbuffer(FILE *ifp,char (*buffer)[8],int size)

{

char temp;

int i=0;

buf_init(buffer,MaxSize);

while(i<size-1&&!feof(ifp))

{

int j=0;

temp=fgetc(ifp);

if(feof(ifp))return;

for(j=0;j<8;++j)

buffer[i][j]=((temp>>(7-j))&1)+48;//写入的是数字,注意转换为字符'1'

++i;

}

}

char CodeMatch(CodeNode *codehead,int ArraySize,char *ch)//在编码中找当前字符串是否是编码,是则返回该编码对应字符,否则返回'/0'

{

int i;

for(i=0;i<ArraySize;++i)

if(strcmp(codehead[i].code,ch)==0)

return codehead[i].ch;

return '/0';

}

void deRbuffer(FILE *ofp,CodeNode *codehead,int ArraySize,char (*buffer)[8],int size)//解码,还原文件

{

int i=0,j;

char temp[CodeMaxLen];

char ch;

temp[0]='/0';

while(*(*buffer+i)!=-1)//读一个字符

{

chstract(temp,*(*buffer+i));//将字符加到字符串temp后

if((ch=CodeMatch(codehead,ArraySize,temp))!='/0')//匹配则解码,否则字符串继续变长

{

fputc(ch,ofp);

temp[0]='/0';

}

++i;

}

}

void chstract(char *temp,char ch)//把一个字符加到当前字符串末尾

{

int i;

for(i=0;i<CodeMaxLen;++i)

{

if(temp[i]=='/0')

{

temp[i]=ch;

temp[i+1]='/0';

return;

}

}

}

/***************共用算法****************/

HuffmanTree *HTCreate(RateTabNode *head)//双链表形式创建Huffman树

{

HuffmanTree *p1,*p2,*root;

RateTabNode *temp,*p;

root=(HuffmanTree *)malloc(sizeof(HuffmanTree));

//printf("%d/n",SizeAssure(head));

if(SizeAssure(head)==2)//当只生剩下两个元素,直接将这两棵树作为子树,返回总根结点地址

{

root->ch='/0';

root->LChild=head;

head->parent=root;

root->RChild=head->next;

root->weight=head->weight+head->next->weight;

head->next->parent=root;

head=root;

head->parent=NULL;

return head;

}

else

{

for(p=temp=head;p!=NULL;p=p->next)//找权最小的结点

{

if(temp->weight>p->weight)

temp=p;

}

p1=temp;

/****记下最小结点的地址,将它从链表中移除(分三种情况,头、尾和中间)***/

if(p1->pre==NULL)//表头

{

head=head->next;

head->pre=NULL;

}

else if(p1->next==NULL)//表尾

{

p1->pre->next=NULL;

}

else

{

p1->pre->next=p1->next;

p1->next->pre=p1->pre;

}//中间   

p1->next=p1->pre=NULL;

/*********寻找次小权结点,过程同上面完全相同,找去掉最小后的最小,即次小**********/

for(temp=p=head;p!=NULL;p=p->next)

{

if(temp->weight>p->weight)

temp=p;

}

p2=temp;

if(p2->pre==NULL)

{

head=head->next;

head->pre=NULL;

}

else if(p2->next==NULL)

{

p2->pre->next=NULL;

}

else

{

p2->pre->next=p2->next;

p2->next->pre=p2->pre;

}

//取次小值

p2->next=p2->pre=NULL;

//printf("%d/n",SizeAssure(head));getch();

/*********将两个最小值建立一棵子树,并将它们的根结点插入双链表**********/

root->LChild=p1;

root->RChild=p2;

p1->parent=root;

p2->parent=root;

root->ch='/0';

root->weight=p1->weight+p2->weight;

root->next=head;

head->pre=root;

head=root;

head->pre=NULL;

head=HTCreate(head);//递归,直到剩两个结点在双链表中

}

}

void FindLeaf(RateTabNode *head,LeafNode *leafhead,int size)//递归查找叶子,记下地址到数组

{

static int num=0;

if(head->LChild==NULL&&head->RChild==NULL&&num<size)

{

leafhead[num].ch=head->ch;

leafhead[num].leaf=head;

++num;

return;

}

if(head==NULL)return;

FindLeaf(head->LChild,leafhead,size);

FindLeaf(head->RChild,leafhead,size);

}

void HFCoding(LeafNode *leafhead,CodeNode *codehead,int size)//自下向上编码,左右

{

int i=0,j=CodeMaxLen;

LeafNode *leaftmp=leafhead;

while(i<size)

{

j=CodeMaxLen;

codehead[i].ch=leaftmp[i].ch;

codehead[i].code[--j]='/0';

while(leaftmp[i].leaf->parent!=NULL&&j>=0)

{

if(leaftmp[i].leaf->parent->LChild==leaftmp[i].leaf)

codehead[i].code[--j]='0';

if(leaftmp[i].leaf->parent->RChild==leaftmp[i].leaf)

codehead[i].code[--j]='1';

leaftmp[i].leaf=leaftmp[i].leaf->parent;//向上

}

++i;

}

}

void buf_init(char (*buffer)[8],int size)//缓冲初始化

{

int i,j;

for(i=0;i<size;++i)

for(j=0;j<8;++j)

buffer[i][j]=-1;

}

此程序还有一点小问题,会造成解压后文本与原文本有一两个字符的出入。

这是因为程序中压缩算法里,当缓冲区中二进制位个数不足下8个的时候(比如11),算法还是

会写入8位(1字节),相当于写入(11000000),所以当解压缩时,会多读入6位(6个0),如果这6个0序列中,存在编码,则程序会错误译码,最坏情况会出入6个字节(当0是某字符的编码时,错译6个;当00时,则3个字符;依次类推),最好情况就是这6个0不含有任何编码。

时间关系,这个问题没来得及修正,修正也较简单,只要压缩时把原文件中字节数一并写入即可,解压时,如果超过这个数以后的字符全都无效。

Huffman编解码实现文本压缩相关推荐

  1. 实验三 Huffman编解码算法实现与压缩效率分析

    一.Huffman编解码原理 1. Huffman编码 对原始文件进行Huffman编码,首先需要解决以下几点问题: 文件符号的概率分布情况是怎样的? Huffman树是如何建立的? 建立起Huffm ...

  2. 数据压缩 实验三 Huffman编解码算法实现与压缩效率分析

    实验目的 掌握Huffman编解码实现的数据结构和实现框架, 进一步熟练使用C编程语言, 并完成压缩效率的分析. 实验原理 1.本实验中Huffman编码算法 (1)将文件以ASCII字符流的形式读入 ...

  3. Huffman编解码

    Huffman编解码算法实现与压缩效率分析 一.背景知识及相关公式 1.信源熵 信源熵是信息的度量单位,一般用H表示,单位是比特,对于任意一个随机变量,它的熵定义为,变量的不确定性越大,熵也就越大. ...

  4. 多媒体技术与应用之图像Huffman编解码

    多媒体技术与应用之图像Huffman编解码 一.实验内容 1.了解BMP图像的格式,实现BMP图片格式的数据域及文件头的分离 2.熟悉Huffman编码原理 3.使用Huffman编码算法对给定图像文 ...

  5. Huffman编解码完全注释

    Huffman编解码完全注释 /** huffman - Encode/Decode files using Huffman encoding.* Copyright (C) 2003 Douglas ...

  6. huffman编解码算法实验与压缩效率分析

    一.基本原理 1.huffman编码原理 huffman编码是一种无失真编码方式,是可变长(VLC)编码的一种. huffman编码基于信源的概率统计模型,基本思路是出现概率大的信源符号编长码,出现概 ...

  7. 实验三—Huffman编解码

    一.实验原理 1.Huffman编码的步骤: (1)首先将所有字符发生的概率从小到大进行排序: (2)将最小的两个概率进行两两一合并,之后继续找最小的两个概率进行合并包括前面已经合并的和数: (3)一 ...

  8. 数据压缩原理 实验三 Huffman编解码算法实现与压缩效率分析

    实验原理 Huffman编码是一种无失真编码方式,是一种可变长编码,它将出现概率大的信源符号短编码,出现概率小的信源符号长编码. 编码步骤: ①将文件以ASCII字符流的形式读入,统计每个符号的发生概 ...

  9. Huffman 编解码算法实现与压缩效率分析

    一.实验原理 1 熵,又称为"信息熵" (Entropy) 1.1 在信息论中,熵是信息的度量单位.信息论的创始人 Shannon 在其著作<通信的 数学理论>中提出了 ...

最新文章

  1. 关于空指针(指针指向为NULL)和void类型的指针的理解
  2. python生成器使用场景桌面_Python – 如何更简洁地使用生成器?
  3. PMCAFF微课堂「已结束」 | 产品汪如何做好“时间管理”让效率提高100倍
  4. 小余学调度:学习记录2021.8月
  5. thinkphp5.0学习(九):TP5.0视图和模板
  6. CSDN博客图片水印|自定义水印|去除水印
  7. apache php 重写url无效,apache用rewrite重写url时出现问题
  8. Hexo+NexT搭建博客笔记
  9. oracle日期虚数0去掉,第 14 章 使用复数运算库
  10. 解决idea创建ssm项目找不到mybatis的mapper的xml文件问题
  11. struts2中,在使用 convention 插件的情况下,如何使用 “chain” 这个resu
  12. 实用多媒体技术 课程习题及解答
  13. excel小写转大写公式_EXCEL人民币金额小写转大写
  14. CADD之分子对接二:简单autodockvina对接流程——redocking
  15. 宁夏移民文化的内涵及特点
  16. 你想要的宏基因组-微生物组知识全在这(1909)
  17. CVPR 2021 论文大盘点-去阴影、去反光、去高光、去伪影篇
  18. python递归必须要有_Python的递归
  19. centos7.4安装
  20. 基本数据类型和内置方法 08

热门文章

  1. 均值、中值、标准差、四分位差(C++)
  2. 最常用的几个数据验证正则判断,手机号,车牌号,身份证,Email,IP
  3. python day 07
  4. 华为鸿蒙电视如何安当贝,华为智慧屏S系列发布,如何安装当贝市场?
  5. ESP32-C3学习,Windows下基于VScode环境建立
  6. Cloudera Manager中安装部署Livy服务
  7. 从王者荣耀看设计模式(十.外观模式)
  8. keras自定义simm作为损失函数,并且实现Tensor和数组之间的转换
  9. RISC-V MCU 电源系统概述
  10. 数据存储单位的换算单位