哈夫曼树的最小堆实现

简介: 哈夫曼树的最小堆实现

哈夫曼树


定义

带权路径长度(WPL):设二叉树有n个叶子结点,每个叶子节点带有权值Wk,从根结点到每个叶子节点的长度为Lk,则每个叶子结点的带权路径长度之和就是:

WPL=∑ k=1nW k L k


特点

1.没有度为1的结点

2.n个叶子结点的哈夫曼树共有2n-1个结点

3.哈夫曼树的任意非叶子结点的左右子树交换后仍是哈夫曼树

4.同一组权值,存在不同构的哈夫曼树


图解

初始

image.png

第一次合并

image.png

第二次合并

image.png

第三次合并

image.png


模板

根据给定的n个权值,构造n棵只有根结点的二叉树。通过最小堆每次选取两棵根结点权值最小的树作为左右子树,构造一棵新的二叉树,并将其插入最小堆中。重复上述步骤,直到只有一棵树为止,这棵树就是哈夫曼树。

#include <iostream>
using namespace std;
#define MaxSize 1000
int A[] = {1, 3, 5, 8};
int A_length = 4;
struct TreeNode
{
    int weight;
    TreeNode *left;
    TreeNode *right;
};
struct MinHeap
{
    TreeNode **data; //这是一个数组,每个元素的类型为(TreeNode*),是指向某个哈夫曼树的指针
    int size;
    int capacity;
};
MinHeap *CreateHeap();                   // 初始化堆
TreeNode *CreateHT();                    // 初始化哈夫曼树
TreeNode *Delete(MinHeap *H);            // 删除最小堆元素
void Insert(MinHeap *H, TreeNode *Huff); // 插入最小堆元素
void PreOrderTraversal(TreeNode *Huff);  // 先序遍历
void BuildMinHeap(MinHeap *H);           // 建堆
TreeNode *Huffman(MinHeap *H);           // 哈夫曼树的构建
int main()
{
    MinHeap *H;
    TreeNode *Huff;
    H = CreateHeap();
    Huff = Huffman(H);
    PreOrderTraversal(Huff);
    system("pause");
    return 0;
}
// 初始化堆
MinHeap *CreateHeap()
{
    MinHeap *H;
    H = new MinHeap;
    H->data = new TreeNode *[MaxSize + 1]; // 每个元素的类型为(TreeNode*)
    H->capacity = MaxSize;
    H->size = 0;
    // 给堆设置哨兵,哨兵要小于堆内所有值
    TreeNode *Huff;
    Huff = CreateHT();
    Huff->weight = INT_MIN;
    H->data[0] = Huff;
    return H;
}
// 初始化哈夫曼树
TreeNode *CreateHT()
{
    TreeNode *Huff;
    Huff = new TreeNode;
    Huff->weight = 0;
    Huff->left = NULL;
    Huff->right = NULL;
    return Huff;
}
// 插入最小堆元素(哈夫曼树)
void Insert(MinHeap *H, TreeNode *Huff)
{
    int weight = Huff->weight;
    int i = ++H->size;
    for (; H->data[i / 2]->weight > weight; i /= 2)
    {
        H->data[i] = H->data[i / 2];
    }
    H->data[i] = Huff;
}
// 删除最小堆元素
TreeNode *Delete(MinHeap *H)
{
    int parent, child;
    TreeNode *T = H->data[1];
    TreeNode *tmp = H->data[H->size--];
    for (parent = 1; parent * 2 <= H->size; parent = child)
    {
        child = 2 * parent;
        if ((child != H->size) && (H->data[child + 1]->weight < H->data[child]->weight))
            child++;
        if (H->data[child]->weight >= tmp->weight)
            break;
        else
            H->data[parent] = H->data[child];
    }
    H->data[parent] = tmp;
    return T;
}
// 建堆
void BuildMinHeap(MinHeap *H)
{
    TreeNode *Huff;
    for (int i = 0; i < A_length; i++)
    {
        Huff = CreateHT();
        Huff->weight = A[i];
        Insert(H, Huff);
    }
}
void PreOrderTraversal(TreeNode *Huff)
{
    if (Huff)
    {
        cout << Huff->weight << " ";
        PreOrderTraversal(Huff->left);
        PreOrderTraversal(Huff->right);
    }
}
//构建哈夫曼树
TreeNode *Huffman(MinHeap *H)
{
    TreeNode *T;
    BuildMinHeap(H);
    int times = H->size;
    // 做times-1次合并
    for (int i = 1; i < times; i++)
    {
        T = new TreeNode;
        T->left = Delete(H);
        T->right = Delete(H);
        T->weight = T->left->weight + T->right->weight;
        Insert(H, T);
    }
    T = Delete(H);
    return T;
}
目录
相关文章
|
移动开发 vr&ar
数据库系统概论——关系代数详解
关系代数是一种抽象的查询语言,是关系数据操纵语言的一种传统表达方式,它是利用对关系的运算来表达查询的。任何运算都是将一定的运算符作用于一定的运算对象上,得到预期的运算结果。关系代数的运算对象是关系,运算结果亦为关系。集合运算符将关系看成元组的集合从关系的“水平”方向即行的角度来进行运算专门的关系运算符不仅涉及行而且涉及列算术比较符辅助专门的关系运算符进行操作逻辑运算符辅助专门的关系运算符进行操作。
2842 1
数据库系统概论——关系代数详解
|
存储 Java Maven
Javaweb之Maven仓库的详细解析
2.3 Maven仓库 仓库:用于存储资源,管理各种jar包 仓库的本质就是一个目录(文件夹),这个目录被用来存储开发中所有依赖(就是jar包)和插件
834 0
|
6月前
|
人工智能 JavaScript UED
如何实现两个下拉选择框 select选中联动效果?
本文通过一个公司与产品联动的下拉选择案例,详细讲解了Element UI中双向联动下拉框的实现方法。涵盖数据过滤、回显处理、重置功能及注意事项,结合Vue实战代码,帮助开发者提升表单交互体验,适用于各类关联选择场景的开发参考。(238字)
481 0
如何实现两个下拉选择框 select选中联动效果?
|
11月前
|
Ubuntu 数据库 数据安全/隐私保护
刚装好的ubuntu怎么联网
通过以上步骤和解决方案,你应该能够在刚装好的Ubuntu系统中成功联网。如果在联网过程中遇到其他问题或困难,可以查看Ubuntu的官方文档或在相关论坛和社区寻求帮助。
|
存储 Oracle 关系型数据库
【数据库-DB2】深入了解DB2 reorg
本文介绍了DB2数据库中reorg操作的重要性,旨在通过重组表数据来消除数据碎片、压缩信息并提高数据访问速度。reorg操作能够根据索引关键字重新排序数据,减少查询I/O次数,提升查询性能。文章详细讲解了reorg的操作步骤、适用场景及注意事项,强调了在执行reorg前后更新统计信息的必要性。
1279 2
|
存储 机器学习/深度学习 人工智能
多模态RAG实战指南:完整Python代码实现AI同时理解图片、表格和文本
本文探讨了多模态RAG系统的最优实现方案,通过模态特定处理与后期融合技术,在性能、准确性和复杂度间达成平衡。系统包含文档分割、内容提取、HTML转换、语义分块及向量化存储五大模块,有效保留结构和关系信息。相比传统方法,该方案显著提升了复杂查询的检索精度(+23%),并支持灵活升级。文章还介绍了查询处理机制与优势对比,为构建高效多模态RAG系统提供了实践指导。
2943 0
多模态RAG实战指南:完整Python代码实现AI同时理解图片、表格和文本
|
传感器 机器学习/深度学习 编解码
智能驾驶--语义分割 公开数据集 汇总
本文整理了10个质量较好,数据集较大,比较新的,图像语义分割的公开数据集;主要服务于智能驾驶方向(辅助驾驶、自动驾驶等)。
3678 0
|
人工智能 数据可视化 API
语义分割笔记(一):基于PaddleSeg使用Transfomer模型对航空遥感图像分割
这篇博客介绍了如何使用PaddleSeg和Transformer模型SegFormer B3对航空遥感图像进行语义分割,包括项目背景、数据集处理、训练步骤和代码实现。
1682 1
语义分割笔记(一):基于PaddleSeg使用Transfomer模型对航空遥感图像分割
|
机器学习/深度学习 算法 开发者
探索深度学习中的优化器选择对模型性能的影响
在深度学习领域,优化器的选择对于模型训练的效果具有决定性作用。本文通过对比分析不同优化器的工作原理及其在实际应用中的表现,探讨了如何根据具体任务选择合适的优化器以提高模型性能。文章首先概述了几种常见的优化算法,包括梯度下降法、随机梯度下降法(SGD)、动量法、AdaGrad、RMSProp和Adam等;然后,通过实验验证了这些优化器在不同数据集上训练神经网络时的效率与准确性差异;最后,提出了一些基于经验的规则帮助开发者更好地做出选择。