数据结构——HuffmanTree

简介: 数据结构——HuffmanTree

Huffman tree

基本术语

  • 路径和路径长度

    • 路径:在一棵树中,从一个结点往下可以达到的孩子或子孙结点之间的通路。
    • 结点的路径长度:从一个结点到另一个结点的路径上分支的数目。
  • 结点的权及带权路径长度

    • 结点的权:将树中结点赋予一个有着某种含义的数值。
    • 结点的带权路径长度:从根结点到该结点之间的路径长度与该结点的权的乘积。
  • 树的带权路径长度

    • 树中所有叶子结点的带权路径长度之和。
  • 赫夫曼树( Huffman tree )

    • 带权路径长度达到最小的二叉树即为赫夫曼树
在所有含 n 个叶子结点、并带相同权值的二叉树中,必存在一棵其带权路径长度取最小值的树,称为“ 最优二叉树”。

构造 Huffman tree

基本思想:使权大的结点靠近根
  • 根据给定的 n 个权值 {w1, w2, …, wn},构造 n 棵二叉树的集合F = {T1, T2, … , Tn},其中每棵二叉树中均只含一个带权值 为 wi 的根结点,其左、右子树为空树;
  • 在 F 中选取其根结点的权值为最小的两棵二叉树,分别作为左、

右子树构造一棵新的二叉树,并置这棵新的二叉树根结点的权值为其左、右子树根结点的权值之和;

  • 从F中删去这两棵树,同时加入

刚生成的新树;

  • 重复上述两步,直至 F 中只含一棵树为止。

哈夫曼构造算法实现

一棵有 n 个叶子结点的Huffman树有 2n-1 个结点
  • 采用顺序存储结构---一维结构数组
  • 结点类型定义

    typedef struct {
        ElemType elem;  // 结点值
        int weight;  // 权值
        int parent, lch, rch;
    }HTNode, *HuffmanTree;
  • 构造HuffmanTree

    • 输入初始n个叶子结点:置HT[1..n]的weight值
    • 进行以下n-1次合并,依次产生HT[i],i=n+1..2n-1:

      • 在HT[1..i-1]中选两个未被选过的weight最小的两个结点HT[s1]和HT[s2] (从parent = 0 的结点中选)
      • 修改HT[s1]和HT[s2]的parent值: parent=i
      • 置HT[i]:weight=HT[s1].weight + HT[s2].weight ,lch=s1, rch=s2
Status CreatHuffmanTree(HuffmanTree HT, int n){
    if (n <= 1)  // 结点数量不合法
        return ERROR;
    int m = 2 * n - 1;
    int i;
    int s1, s2;
    HT = new HTNode[m + 1];  // 0号单元未用,HT[m]表示根结点   
    for (i = 1;i <= m;++i) {
        HT[i].lch = 0;
        HT[i].rch = 0;
        HT[i].parent = 0;
    }
    for (i = 1;i <= n;++i)
        // 输入权值
        cin >> HT[i].weight;
    for (i = n + 1;i <= m;++i) {
        // 构造Huffman树
        Select(HT, i - 1, &s1, &s2);  // 在HT[k](1≤k≤i-1)中选择两个其双亲域为0, 且权值最小的结点, 并返回它们在HT中的序号s1和s2
        if (s1 != 0 && s2 != 0) {
            HT[s1].parent = i;
            HT[s2].parent = i;  //表示从F中删除s1,s2
            HT[i].lch = s1;
            HT[i].rch = s2;  //s1,s2分别作为i的左右孩子
            HT[i].weight = HT[s1].weight + HT[s2].weight;  //i 的权值为左右孩子权值之和
        }
    }
    return OK;
}

哈夫曼树的应用

哈夫曼编码

  • 算法实现

    Status CreatHuffmanCode(HuffmanTree HT, HuffmanCode& HC, int n) {
        if (n <= 1)
            return ERROR;
        int start, i;
        int f = 0, c;
        HC = new char* [n + 1];
        char* cd = new char[n];
        cd[n - 1] = '0';
        for (i = 1; i <= n; ++i) {
            while (f != 0) {
                // 从叶子结点开始向上回溯,直到根结点
                start = n - 1;
                c = i;
                f = HT[i].parent;
                if (HT[f].lch == c) cd[start] = '0';
                else cd[start] = '1';
                c = f;
                f = HT[f].parent;
            }
            HC[i] = new char[n - start];  // 编码数组
            strcpy(HC[i], &cd[start]);
        }
        delete cd;
        cd = NULL;
        return OK;
    }
  • 重要结论

    • 哈夫曼编码是不等长编码
    • 哈夫曼编码是前缀编码,即任一字符的编码都不是另一字符编码的前缀
    • 哈夫曼编码树中没有度为1的结点。若叶子结点的个数为n,则哈夫曼编码树的结点总数为 2n-1
    • 发送过程:根据由哈夫曼树得到的编码表送出字符数据
    • 接收过程:按左0、右1的规定,从根结点走到一个叶结点,完成一个字符的译码。反复此过程,直到接收数据结束
目录
相关文章
|
存储 算法 前端开发
常见数据结构
常见数据结构
62 0
|
3月前
|
存储 JavaScript 前端开发
复杂数据结构
【8月更文挑战第25天】
31 0
|
6月前
|
存储 算法 C#
C#编程与数据结构的结合
【4月更文挑战第21天】本文探讨了C#如何结合数据结构以构建高效软件,强调数据结构在C#中的重要性。C#作为面向对象的编程语言,提供内置数据结构如List、Array和Dictionary,同时也支持自定义数据结构。文章列举了C#实现数组、链表、栈、队列等基础数据结构的示例,并讨论了它们在排序、图算法和数据库访问等场景的应用。掌握C#数据结构有助于编写高性能、可维护的代码。
56 3
|
6月前
|
存储 算法 索引
数据结构每日回顾
数据结构每日回顾
38 1
|
存储 算法
【数据结构】这堆是什么
【数据结构】这堆是什么
|
算法 索引
数据结构 静态查找
数据结构 静态查找
225 0
数据结构 静态查找
uiu
|
存储 机器学习/深度学习 算法
我对八种常见数据结构的理解(一)
我对八种常见数据结构的理解(一)
uiu
132 0
我对八种常见数据结构的理解(一)
uiu
|
存储 算法 JavaScript
我对八种常见数据结构的理解(二)
我对八种常见数据结构的理解(二)
uiu
174 0
我对八种常见数据结构的理解(二)
|
算法 安全
初识数据结构
初识数据结构
211 0
初识数据结构