霍夫曼编码应用

//对于给定的一组密文,根据出现的次数建立霍夫曼树、生成霍夫曼编码、编码文件译码
//email:llu15@lzu.edu.cn
//本程序共定义了5个函数:菜单、霍夫曼树建立、霍夫曼编码生成、输入密码查看原文 以及排序函数
//本程序定义了2个结构体:主结构体记录各种信息,辅助结构体只记录权值和下标(方便排序)
#include<stdio.h>
// 定义存储结构体
typedef struct
{
    char ch;
    int weight;
    int lson;
    int rson;
    int parent;
    int bit[26];
    int start;
} huffnode;
huffnode huff[51];


// 定义辅助结构体,使用此来进行排序
typedef struct
{
    int weight;
    int adr;
}assit;
assit a[26];            //因为最多有26个英文字母,定义长度为26的辅助数组


//函数声明
int menu();
int crea_hufftree();
int huffman_code(int len);
int decode(int len);
void sort(assit a[], int length);




int main()
{
    menu();
    return 0;
}


//菜单函数
int menu()
{
    int choice,len;
    printf("        ****************************\n");
    printf("        *     1.建立霍夫曼树       *\n");
    printf("        *     2.生成霍夫曼编码     *\n");
    printf("        *     3.输入密码查看原文   *\n");
    printf("        *     4.退出系统           *\n");
    printf("        *                          *\n");
    printf("        *     请按顺序执行操作     *\n");
    printf("        *                          *\n");
    printf("        ****************************\n");
    printf("请输入选择:");
    scanf("%d",&choice);
    while(1)
    {
        switch(choice)
        {
            case 1:
                {
                    len=crea_hufftree();
                    break;
                }
            case 2:
                {
                    printf("字符霍夫曼编码:\n");
                    huffman_code(len);
                    break;
                }
            case 3:
                {
                    decode(len);
                    break;
                }
            case 4:
                {
                    system("cls");
                    printf("谢谢使用,再见!\n");
                    return 0;
                }
        }
        printf("\n请选择:");
        scanf("%d",&choice);
    }
    return 0;
}


//建立霍夫曼树函数
int crea_hufftree()
{
    int i,len=-1;
    char ch;
    for(i=0;i<=51;i++)                             //完成结构体初始化
    {
        huff[i].ch='\0';
        huff[i].weight=0;
        huff[i].lson=-1;
        huff[i].rson=-1;
        huff[i].parent=0;
    }
    printf("请输入字符串:");
    ch=getchar();                                  //吸收回车
    ch=getchar();
    while (ch!='\n')
    {                                              //读入的电文出现几次,将权设置成多少
i=0;
while(i<=len)
        {
            if (huff[i].ch==ch)
                {
                    huff[i].weight++;
                    break;
                }
            else i++;
        }
if (i>len)
        {
huff[i].ch=ch;
huff[i].weight=1;
len++;
}
ch=getchar();
}


for(i=0;i<=len;i++)                             //将存储数组复制到辅助数组
{
   a[i].adr=i;
   a[i].weight=huff[i].weight;
}


i=0;


while(i<len)                                    //要生成剩余的len个节点,所以循环len次
    {
        sort(a,len+1-i);                            //依据权值对辅助数组a的前len+1-i项排序
        i++;
        huff[len+i].weight=a[0].weight+a[1].weight; //生成根结点的值
        huff[len+i].lson=a[0].adr;                  //生成左子树
        huff[len+i].rson=a[1].adr;                  //生成右子树
        huff[a[0].adr].parent=len+i;                //记录父结点
        huff[a[1].adr].parent=len+i;                //记录父结点
        a[0].weight=huff[len+i].weight;             //将生成的二叉树作为辅助数组的第一个元素
        a[0].adr=len+i;
        a[1].weight=a[len-i+1].weight;              //将辅助数组的最后一个元素放到第二个元素的位置上
        a[1].adr=a[len-i+1].adr;                    //以上4个语句作用可以为减少排序的工作量
    }
    printf("\n恭喜!霍夫曼树建立成功,按2可以查看字符的霍夫曼编码\n");
    return len;
}


//生成霍夫曼编码函数
//自底向上开始(也就是从数组序号为零的结点开始)向上层层判断,最后输出生成的编码。
int huffman_code(int len)
{
    int c,p,i,j;
    for(i=0;i<=len;i++)
    {
        c=i;
        p=huff[i].parent;
        huff[i].start=len;
        while(p!=0)
        {
            if(huff[p].lson==c)                     //若在父结点左侧,则置码为 0,若在右侧,则置码为1
                huff[i].bit[huff[i].start]=0;
            else
                huff[i].bit[huff[i].start]=1;
            huff[i].start--;                        //记录每个叶结点编码的起始位
            c=p;
            p=huff[c].parent;                       //若父结点存在,则层层向上直到p=0(根结点)
        }
        printf("%c的霍夫曼编码为: ",huff[i].ch);
        for(j=huff[i].start+1;j<=len;j++)
            printf("%d",huff[i].bit[j]);
        printf("\n");
    }
    return 0;
}


//译码函数
int decode(int len)
{
    int i,j=0;
    char mima[100];
    i=2*len;                                  //从根结点开始往下搜索
    printf("输入霍夫曼编码组成的密码,我们可以为您翻译为原文\n(以#为结束标志):");
    fflush(stdin);                            //清空缓冲区
    gets(mima);                               //输入密码
    printf("\n译码后的字符为");
    while(mima[j]!='#')
    {
        if(mima[j]=='0')
        i=huff[i].lson;                       //密码为0,走向左孩子
        else
        i=huff[i].rson;                       //密码为1,走向右孩子
        if(huff[i].lson==-1)                  //如果遇到左孩子为-1,说明该结点是叶结点,可以输出字符了
        {
            printf("%c",huff[i].ch);
            i=2*len;                          //回到根结点
        }
        j++;
    }
    if(huff[i].lson!=-1&&mima[j]!='#')        //电文读完,但尚未到叶子结点,则输入电文有错
    printf("\n您输入的密码有错误\n");
    return 0;
}


//依据权值大小对辅助数组assit的前n-i项排序,采用冒泡排序方法
void sort(assit a[], int length)
{
    int i,j,tempt;
for (i=0;i<length-1;i++)
{
for (j=0;j<length-i-1;j++)
{
if (a[j].weight>a[j+1].weight)
{
tempt = a[j].weight;
a[j].weight=a[j+1].weight;
a[j+1].weight=tempt;
tempt = a[j].adr;
a[j].adr=a[j+1].adr;
a[j+1].adr=tempt;
}
}
}
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值