C/C++ 数据结构(十三)哈夫曼树

本篇 核心知识点 :哈夫曼树(最优二叉树)全套概念、构造流程、WPL 计算

一、哈夫曼树(最优二叉树)

1 基础专业概念

(1)路径

概念:树中任意两个节点之间唯一的通路;

特性:二叉树两点有且仅有一条连通路径,无环路。

(2)路径长度

概念:路径上经过节点的数量;每经过一个节点,路径长度 + 1。

(3)节点权值

概念:给叶子节点赋予代表使用频率、权重的数值;只有叶子带权,中间节点无业务权值。

(4)带权路径长度 WPL

概念:单个叶子节点 路径长度 × 自身权值;整棵树 WPL = 所有叶子带权路径之和

(5)哈夫曼树(最优二叉树)

概念:给定一组叶子权值,构造出整树 WPL 最小的二叉树,称为哈夫曼树。

特性:

  1. 哈夫曼树形态不唯一,但所有合法构造的 WPL 一定相等;

  2. 不存在度为 1 的节点,所有中间节点度均为 2;

  3. 应用场景:文件数据压缩编码(哈夫曼编码)。

2 哈夫曼树标准构造步骤

  1. 将所有权值作为独立叶子节点,存入有序容器(升序排列);

  2. 取出当前权值最小的两个节点,作为新节点的左右子树;

  3. 新节点权值 = 两个子节点权值之和;

  4. 删除刚才取出的两个最小节点,将新生成的父节点放回容器重新排序;

  5. 重复 2~4 步,直到容器仅剩余 1 个节点,该节点为哈夫曼树根。

3 构造示例 + WPL 计算

给定权值数组 {2,2,3,4,5}

  1. 首轮最小 2、2 → 新节点 4,剩余{3,4,5,4}

  2. 次轮最小 3、4 → 新节点 7,剩余{4,5,7}

  3. 次轮最小 4、5 → 新节点 9,剩余{7,9}

  4. 最后 7、9 合并根 16

    WPL 计算:

    2×3 + 2×3 + 3×2 + 4×2 + 5×2 = 6+6+6+8+10 = 36

拓展特性

不同合并顺序会生成形态不同哈夫曼树,但全局 WPL 数值完全一致。

4 代码框架(哈夫曼树节点)

复制代码
#include <unordered_map>
#include <iostream>
#include <string>
using namespace std;

int main(){
    unordered_map<string, int> equip;
    // 下标插入,键不存在自动创建
    equip["长剑"] = 120;
    // insert插入,重复键无效
    equip.insert(pair<string,int>("法杖",95));
    // 遍历
    for(auto& item : equip)
        cout << item.first << " 攻击:" << item.second << endl;
    // 查找
    if(equip.find("长剑") != equip.end())
        cout << "武器存在" << endl;
    return 0;
}