当前位置: 首页 > article >正文

浅谈【数据结构】树与二叉树之哈夫曼树

目录

1、哈夫曼树

1.1哈夫曼编码

1.2哈夫曼树

1.3构建一棵哈夫曼树


谢谢帅气美丽且优秀的你看完我的文章还要点赞、收藏加关注

没错,说的就是你,不用再怀疑!!!

希望我的文章内容能对你有帮助,一起努力吧!!!


1、哈夫曼树

1.1哈夫曼编码

在电报通信过程中,电文是以二进制0/1序列传送的,每一个字符对应了一个二进制的编码。

为了缩短按电文长度,采用不等长的编码方式,把使用频率较高的字符采用短编码。使用频率低的字符 采用长的编码。

1.2哈夫曼树

哈夫曼树:又称为最优二叉树

它是由n个带权的叶子结点构成的所有二叉树中,带权路径长度 WPL 最小的二叉树

一棵树的带权路径长度:树中所有叶子结点的带权路径长度之和。

结点的带权路径长度:从根结点开始到该结点的路径的长度与该结点上的权值的乘积。

1.3构建一棵哈夫曼树

假设N个权值,分别为W1,W2,W3....Wn的叶子结点,构建这一棵哈夫曼树的规则:

  • 第一步:
    • 构建森林
      • 把每一个叶子结点作为一棵独立的树看待(只有根结点的树),这样就拥有了n棵树的以 一个森林
      • 把森林存放到一个优先队列(不是队列)中,方便取出最小的结点。
  • 第二步:
    • 从优先队列中取出权值最小的两棵树(结点),再创建一棵新结点,将新结点设为两个最小结 点的父结点。父结点的权值就是两个结点的权值之和。
  • 第三步:
    • 将创建好的新结点加入到优先队列中。
  • 第四步:
    • 重复第二步和第三步直到优先队列中只剩一个结点,该节点就是哈夫曼树的根结点。

***示例代码***

#include <iostream>
#include <queue>


template <typename __queue_node_type__>
class priorityQueue
{
private:
    typedef struct node
    {
        __queue_node_type__ data;
        struct node *next;
    }Node;

    Node *first;
    Node *final;
    int   count;
public:
    priorityQueue()
        :first(nullptr)
        ,final(nullptr)
        ,count(0)
    {}
    ~priorityQueue()
    {}
    void push(__queue_node_type__ data_t)
    {
        // 新结点
        Node *new_ptr = new Node;
        new_ptr->data = data_t;
        new_ptr->next = nullptr;

        // 是否为链表中第一个结点
        if(count == 0)
        {
            first = new_ptr;
            final = new_ptr;
            // 更新个数
            count++;
            return;
        }
        else
        {
            if(first->data > data_t)
            {
                new_ptr->next = first;
                first = new_ptr;
                // 更新个数
                count++;
                return;
            }
            // 查找插入位置
            Node *node_ptr = first;
            while(node_ptr->next)
            {
                if(node_ptr->data > data_t)
                {
                    new_ptr->next = node_ptr->next;
                    node_ptr->next = new_ptr;
                    count++;
                    return;
                }
                node_ptr = node_ptr->next;
            }
        }

        final->next = new_ptr;
        final = new_ptr;
        count++;
        return;
    }
    __queue_node_type__ pop()
    {
        if(count == 0)
            throw int(-1);
        __queue_node_type__ data_t = first->data;

        Node *node_ptr = first;
        first = first->next;

        node_ptr->next = nullptr;
        delete node_ptr;
        count--;
        return data_t;
    }
    int length() const
    {
        return count;
    }
};



template <typename __tree_node_type__>
class HafuManTree
{
private:
    typedef struct node
    {
        __tree_node_type__ weight;
        struct node *lchild;
        struct node *rchild;
    } Node;

    Node *root;
public:
    HafuManTree(std::initializer_list<__tree_node_type__> list)
     : root(nullptr)
    {
        // 构建森林
        // 创建一个优先队列
        priorityQueue<Node*> queue;

        // 第一步:把所有的结点存入优先队列
        for(auto var : list)
        {
            Node *node_ptr = new Node;
            node_ptr->weight = var;
            node_ptr->lchild = nullptr;
            node_ptr->rchild = nullptr;
            queue.push(node_ptr);
        }

        // 第四步:重复第二步和第三步
        while(queue.length()!=1)
        {
            // 第二步:取出权值最小的两棵树(结点),再创建一棵新结点
            Node* data1 = queue.pop();
            Node* data2 = queue.pop();
            
            // 第三步创建新结点作为两个结点的父节点
            Node* newfather = new Node;
            newfather->weight = data1->weight + data2->weight;

            newfather->lchild = data1;
            newfather->rchild = data2;

            // 把新结点存入优先队列
            queue.push(newfather);
        }

        // 最后一个元素是哈夫曼树的根结点
        root = queue.pop();
    }


    ~HafuManTree(){}

    void levelprint()
    {
        std::queue<Node*> queque;

        queque.push(root);

        while(queque.size())
        {
            Node *node_ptr = queque.front();
            queque.pop();

            if(node_ptr->lchild)
                queque.push(node_ptr->lchild);
            if(node_ptr->rchild)
                queque.push(node_ptr->rchild);
            std::cout << node_ptr->weight << std::endl;
        }
    }
};


int main()
{
    HafuManTree<int> tree({1,2,3,4,5,6,7,8,9});

    tree.levelprint();
    return 0;
}


http://www.kler.cn/news/283212.html

相关文章:

  • 【Java设计模式】集合管道模式:简化数据操作
  • 买对不买贵,宠物空气净化器应该怎么选才能选到好的产品
  • 大数据技术之Flume 企业开发案例——负载均衡和故障转移(6)
  • SIGFPE (Arithmetic exception)
  • [Meachines] [Medium] Bastard Drupal 7 Module Services-RCE+MS15-051权限提升
  • 参数高效的模型微调
  • 【学习笔记】技术分析-华为智驾控制器MDC Pro 610分析
  • 怎么自定义spring security对用户信息进行校验及密码的加密校验
  • 关于springboot的异常处理以及源码分析(二)
  • 【面试04】ARM架构问题
  • 从 MLOps 到 LMOps 的关键技术嬗变
  • 红黑树刨析(删除部分)
  • 阿里PAI-ChatLearn:大规模 Alignment高效训练框架正式开源
  • 【C++笔记】类和对象的深入理解(一)
  • MySQL:简述数据库的主从复制
  • 08:字符串
  • 用mintupgrade工具将Linux Mint 21.3升级到Linux Mint 22失败的解决办法
  • Python私教张大鹏FastAPI开源框架和项目第一次整理 20240830
  • chapter09-OOP高级部分——(抽象类模版设计模式)——day12
  • Android APK打包脚本
  • 非阻塞式定时器 apscheduler
  • 力扣8.28
  • 2024年八大在线流程图工具推荐,快来试试吧!
  • 基于asp.net的在线考试系统源码分享
  • Mysql8.x配置详解
  • 回归预测|基于CNN-LSTM-Attention结合Adaboost集成数据预测Matlab程序 多特征输入单输出
  • 喜羊羊做Python二级(模拟考试--易错点)
  • 算法练习: 矩阵置零
  • 对于虚拟机上的相关命令
  • leetcode 19.删除链表的倒数第N个结点