ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

哈夫曼树和哈夫曼编码

2022-01-25 15:05:51  阅读:180  来源: 互联网

标签:编码 结点 code 哈夫曼 二叉树 权值 Huffman


基础概念

 哈夫曼树又称最优二叉树,是一种带权路径长度最短的二叉树。

结点的权值:
将树中结点赋给一个含有某种含义的数值。记为:Wi(i=1,2,...n)
路径长度:
等于路径上的结点数减1。
结点的带权路径长度:
从根结点到该结点的路径长度与该结点的权值乘积。记为:Li(i=1,2,...n)。

树的带权路径长度:
树中所有叶子结点的带权路径长度之和
记为WPL
= (W1L1+W2L2+W3L3+...+WnLn),

如果让这N个结点,构成一棵有N个叶结点的二叉树,可以证明哈夫曼树的WPL是最小的。

哈夫曼树也是效率最高的判别树。( 判断树:用于描述分类的判断树)
注意:

  1. 满二叉树不一定是哈夫曼树;
  2. 哈夫曼树中权值越大的叶子离根越近
  3. 具有相同带权结点的哈夫曼树不惟一

构造思想

构造哈夫曼口诀:

  1. 构造森林全是根,
  2. 先用两小造新树,
  3. 删除两小添新人,
  4. 重复2,3剩单根

具体来说就是:

  1. 根据给定的n个权值{w1,w2,…,wn}构成二叉树集合F={T1,T2,…,Tn},其中每棵二叉树Ti中只有一个带权为wi的根结点,其左右子树为空.
  2. 在F中选取两棵根结点权值最小的树作为左右子树构造一棵新的二叉树,且置新的二叉树的根结点的权值为左右子树根结点的权值之和.
  3. 在F中删除这两棵树,同时将新的二叉树加入森林中.
  4. 重复2、3,直到F只含有一棵树为止.(得到哈夫曼树)
    image

构造代码

伪代码:

将n个结点放入集合S
while (S中的结点数 > 1){
取走S中2个权值最小的结点,计算它们值之和,并加入S
}
return 集合S剩下的结点 // 剩下的结点就是根结点

借助优先队列实现代码:

#include <bits/stdc++.h>
using namespace std;

struct Huffman
{
    Huffman *lchild;
    Huffman *rchild;
    double data;
};

struct cmp
{ /* 规定优先队列的排序规则 */
    bool operator()(Huffman *a, Huffman *b) const
    {
        return (a->data > b->data); /* 小顶堆 */
    }
};

int main()
{
    priority_queue<Huffman *, vector<Huffman *>, cmp> Q;

    double x;
    while (cin >> x)
    {
        Huffman *h = new Huffman();
        h->data = x;
        h->lchild = h->rchild = 0;
        Q.push(h);
    }

    Huffman *p;
    while (Q.size() > 1)
    { /* 如果Q剩余结点大于1,则执行循环体 */
        p = new Huffman();
        Huffman *p1, *p2;
        p1 = Q.top(); /* 依次取出权值最小的两个结点,放入p1和p2 */
        Q.pop();
        p2 = Q.top();
        Q.pop();

        /*
        计算两结点的权值之和,存入p,且因为
        p1->data <= p2->data,可以将权值小
        的结点存入p的左子树,权值大的结点存入p
        的右子树,最后将p放入Q中
        */
        p->data = p1->data + p2->data;
        p->lchild = p1;
        p->rchild = p2;
        Q.push(p);
    }
     Pre(F);
    return 0;
}

Huffman 编码

编码规则:
从根节点到每一个叶子节点的路径上,左分支记为0,右分支记为1, 将这些0与1连起来即为叶子节点的哈夫曼编码。如下图:
image

哈夫曼编码是最优前缀码
前缀编码:
要求任一字符的编码都不能是另一字符编码的前缀。
为什么哈夫曼编码是最优前缀码?

image

代码:

/*
code 变量的初始值是空字符串,采用二叉树后续遍历,如果是非叶子结点,
存在左子树就将code加"0",存在右子树就将code加"1",继续递归调用;
如果是叶子结点,就记录到键值对(map)里。
*/
void huffman_code(Huffman* h, string code, map<double, string>& map_huff)
{
    if (!h)
        return;
    if (h->lchild)
        huffman_code(h->lchild, code + "0", map_huff);
    if (h->rchild)
        huffman_code(h->rchild, code + "1", map_huff);
    if (h->lchild == 0 && h->rchild == 0) {
        map_huff[h->data] = code;
        return;
    }
}


实战

7-3 修理牧场 (25 分)

标签:编码,结点,code,哈夫曼,二叉树,权值,Huffman
来源: https://www.cnblogs.com/kingwz/p/15842967.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有