数据结构-哈夫曼树

        哈夫曼树是一种哈夫曼编码形成的树,是由美国数学家赫夫曼 1952 年发明的,所以也称赫夫曼编码。它是为了解决数据存储空间的问题的,压缩存储就是采用了赫夫曼编码,使得数据的存储变得更合理,这样就压缩了空间。举个例子,以下是分数的统计情况

 如果是正常程序来判断某个人的成绩等级时,就有

        但是如果把比例看作数据的权值(权值其实就是这种数据在所有数据中所占有的比例, 比例越大,权值越大) ,根据权值进行赫夫曼编码就会得到以下的树图

 

显然这样的树图比上面的效率更高一点。  

如何构建一颗哈夫曼树

        例如,给定我们以下四个结点 ABCD,他们的权值是 1548
        首先我们选取这些结点中权值最小的两个,使他们成为兄弟来自同一个双亲,双亲的权值为这两个结点权值的和,如图所示。

 

         这样之后 A 和 C 就进入哈夫曼树中了,同时衍生出了一个新结点我们暂时称为 A-C,权值为 AC 的和,那么此时还剩下的结点就是 BD 和 A-C,然后再选两个最小的,进行上述操作。

最后剩下 D 和新的结点,然后再重复操作,得到一颗哈夫曼树

 

 程序实现示例

结构定义示例

哈夫曼树结点结构定义示例:
typedef char TYPE; //数据类型
typedef int VType; //权值类型
typedef struct tnode
{
    TYPE date; //元素
    VType weight; //权值
    struct tnode *parents; //双亲结点
    struct tnode *lchild; //左孩子
    struct tnode *rchild; //右孩子
}TNode;

初始化结点示例

        首先要构建好所有结点元素,保存到链表中,按照权值升序排列,当然,方法很多,这只是其中一种生成哈夫曼树的方法而已。
Head *p=create_double_linkedist(); //构建管理链表
TYPE c;
VType n;
printf("请输入建立哈夫曼树的节点数据和权值,输入-1 结束\n");
for(n=0;n<N;n++)
{
    scanf("%c %d",&c,&n);
    if(n==0)
        break;
    //构建结点
    TNode *HuffTree = (TNode *)malloc(sizeof(TNode));
    HuffTree->date = c;
    HuffTree->weight = n;
    HuffTree->parents = NULL;
    HuffTree->lchild = NULL;
    HuffTree->rchild = NULL;
    insert_double_linkedist(p,HuffTree); //保存到链表中,按照权值升序排列
}
下面是链表的结构
typedef struct node //单链表结构体
{
    TNode *date; //哈夫曼树的结点
    struct node *next;
    struct node *prev;
}Node;
typedef struct head //管理链表结点
{
    int num;
    struct node *first; //头
    struct node *tail; //尾
}Head;

哈夫曼树构建示例

//创建一颗哈夫曼树
TNode *create_hafumantree(Head *p)
{
    if(p==NULL || p->num==0) //链表为空或没有结点
        return NULL;
    TNode *t = NULL;
    if(p->num==1)
    {
        t = p->first->date;
        return t;
    }
    int min1,min2,sum; //最小值,第二小值,和值
    while (p->num>1)
    {
        min1=p->first->date->weight; //赋值最小值
        min2=p->first->next->date->weight; //赋值第二小值
        sum=min1+min2; //和值
        //构建结点保存和值结点
        TNode *HuffTree = (TNode *)malloc(sizeof(TNode));
        HuffTree->date = 0; //无数据
        HuffTree->weight = sum; 
        HuffTree->parents = NULL;
        HuffTree->lchild = p->first->date;
        HuffTree->rchild = p->first->next->date;
        p->first->date->parents = HuffTree->rchild;
        p->first->next->date->parents = HuffTree->rchild;
        //最小和第二小的结点出链表
        delete_frist(p); //删除头节点
        delete_frist(p);
        insert_double_linkedist(p,HuffTree); //和值结点按权值升序插入链表
    }
    t = p->first->date; //最后一个链表节点就是根节点
    delete_frist(p); //清空链表
    return t; 
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

九月丫

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

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

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

打赏作者

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

抵扣说明:

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

余额充值