某套通信系统含有8 种字符,每种字符出现概率分别为{2, 15, 30, 8, 10, 5, 12, 18},为其设计Huffman 编码。赫夫曼编码,C语言实现。

数据结构之赫夫曼编码

!!!注意!!!

创建文件时请以.cpp结尾,否则报错。

算法思想:

1、创建赫夫曼树:赫夫曼树可以储存在一个大小为2n-1的数组中,数组的每个成员包含了四个信息:权值,双亲,左孩子,右孩子。初始化数组时,可以对前n个元素赋权值,其余成员赋0值;(n+1)到(2n-1)的元素全部赋0。构建赫夫曼树其实就是在森林中寻找双亲为0与权值最小的两个节点,对其赋值,直到仅剩下一个节点时,该节点即为赫夫曼树的根节点。

2、求赫夫曼编码:从叶子到根逆向求编码。从HT【1】开始,判断该节点是左孩子还是右孩子。若为左孩子,则编码’0’;若为右孩子,则编码‘1’。继续寻找该节点的双亲,继续判断,直到双亲=0。此时该字符的赫夫曼编码完成。

流程图:
1

2

#include<stdio.h>
#include<stdlib.h>
#include<string.h>

#define TRUE 1                /*状态码预定义*/
#define FALSE 0
#define OK 1
#define ERROR 0
#define INFEASIBLE -1
#define OVERFLOW -2

#define MAXIUMWEIGHT 999999   /*最大权值*/

typedef int Status;

typedef struct
{
    unsigned int weight;   /*权值*/
    unsigned int parent,lchild,rchild;   /*双亲,左孩子,右孩子*/
}HTNode,*HuffmanTree;

 typedef char * * HuffmanCode;   //二级指针

Status Select(HuffmanTree HT,int n,int *s1,int *s2)    /*选择函数,找出HT中最小权值的两个节点*/
{
    int i,small_1=MAXIUMWEIGHT,small_2=MAXIUMWEIGHT;
    *s1=*s2=1;
    for(i=1;i<=n;i++)
    {
        if(HT[i].parent==0)   /*无双亲*/
        {
            if(HT[i].weight<small_1)   
            { 
                small_2=small_1;   //更新第二最小权值
                small_1=HT[i].weight;
                *s2=*s1;
                *s1=i;
            }
            else if(HT[i].weight<small_2)
            {   
                small_2=HT[i].weight;
                *s2=i;
            }
        }
    }
    return OK;
}

Status HuffmanCoding(HuffmanTree &HT,HuffmanCode &HC,unsigned int *w,int n) //c++的取引用,所以文件后缀名为.cpp,否则报错。
{
    int m,i,s1,s2,start;   
    int c,f;
    char *cd;
    HuffmanTree p;
    if(n<1) return  ERROR;
    m=2*n-1;   //节点数
    HT=(HuffmanTree)malloc((m+1)*sizeof(HTNode));  //给HT分配内存空间,相当于定义了HT[m+1]
    p=(HuffmanTree)malloc((m+1)*sizeof(HTNode));   //若用p来对HT操作,则类型与HT需相同,分配相同空间大小,否则运行可能不成功,实际以编译器为准
    for(p=HT+1,i=1;i<=n;++i,++p,++w) 
	{
		/*注释里的为MinGW编译器下编译*/
        //*(p+1)={w[i-1],0,0,0};   //教材上写*p={w[i-1],0,0,0}; 其实不然,因为HT[0]闲置不用,所以要从p+1开始。p=HT[0]
		p->weight=*w;  //适用于vc++6.0的写法
		p->lchild=0;
		p->rchild=0;
		p->parent=0;
	}
    for(;i<=m;++i)
	{
		/*注释里的为MinGW编译器下编译*/
        //HT[i]={0,0,0,0};  //节点置零操作
		HT[i].weight=0;  //适用于vc++6.0的写法
		HT[i].parent=0;
		HT[i].rchild=0;
		HT[i].lchild=0;
	}
    for(i=n+1;i<=m;++i)  //i从n+1开始是因为前n个节点已有初始权值,且都为叶子
    {
        Select(HT,i-1,&s1,&s2);
        HT[s1].parent=i;  //给叶子寻找双亲
        HT[s2].parent=i;
        HT[i].lchild=s1;  //给双亲加节点
        HT[i].rchild=s2;
        HT[i].weight=HT[s1].weight+HT[s2].weight;  //双亲也有权值,也得加入判断
    }
    //从叶子到根逆向求每个字符的赫夫曼编码
    HC=(HuffmanCode)malloc((n+1)*sizeof(char *));  //相当于HC[n+1] , HC[i]的类型为字符指针类型
    cd=(char *)malloc(n*sizeof(char));   //串
    cd[n-1]='\0';  //最后一个是终止符
    for(i=1;i<=n;++i)  //有n个叶子
    {
        start=n-1;   //从叶子开始,所以赋值从后往前赋
        for(c=i,f=HT[i].parent;f!=0;c=f,f=HT[f].parent)   //先找节点,再找双亲f,再找f的双亲,直到根节点
        {
            if(HT[f].lchild==c)  cd[--start]='0';  //如果叶子为左子,则编码0
            else cd[--start]='1';  //右子为1
            HC[i]=(char*)malloc((n-start)*sizeof(char));  //不确定编码的长度,所以继续分配空间,注意下标为i,表示每个字符的编码
            strcpy(HC[i],&cd[start]);  //字符串复制
        }
    }
    free(cd);  //释放工作空间
    return OK;
}

Status PrintHuffmanCode(HuffmanCode HC,unsigned int *w,int n)  //简单的打印编码函数
{
    printf("Huffman code : \n");
    for(int i = 1; i <= n; i++)
        printf("%d code = %s\n",w[i-1], HC[i]);
    return OK;
}

int main()
{
    unsigned int w[8]={2,15,30,8,10,5,12,18};  //字符权值数组
    HuffmanCode HC;  
    HuffmanTree HT;
    HuffmanCoding(HT,HC,w,8);
    PrintHuffmanCode(HC,w,8);
    return 0;
}


评论 18
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Akihiris

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值