ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

哈夫曼树(Huffman树)原理分析及实现

2022-01-05 08:31:41  阅读:247  来源: 互联网

标签:Node code 哈夫曼 val nullptr pNode HuffmanTree 原理 Huffman


哈夫曼树(Huffman树)原理分析及实现

1 构造原理

假设有n个权值,则构造出的哈夫曼树有n个叶子结点。 n个权值分别设为 w1、w2、…、wn,则哈夫曼树的构造规则为:
  (1) 将w1、w2、…,wn看成是有n 棵树的森林(每棵树仅有一个结点);
  (2) 在森林中选出两个根结点的权值最小的树合并,作为一棵新树的左、右子树,且新树的根结点权值为其左、右子树根结点权值之和;
  (3)从森林中删除选取的两棵树,并将新树加入森林;
  (4)重复(2)、(3)步,直到森林中只剩一棵树为止,该树即为所求得的哈夫曼树。

显然对n个权值,构造哈夫曼树树需要合并n-1次,形成的树结点总数为2n-1;

例如:A:60, B:45, C:13 D:69 E:14 F:5 G:3

第一步:找出字符中最小的两个,小的在左边,大的在右边,组成二叉树。

F和G最小,因此如图,从字符串频率计数中删除F与G,并返回G与F的和 8给频率表

image-20220105081831621

重复第一步:

image-20220105081848649

image-20220105081907259

image-20220105081926271

image-20220105081940474

image-20220105081958021

编码规则:添加 0 和 1,规则左0 右1

image-20220105082019527

2 代码实现

根据哈夫曼树的构造原理,为方便实现,我们使用数组来存储每个结点,其命名为Tree;

2.1 节点结构

节点具有以下结构:

//结点结构
struct Node {
    int   val{0};           //节点的值
    Node* left{nullptr};    //节点的左孩子
    Node* right{nullptr};   //节点的右孩子
    Node* parent{nullptr};  //节点的父节点

    explicit Node(int value) : val(value) {}

    Node(int value, Node* pleft, Node* pRight, Node* pParent)
        : val(value), left(pleft), right(pRight), parent(pParent) {}
};

2.2 类的实现

Huffman.h

#include <iostream>
#include <queue>
#include <string>
#include <vector>

using namespace std;

struct Node {
    int   val{0};           //节点的值
    Node* left{nullptr};    //节点的左孩子
    Node* right{nullptr};   //节点的右孩子
    Node* parent{nullptr};  //节点的父节点

    explicit Node(int value) : val(value) {}

    Node(int value, Node* pleft, Node* pRight, Node* pParent)
        : val(value), left(pleft), right(pRight), parent(pParent) {}
};

class Compare  //比较类,用于构造Node*类型的priority_queue
{
public:
    bool operator()(Node* a, Node* b) {
        return a->val > b->val;  //结点的值越小越靠前
    }
};

class HuffmanTree {
public:
    HuffmanTree();

    ~HuffmanTree();

    Node* Create();

    void PreOrder(Node* pNode);

    void InOrder(Node* pNode);

    void PostOrder(Node* pNode);

    void Encode(Node* pNode, string code);

private:
    Node* root;  // 哈夫曼树头

    priority_queue<Node*, vector<Node*>, Compare> nodes;

    void destroyTree(Node* pNode);
};

Hufman.cpp

#include "Huffman.h"

HuffmanTree::HuffmanTree() {
    // priority_queue没有clear
    while (!nodes.empty()) nodes.pop();
    int a[] = {4, 3, 5, 8, 7, 9};
    int len = sizeof(a) / sizeof(a[0]);
    for (int i = 0; i < len; i++) { nodes.push(new Node(a[i])); }
    root = nullptr;
}

HuffmanTree::~HuffmanTree() {
    destroyTree(root);
}

void HuffmanTree::destroyTree(Node* pNode) {
    if (pNode == nullptr)
        return;
    destroyTree(pNode->left);
    destroyTree(pNode->right);
    delete pNode;
}

Node* HuffmanTree::Create() {
    while (nodes.size() > 1) {
        Node* p1 = nodes.top();
        nodes.pop();
        Node* p2 = nodes.top();
        nodes.pop();

        Node* cur  = new Node(p1->val + p2->val);
        cur->left  = p1;
        cur->right = p2;
        p1->parent = cur;
        p2->parent = cur;

        nodes.push(cur);
    }

    root = nodes.top();
    nodes.pop();

    return root;
}

void HuffmanTree::PreOrder(Node* pNode) {
    if (pNode == nullptr)
        return;
    cout << pNode->val << " ";
    PreOrder(pNode->left);
    PreOrder(pNode->right);
}

void HuffmanTree::InOrder(Node* pNode) {
    if (pNode == nullptr)
        return;
    InOrder(pNode->left);
    cout << pNode->val << " ";
    InOrder(pNode->right);
}

void HuffmanTree::PostOrder(Node* pNode) {
    if (pNode == nullptr)
        return;
    PostOrder(pNode->left);
    PostOrder(pNode->right);
    cout << pNode->val << " ";
}

void HuffmanTree::Encode(Node* pNode, string code) {
    //叶子节点的处理
    if (pNode->left == nullptr && pNode->right == nullptr)
        cout << pNode->val << " 被编码为 " << code << endl;

    if (pNode->left) {
        //左子树,编码code添加'0'
        code += "0";
        Encode(pNode->left, code);
        //编码code删除'0'
        code.erase(code.end() - 1);
    }

    if (pNode->right) {
        //左子树,编码code添加'1'
        code += "1";
        Encode(pNode->right, code);
        //编码code删除'1'
        code.erase(code.end() - 1);
    }
}

3 测试代码及输出

int main() {
    HuffmanTree obj;
    Node*       root = obj.Create();
    cout << "先序遍历: ";
    obj.PreOrder(root);
    cout << endl;

    cout << "中序遍历: ";
    obj.InOrder(root);
    cout << endl;

    cout << "后序遍历: ";
    obj.PostOrder(root);
    cout << endl;

    cout << "哈夫曼编码: ";
    obj.Encode(root, "");

    return 0;
}

正确输出:
image-20220105003326817

4 参考资料

1.哈夫曼树算法及C++实现
2.百度百科·哈夫曼树
3.数据结构:Huffman树(哈夫曼树)原理及C++实现

标签:Node,code,哈夫曼,val,nullptr,pNode,HuffmanTree,原理,Huffman
来源: https://www.cnblogs.com/paul-617/p/15765291.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有