哈夫曼编码与解码

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define MAXNUM 60

typedef struct
{
    char ch;
    int weight; //权值,这个字符出现的频率
    int parent;
    int left;
    int right;
}HuffNode;

typedef struct
{
    char code[MAXNUM];
    int start;
}HuffCode;

HuffNode ht[MAXNUM*2]; //存放哈夫曼树

HuffCode hcd[MAXNUM]; //存放ht数组中对应的字符的编码

int n; //字符的个数

//初始化哈夫曼树ht
void initHt()
{
    char ch;
    int i;
    printf("input the count of points:");
    scanf("%d",&n);
    int total=2*n-1;
    for (i=0;i<total;i++)
    {
        ht[i].weight=0;
        ht[i].parent=-1;
        ht[i].left=-1;
        ht[i].right=-1;
    }
    for (i=0;i<n;i++)
    {
        getchar();
        printf ("Please input value of leaf node %d: \n", i);
        scanf("%c",&ht[i].ch);
    }
    for (i=0;i<n;i++)
    {
        printf ("Please input weight of leaf node %d: \n", i);
        scanf("%d",&ht[i].weight);
    }
}

    //构造哈夫曼树,看成有n棵树,选择权值最小的两棵树合并
void createHuffTree()
{
    int i=0,k;
    int minI,minJ;
    int f=0;
    minI=minJ=-1; //minI<minJ
    for(k=n;k<2*n-1;k++){
    //寻找ht中权值最小且无父结点的两个结点
        i=0;
        f=0;
        while(ht[i].ch!='\0'){
            if(ht[i].parent==-1){
              if(f==0){
                minI=i;
                f++;
              }else if(f==1){
                if(ht[i].weight<ht[minI].weight){
                    minJ=minI;
                    minI=i;
                }else
                    minJ=i;
                    f++;
                }else{
                    if(ht[i].weight<ht[minI].weight){
                        minJ=minI;
                        minI=i;
                    }else if(ht[i].weight<ht[minJ].weight)
                        minJ=i;
                    }
                }
                    i++;
            }
            //合并两个结点
            ht[k].ch='#';
            ht[k].left=minI;
            ht[k].right=minJ;
            ht[k].weight=ht[minI].weight+ht[minJ].weight;
            ht[k].parent=-1;
            ht[minI].parent=ht[minJ].parent=k;
        }
}

//将一个字符串反转
void reverse(char *str)
{
    int i,j;
    char ch;
    for(i=0,j=strlen(str)-1;i<j;i++,j--){
        ch=str[i];
        str[i]=str[j];
        str[j]=ch;
    }
}

//哈夫曼编码,通过父节点从下往上找
void createHuffCode()
{
    int i,j,length;

    for(i=0;i<n;i++){
        length=0;
        j=i;
        //给每个字符进行编码
        while(ht[j].parent!=-1){
            if(ht[ht[j].parent].left==j){
                hcd[i].code[length++]=0+'0';
            }else
                hcd[i].code[length++]=1+'0';
                j=ht[j].parent;
            }

        hcd[i].start=hcd[i].code[length-1]-'0';
        hcd[i].code[length]='\0';
        reverse(hcd[i].code);
    }


}

//哈夫曼解码,每次都从根节点开始搜索
int releaseHuffCode(char *str,char* code)
{
    int root=2*n-2;
    int length=0,i=0;
    while(code[i]){
        if(code[i]=='0'+0)
            root=ht[root].left;
        else if(code[i]=='0'+1)
            root=ht[root].right;
        else
            return 0;
    if(ht[root].left==-1 && ht[root].right==-1){
        str[length++]=ht[root].ch;
        root=2*n-2;
    }
    i++;
    }
    str[length]='\0';
    if(root==2*n-2)
        return 1;
    return 0;
}

//用户输入编码字符
void encode()
{
    int i=0,j,f=1;
    char str[1000];
    char code[1000]={'\0'};
    printf("\n请输入要编码的字符串(length<1000)\n");
    scanf("%s",str);
    while(str[i]){
        if(str[i]>='A'&&str[i]<='Z'){
    for(j=0;j<n;j++)
        if(str[i]==ht[j].ch){
            strcat(code,hcd[j].code);
            break;
        }
            i++;
        }else{
            f=0;
            break;
        }
    }
        if(f)
        puts(code);
    else
        printf("你输入的字符串错误!\n");
        printf("按任意键后重新选择!\n");
    getchar();
}

//用户输入解码字串
void decode()
{
    char str[1000];
    char code[1000];
    printf("\n请输入要解码的字串(用0和1表示)\n");
    scanf("%s",code);
    if(releaseHuffCode(str,code))
        puts(str);
        else
        printf("你输入的字串错误!\n");
    
    printf("按任意键后重新选择!\n");
    getchar();
}

//主函数
int main()
{
    int choice=1;
    initHt();
    createHuffTree();
    createHuffCode();
    while(choice){
        printf("\n请输入你的选择:1 ---- 编码 2 ---- 解码 0 ---- 退出\n");
        scanf("%d",&choice);
        switch(choice){
            case 1:
                encode();
                break;
            case 2:
                decode();
                break;
            case 0:
                printf("退出!\n");
                break;
            default:
                choice=1;
                printf("你的输入错误!按任意键后重新输入!\n");
                getchar();
                break;
            }
     }
    return 0;
}

测试数据:
/*
5
A
B
C
D
E
8
10
3
4
5
选择编码:ABBDE
结果为10111101100
*/

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值