哈夫曼编码

题目描述:

手动输入一系列字符,自动统计字符出现的次数并作为该字符的权重,实现对应哈夫曼树的构造、编码、译码。

样例:

 

#include<bits/stdc++.h>
using namespace std;
#define maxval 10000
#define MaxBit 100   //哈夫曼编码的最大位数


typedef struct{
    char ch;
    int weight;
    int flag;
    int lchild,rchild,parent;
}HuffmanTree;

typedef struct{
    char codeBit[MaxBit];   //位串
    int start;      //编码在位串中的起始位置
    int weight;
    char ch;        //字符
}CodeNode;

void CreateHuffmanTree(HuffmanTree HuffTree[],int r[],int n){
    int i,j,p1,p2,small1,small2;//x1,x2,
    int w;
    char c;
    int m = 2*n-1;
    for(i=0;i<m;i++){//初始化 
        HuffTree[i].parent=0;
        HuffTree[i].lchild=-1;
        HuffTree[i].rchild=-1;
        HuffTree[i].weight=0;
    }
    i=0;
    for(j=0;j<n;j++){
        while(!r[i])  i++;
        if(r[i]&&(i<255)&&(i>=0)){
            HuffTree[j].ch=i;
            HuffTree[j].weight=r[i];
        }
        i++;
//      哈夫曼树检测 
//      cout<<HuffTree[j].ch<<" "<<HuffTree[j].weight<<endl;
    }   
     for(i=n;i<m;i++){    
        p1=0;p2=0;
        small1=maxval;small2=maxval; 
        for(j=0;j<i;j++)   
            if(HuffTree[j].parent==0)
                if(HuffTree[j].weight<small1){ 
                    small2=small1; 
                    small1=HuffTree[j].weight;
                    p2=p1;
                    p1=j;
                }
                else if(HuffTree[j].weight<small2){
                        small2=HuffTree[j].weight;  
                        p2=j;
                }
                HuffTree[p1].parent=i;
                HuffTree[p2].parent=i;
                HuffTree[i].lchild=p1;  //最小转成新左孩子
                HuffTree[i].rchild=p2;  //次小转成新右孩子
                HuffTree[i].weight=HuffTree[p1].weight+HuffTree[p2].weight;
     }
     
}

//哈夫曼编码
void CalculateHuffmanCode(HuffmanTree HuffTree[],CodeNode HFCode[],int n){
    int i,c,p;
    CodeNode cd;   
    for(i=0;i<n;i++){
        cd.start=n;
        cd.ch=HuffTree[i].ch;
        c=i;     
        p=HuffTree[i].parent;   
        while(p!=0){
            cd.start--;
            if(HuffTree[p].lchild==c)   cd.codeBit[cd.start]='0';   //左'0'
            else    cd.codeBit[cd.start]='1';   //右'1'
            c=p;
            p=HuffTree[p].parent;
        }
        HFCode[i]=cd;    
    }
}

void decode(HuffmanTree HuffTree[],int m)//依次读入电文,根据哈夫曼树译码
{
 int i,j=0;
 char b[MaxBit];
 char endflag='#';    //电文结束标志取2
 i=m-1;             //从根结点开始往下搜索
 printf("输入发送的编码(以'#'为结束标志):");
 printf("\n");
 fflush(stdin);
 gets(b);
 printf("译码后的字符为");
 while(b[j]!='#')
 {
  if(b[j]=='0')
   i=HuffTree[i].lchild;   //走向左孩子
  else
   i=HuffTree[i].rchild;   //走向右孩子
  if(HuffTree[i].lchild==-1)     //tree[i]是叶结点
  {
   printf("%c",HuffTree[i].ch);
   i=m-1;      //回到根结点
  }
  j++;
 }
 printf("\n");
 if(HuffTree[i].lchild!=-1&&b[j]!='#')   //电文读完,但尚未到叶子结点
  printf("\nERROR\n");  //输入电文有错
}//decode

int main(){
    char *a=new char[1024];
    string str; int t;
    int r[1024]={0};
    int N,n=0;//n为叶子节点数 

    printf("单词数目: \n");
    scanf("%d",&N);
    printf("输入字符串: \n");
    for(int j=0;j<N;j++){
        cin>>a;
        while(*a!='\0'){ str+=*a; r[*a++]+=1;}  
        if(j!=(N-1)) { r[32]+=1; str+=" ";}
    }   
        for(int i=0;i<255;i++)
            if(r[i]) n++;
    
    cout<<"叶子节点数: "<<n<<endl;
    int m = 2*n-1;
    HuffmanTree tree[m];
    CodeNode code[n];
    
    CreateHuffmanTree(tree,r,n);//建立哈夫曼树
    CalculateHuffmanCode(tree,code,n);//哈夫曼编码
    cout<<"哈夫曼编码: "<<endl;
    for(int i=0;i<n;i++){
        printf("%c: ",code[i].ch);
        for(int j=code[i].start;j<n;j++)
        printf("%c ",code[i].codeBit[j]);
        printf("\n");
    }
    cout<<str<<"的哈夫曼编码为:"<<endl;
    for(int i=0;i<str.length();i++){
        for(int j=0;j<n;j++)
            if(str[i]==code[j].ch)
                for(int p=code[j].start;p<n;p++) printf("%c ",code[j].codeBit[p]);
    }
    printf("\n");
    decode(tree,m);

    return 0;
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值