c++哈夫曼编码

哈夫曼编码的基本步骤:
(1)把概率最小的两个符号组成一个新的节点
(2)重复步骤,直到概率和为1
(3)总根节点开始到相应于每个符号的“树叶”,概率大的标“1”,概率小的标“0”
(4)从根节点开始,对符号进行编码

1、定义结构体

typedef struct
{
 float weight;
 int parent,lchild,rchild;
}HTNode;

typedef struct
{
  char data;
  float weight;
  char code[N];
}HTNode;

2、mian函数,调用Huffman函数进行编码,并计算编码的平均长度


void main()
{
 int i,n;
 float l;
 HTNode ht[M+1];
 HTCode hc[N+1];
 Init(hc,&n);
 HuffmanCoding(ht,hc,n);
 for( i=1;i<=n;i++)
   printf("\n %c的编码结果是:%s",hc[i].data,hc[i].code);
 //计算平均码长
 l=0;
    for( i=1;i<=n;i++)
 {
  l+=strlen(hc[i].code)*hc[i].weight; 
    }
    printf("\n 哈夫曼编码的平均码长是:%f\n",l);
 getchar();等待用户按任意键返回,阻止运行黑框闪退问题
 for(i=1;i<=n;i++)
  printf("\n %c的编码结果是:%s",hc[i].data,hc[i].code);
 l=0;
 for(i=1;i<=n;i++)
  l+=strlen(hc[i].code)*hc[i].weight;
 printf("\n 赫夫曼编码的平均码长是: %f\n",l);
}

3、创建Init,用于初始化待编码项的名称和权值

void Init(HTCode hc[],int*n)
{
 int i;
 printf("\n 请输入要编码的总项数n=");
 scanf("%d",&(*n));
 fflush(stdin);
 printf("\n 输入%d项带编码数的信息\n",*n);
 for(i=1;i<=*n;i++){
  printf("\n第%d的名称是:",i);
  scanf("%c",&(hc[i].data));
  fflush(stdin);
 }
 printf("\n 注意:各项带编码数的权重之和应该为1 \n",*n);
 for(i=1;i<=*n;i++){
  printf("\n第%d的权重是:",i);
  scanf("%f",&(hc[i].weight));
 }
}

4、创建HuffmanCoding函数,其主要的功能是:先构造二叉树,然后再根据构造的二叉树,进行哈夫曼编码

void HuffmanCoding(HTNode ht[],HTCode hc[],int n)
{
 char cd[N];
 int i,m,c,f,s1,s2,start;
 m=2*n-1;
 for(i=1;i<=m;i++){
  if(i<=n)
   ht[i].weight=hc[i].weight;
  else
   ht[i].weight=0.0;
  ht[i].parent=ht[i].lchild=ht[i].rchild=0;
 }
 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].weight=ht[s1].weight+ht[s2].weight;
 }
 for(i=1;i<=m;i++){
  printf("\n 第%d个节点的权重是:%f",i,ht[i].weight);
  printf("\n 第%d个节点的左子节点是:%d",i,ht[i].lchild);
  printf("\n 第%d个节点的右子节点是:%d",i,ht[i].rchild);
  printf("\n 第%d个节点的父节点是:%d",i,ht[i].parent);
 }
 for(i=0;i<N;i++){
  cd[i]=' ';
 }
 cd[n-1]='\0';
 for(i=1;i<=n;i++){
  start=n-1;
  for(c=i,f=ht[i].parent;f;c=f,f=ht[f].parent)
  {
   if(ht[f].lchild==c)
    cd[--start]='0';
   else
    cd[--start]='1';
  }
  strcpy(hc[i].code,&cd[start]);
 }
}

5、创建Select函数,用于在剩余二叉树根节点和新产生的根节点中选出权值最小的两项

void Select(HTNode ht[],int k,int *s1,int *s2)
{
 int i;
 for(i=1;i<=k;k++){
  if(ht[i].parent==0)
  {
   *s1=i;
   break;
  }
 }
 for(i=1;i<=k;i++)
 {
  //if(ht[i].parent==0&&ht[i].weight<ht[*s1].weight && fabs(ht[i].weight-ht[*s1].weight)>1e-6)
        if(ht[i].parent==0&&ht[i].weight<ht[*s1].weight&&fabs(ht[i].weight-ht[*s1].weight)>1e-6)
   *s1=i;
 }
 for(i=1;i<=k;i++)
 {
  if(ht[i].parent==0&&i!=*s1)
  {
   *s2=i;
   break;
  }
 }
 for(i=1;i<=k;i++)
 {
  //if(ht[i].parent==0&&i!=*s1&&ht[i].weight<ht[*s2].weight && fabs(ht[i].weight-ht[*s2].weight)>1e-6)
  if(ht[i].parent==0&&i!=*s1&&ht[i].weight<ht[*s2].weight&&fabs(ht[i].weight-ht[*s2].weight)>1e-6)
   *s2=i;
 }
 printf("\n 这是 *s1:%d\n",*s1);
    printf("\n 这是 *s2:%d\n",*s2);
}
  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
编码是一种可变长度编码的压缩算法,通过根据字符出现的频率构建最优前缀编码表来减少数据的存储空间。 首先,根据字符的频率构建哈树。哈树是一种特殊的二叉树,其每个叶子节点代表一个字符,而每个非叶子节点代表出现频率较低的两个字符的合并。频率越高的字符距离根节点越近,频率越低的字符距离根节点越远。 然后,根据哈树构建编码表。从根节点开始,向左路径表示编码0,向右路径表示编码1。将每个叶子节点的路径编码存储在编码表中,以便后续的编码和解码过程中使用。 编码过程中,将要压缩的数据按照编码表进行替换。将原始的字符序列转换为哈编码序列,从而减少存储空间。编码后的数据长度可能会比原始数据短。 解码过程中,根据编码表将哈编码序列转换为原始字符序列。从根节点开始,根据编码(0或1)判断是向左还是向右,直到叶子节点找到对应的字符。解码后的数据与原始数据保持一致。 哈编码十分有效,特别适用于频率分布不均的数据。频率高的字符可以使用较短的编码,频率低的字符可以使用较长的编码,整体上减少了数据的存储空间。但是,在编码和解码过程中,需要使用编码表进行对应,因此需要将编码表存储在文件中或者以其他方式传输。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值