对26个英文字母进行huffman编码

<ol><li class="alt"><span><span class="comment">1、建立哈夫曼树</span> </span></li><li><span><span class="comment">2、从每个叶结点回溯到root的路径,并记录路径,则为哈夫曼编码</span> </span></li><li class="alt"><span><span class="comment">3、查表方式获得每个字符的哈夫曼编码</span> </span></li></ol>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
///----------------------定义结点数据---------------
#define leave 26
#define node (26*2-1)
typedef struct nodee
{
    char character;
    float weight;
    int lson;
    int rson;
    int par;
}Node,*pnode;

typedef struct code
{
    int hufcode[leave];///叶节点最长编码位数应该为树的最长路径 ,储存编码结果
    int sta;  ///编码起始位(相对编码数组)
    char Char; ///编码的字符值

}Code,*pcode;

///----------------------构造哈夫曼树----------------
void huffman(Node ht[],float wt[])
{
    int i,j,x1,x2;
    float min1,min2;
///初始化结点数组ht  ,即对huffman树进行初始化
    for(i=0;i<node;i++)
    {
        ht[i].par=-1;
        ht[i].lson=-1;
        ht[i].rson=-1;
        if(i<leave)
        {
            ht[i].weight=wt[i];
            ht[i].character=i+65;///A-Z的ASCii码
        }
        else
        {
            ht[i].weight=0;
            ht[i].character='?';///生成的中间结点字符值标记为'?'
        }
    }
///控制n-1次结点的结合(若有n个叶结点)
    for(i=1;i<leave;i++)
    {
        min1=min2=100;///min1、min2记录当前最小、次小权值
        x1=x2=0; ///x1、x2记录当前最小次小权值结点的位置(数组标号)
        for(j=0;j<leave-1+i;j++) ///在[0-j]范围内找最小次小权值结点
        {
            if(ht[j].par==-1 && ht[j].weight<min1)///parent元素的判断是为了排除已结合过的结点,结合过的结点parent有正值
            {
                min2=min1;///当前结点权值小于最小值,所以当前结点变成最小权值结点,原最小结点变成原来的次小结点
                x2=x1;
                min1=ht[j].weight;
                x1=j;
            }
            else
            {
                if(ht[j].par==-1 && ht[j].weight<min2) ///当前结点权值大于最小值,小于次小值,则取代次小结点
                {
                    min2=ht[j].weight;
                    x2=j;
                }
            }
        }

        ///将找到的最小、次小权值结点结合成树,为其父结点赋值,可见该哈夫曼树的根节点应该是ht数组最后一个结点ht[node-1]
        ht[x1].par=leave-1+i;
        ht[x2].par=leave-1+i;
        ht[leave-1+i].weight=ht[x1].weight+ht[x2].weight;
        ht[leave-1+i].lson=x1;
        ht[leave-1+i].rson=x2;
    }
}
///--------------------获取并保存每个叶节点的哈夫曼编码供解码时查询--------------------------
void codeht(Node ht[],Code hc[])
{
    int i,j,d,p;
    Code x;
///依次每个叶结点(在哈夫曼结点数组的最前面的空间中)寻找双亲直到root,记录路径,路径就是哈夫曼编码

    for(i=0;i<leave;i++)///从每个字母都向上找寻根节点,使得整个树完整的编码
    {
        x.Char=ht[i].character;
        x.sta=leave-1;///默认编码起点为编码数组最后一位
        d=i;
        p=ht[i].par;
        while(1)
        {
            if(ht[p].lson == d)
                x.hufcode[x.sta]=0;///默认编码为左0右1
            else if(ht[p].rson==d)
                x.hufcode[x.sta]=1;
            else
               printf("ERROR!!");


            d=p;
            p=ht[d].par;///继续向着根延伸编码
            if(p==-1)break;///到了26个字母以外停止,ht[i]为root结点退出循环,说明已经回溯到了根结点

            x.sta--;
        }
        for(j=x.sta;j<leave;j++)
        {
            hc[i].hufcode[j]=x.hufcode[j];
        }
        hc[i].sta=x.sta;
        hc[i].Char=x.Char;
    }
}
///--------------------输出每个字符的的哈夫曼编码------------------------
void printcode(Code hc[])
{
    int i,j;
    for(i=0;i<leave;i++)
    {
        printf("字母%c的huffman编码为:",hc[i].Char);
        for(j=hc[i].sta;j<leave;j++)
        {
            printf("%d",hc[i].hufcode[j]);
        }
        printf("\n");
    }
}
///-----------------------查询字符的编码---------------------------
void findcode(Code hc[])
{
    int i,j;
    char x;
    printf("请输入一个大写英文字母:");
    while(scanf("%c",&x)!=EOF)
    {
        getchar();
        for(i=0;i<leave;i++)
        {
            if(x==hc[i].Char)
            {
                printf("字符%c的huffman编码为:",x);
                for(j=hc[i].sta;j<leave;j++)
                {
                    printf("%d",hc[i].hufcode[j]);
                }
                printf("\n");
            }
        }
        printf("请输入一个大写英文字母:");
    }


}

///---------------------主函数-----------------------
int main()
{
    Node huftree[node];///存放所有结点数据
    Code hcode[leave];///存放所有的编码结果
    ///存放叶结点权值
    float wt[leave]={0.0856,0.0139,0.0297,0.0378,0.1304,0.0289,0.0199,0.0528,0.0627,0.0013,0.0042,0.0339,0.0249,0.0707,0.0797,0.0199,0.0012,0.0677,0.0607,0.1045,0.0249,0.0092,0.0149,0.0017,0.0199,0.0008};
    huffman(huftree,wt);
    codeht(huftree,hcode);
    printcode(hcode);///调用可以输出所有的字母编码
    findcode(hcode);
    return 0;
}

  • 8
    点赞
  • 40
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值