zoukankan      html  css  js  c++  java
  • 哈夫曼树与哈夫曼编码

    哈夫曼树是一种简单的树结构,建树过程如下:

    给出一组数据,不断选择最小的两个数,并用两个数的和作为它们的parent节点,再从数据中删除这两个数,将两个数的和加入数据中,直到所有的数据都被加入树结构,形成一颗树。

    这颗树的所有非叶子节点都有两个child,两个child的值的和则是这个节点的值,根节点是初始数据的总和。

    哈夫曼树有多种用途,这里讲解一下哈夫曼编码。

    哈夫曼编码是将所给数据生成哈夫曼树后,从根节点开始,给每个节点的left child添加一位编码0,right child添加一位编码1,如图,编码完成后,则每个节点有了对应的二进制编码,如图中值为2的节点编码为010100,值为13的节点编码为00.

    哈夫曼树有广泛的应用,例如在建立字库时,根据每个字符的使用频率,将使用频率高的字符编一个较短的编码,而将使用频率低的字符编一个较大的编码,来有效的节省空间。下面我展示一下哈夫曼编码的代码。

    #pragma once
    #include <queue>
    #include <string>
    
    int huffman_N;
    std::string huffman_code_res[MAX_N];
    
    struct Node
    {
        int id, freq, left, right;
        void init(int i, int f)
        {
            id = i;
            freq = f;
            left = right = INF;
        }
        bool operator<(const Node &a) const
        {
            return a.freq < freq;
        }
    } huffman_node[2 * MAX_N];
    
    void add_huffman_code(Node tmp)
    {
        huffman_code_res[tmp.left] = huffman_code_res[tmp.id] + "0";
        huffman_code_res[tmp.right] = huffman_code_res[tmp.id] + "1";
        if (huffman_node[tmp.left].left != INF) add_huffman_code(huffman_node[tmp.left]);
        if (huffman_node[tmp.right].left != INF) add_huffman_code(huffman_node[tmp.right]);
    }
    
    void make_huffman_tree()
    {
        std::priority_queue<Node> pq;
        for (int i = 0;i < huffman_N;++i)
        {
            pq.push(huffman_node[i]);
            huffman_code_res[i] = "";
        }
        Node a, b;
        while (!pq.empty())
        {
            a = pq.top();pq.pop();
            if (pq.empty()) break;
            b = pq.top();pq.pop();
            huffman_node[a.id + huffman_N] = { a.id + huffman_N,a.freq + b.freq,a.id,b.id };
            pq.push(huffman_node[a.id + huffman_N]);
        }
        add_huffman_code(a);
    }

    之后我用图中树进行一次测试:

    void huffman_codeTest()
    {
        cin >> huffman_N;
        for (int i = 0;i < huffman_N;++i)
        {
            int tmp;
            cin >> tmp;
            huffman_node[i].init(i, tmp);
        }
        make_huffman_tree();
        for (int i = 0;i < huffman_N;++i)
            cout << i << " " << huffman_node[i].freq << " " << huffman_code_res[i] << endl;
    }

    测试结果如下:

    7
    2 3 5 8 13 15 18
    0 2 11110
    1 3 11111
    2 5 1110
    3 8 110
    4 13 00
    5 15 01
    6 18 10
    请按任意键继续. . .

    可以看到,虽然由于建树顺序的差别,和图中编码有所不同,但是位数一致,哈夫曼树成功的按照使用频率的区别给不同的id进行了编码。根据结果来推断,这棵树的样子是下面这样:


  • 相关阅读:
    猴子选大王(约瑟夫环)
    centos 安装thrift
    KMP字符串匹配算法
    会话技术整理
    PHP数组整理版
    PHP基础知识6【系统内置函数--数组】
    PHP基础知识5【系统内置函数--字符串】
    PHP基础知识笔记4
    PHP基础知识笔记3
    PHP基础知识笔记2
  • 原文地址:https://www.cnblogs.com/cielosun/p/5654592.html
Copyright © 2011-2022 走看看