哈夫曼编/译码器

 

Description

写一个哈夫曼码的编/译码系统,要求能对要传输的报文进行编码和解码。构造哈夫曼树时,权值小的放左子树,权值大的放右子树,编码时右子树编码为1,左子树编码为0。

 

 

Input

输入表示字符集大小为n(n<=100)的正整数,以及n个字符和n个权值(正整数,值越大表示该字符出现的概率越大);输入串长小于或等于100的目标报文。

 

 

Output

经过编码后的二进制码,占一行;

 

 

以及对应解码后的报文,占一行;

最后输出一个回车符;

 

 

Sample Input        5 a b c d e 12 40 15 8 25

                                bbbaddeccbbb

 

 

Sample Output    00011111110111010110110000

                                bbbaddeccbbb

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define maxval 10000
typedef struct
{
    char ch;//标签
    int weight;
    int parent,lchild,rchild;
}tree;//变量名
typedef struct
{
    char bit[100];//位串
    int start;//编码在位串中的起始位置
}codetype;//变量名
tree ht[1005];
codetype co[200];//存放各叶子节点的编码的数组
int p=0;
char str[1000]={'\0'};
void creat(tree ht[],int n)//创建哈夫曼树
{
    int i,j,p1,p2;//p1,p2分别记住每次合并时权值最小和次小的两个根节点的下标
    int small1,small2;
    for(i=0;i<2*n-1;i++)
    {
        ht[i].parent=-1;
        ht[i].lchild=-1;
        ht[i].rchild=-1;
        ht[i].weight=0;
        ht[i].ch=-1;
    }
    for(i = 0; i < n; i++)
    {
        scanf(" ");//空格符
        scanf("%c",&ht[i].ch);
    }
    scanf(" ");//空格符
        for(i=0;i<n;i++)
    {
        scanf("%d ",&ht[i].weight);
    }
    for(i=n;i<2*n-1;i++)
    {
        p1=0;p2=0;
        small1=maxval;
        small2=maxval;
        for(j=0;j<i;j++)//从i个数字中选择最小的p1和次小的p2
        {
            if(ht[j].parent==-1)
            {
            if(ht[j].weight<small1)
            {
                small2=small1;
                small1=ht[j].weight;
                p2=p1;
                p1=j;
            }
            else if(ht[j].weight<small2)
            {
                small2=ht[j].weight;
                p2=j;
            }
            }
        }
        ht[p1].parent=i;
        ht[p2].parent=i;
        ht[i].lchild=p1;
        ht[i].rchild=p2;
        ht[i].weight=ht[p1].weight+ht[p2].weight;
    }
}
void bianma(codetype co[],int n)//编码
{  //从叶子结点出发向上回溯
    int i,j;
    codetype cd;//缓冲变量
    for(i = 0; i < n; i ++)
    {
        cd.start = n-1;
        int cur = i;
        int p = ht[cur].parent;
        while(p!=-1)//存在双亲时
        {
            if(ht[p].lchild == cur)
                cd.bit[cd.start] = '0';//左子树生成0
            else
                cd.bit[cd.start] = '1';//右子树生成1
            cd.start--;
            cur = p;
            p = ht[cur].parent;
        }
        for(j = cd.start+1; j<n; j++)
            co[i].bit[j] = cd.bit[j];
            co[i].start = cd.start;//将各个叶子结点的哈夫曼编码存在co数组之中并保存编码在位串中的起始位置
    }
}
void jiema(char str[], tree ht[], int n)//解码
{
    int  num = 2*n-1;//结点个数
    int i =0;
    int t;
    int k;
    k=strlen(str);
    while(i<k)
    {
        t = num-1;//根节点下标
        while((ht[t].lchild!=-1)&&(ht[t].rchild!=-1))
        {
            if(str[i] == '0')
                t = ht[t].lchild;
            else
                t = ht[t].rchild;
            i++;
        }
        printf("%c", ht[t].ch);
    }
}
void output(int n)//输出编码
{
    char st[1000];
    int i,j,k,q;
    scanf("%s",st);
    q=strlen(st);
    for(i = 0;i<q; i++)
    {
      for(j =0;j<n; j++)
        {
            if(st[i] == ht[j].ch)
            {
                for(k = co[j].start+1; k < n; k++)
                {
                    printf("%c", co[j].bit[k]);
                    str[p]=co[j].bit[k];//将编码保存在数组中以便译码时使用
                    p++;
                }
            }
        }
    }
    printf("\n");
}
int main()
{
    int n;
    scanf("%d",&n);
    creat(ht,n);
    bianma(co,n);
    output(n);
    jiema(str,ht,n);
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值