Huffman Tree


哈夫曼树

简介
当用 n 个结点(都做叶子结点且都有各自的权值)试图构建一棵树时,如果构建的这棵树的带权路径长度最小,称这棵树为“最优二叉树”,有时也叫“赫夫曼树”或者“哈夫曼树”。在构建哈弗曼树时,要使树的带权路径长度最小,只需要遵循一个原则,那就是:权重越大的结点离树根越近。

构建哈夫曼树的过程

  • 对于给定的有各自权值的 n 个结点,构建哈夫曼树有一个行之有效的办法:
  • 在 n 个权值中选出两个最小的权值,对应的两个结点组成一个新的二叉树,且新二叉树的根结点的权值为左右孩子权值的和;
  • 在原有的 n 个权值中删除那两个最小的权值,同时将新的权值加入到 n–2 个权值的行列中,以此类推;
  • 重复 1 和 2 ,直到所以的结点构建成了一棵二叉树为止,这棵树就是哈夫曼树。

c++代码
HUFFMAN.H

#include <string>
#include "vector"
#include "unordered_map"
#include "map"
#include "stack"
#ifndef HUFFMAN_HUFFMAN_H
#define HUFFMAN_HUFFMAN_H
typedef int elemType;

typedef struct Node {
    elemType weight;
    char c;
    struct Node *lChild = nullptr, *rChild = nullptr, *parent = nullptr;
}Node,*lNode;


class huffman {
private:std::map<char, std::string> codeMap;
    std::vector<std::vector<int>> code;
    std::vector<Node *> node_list;
    std::vector<Node *> node_list_bak;
    Node *root{};
    int findMinNode();
    void deleteNode(int pos);
public:
    huffman(const std::map<char, int>& list, int num);
    void generateTree();
    void generateCode();
    void decode(std::string str);
    void printCode();
    void encode();
    Node *returnNode();
};


#endif //HUFFMAN_HUFFMAN_H

HUFFMAN.C

//
// Created by ren on 2020/12/1.
//

#include "huffman.h"
#include "iostream"
#include <algorithm>
#include "unordered_map"
#include "map"
#include "stack"
huffman::huffman(const std::map<char, int>& list, int num) {
    code.resize(num);
    for (auto & it : list){
        Node *node = (Node *)malloc(sizeof(Node));
        node->c = it.first;
        node->weight = it.second;
        this->node_list.push_back(node);
    }
    this->node_list_bak = this->node_list;
}

void huffman::generateTree() {
    Node *nodeRight, *nodeLeft;
//    auto nodeRight = (Node *)malloc(sizeof(Node));
//    auto nodeLeft = (Node *)malloc(sizeof(Node));
    auto nodeParent = (Node *)malloc(sizeof(Node));
    nodeParent->parent = nullptr;
    nodeParent->c = '\0';
    nodeRight = node_list[findMinNode()];
    deleteNode(findMinNode());
    nodeLeft = node_list[findMinNode()];
    deleteNode(findMinNode());
    nodeParent->rChild = nodeLeft;
    nodeParent->lChild = nodeRight;
    nodeParent->weight = nodeRight->weight + nodeLeft->weight;
    nodeLeft->parent = nodeParent;
    nodeRight->parent = nodeParent;
    node_list.push_back(nodeParent);
    if (node_list.size() != 1) {
        this->generateTree();
    }else this->root = node_list[0];

}
void huffman::generateCode() {
    node_list = node_list_bak;
//    for (int i = 0; i < node_list.size(); ++i) {
//        std::cout << node_list[i]->c << std::endl;
//    }
    for (int i = 0; i < node_list.size(); ++i) {
//        std::vector<int> vec;
        char c = node_list[i]->c;
//        vec.push_back(node_list_bak[i]->c);
        Node *temp = node_list[i];
        while (true) {
            if (temp->parent == nullptr) break;
            if (temp->parent->lChild == temp)
                code[i].push_back(0);
            else if (temp->parent->rChild == temp)
                code[i].push_back(1);
            temp = temp->parent;
        }
        code[i].push_back(c);
        std::string str;
        std::reverse(code[i].begin(), code[i].end());
        for (int j = 1; j < code[i].size(); ++j) {
            str.push_back(std::to_string(code[i][j])[0]);
        }
        codeMap.insert(std::make_pair(code[i][0], str));


    }
}
int huffman::findMinNode() {
    int min = 0;
    for (int i = 0; i < node_list.size(); ++i) {
        if (node_list[min]->weight > node_list[i]->weight) min = i;
    }
    return min;
}

void huffman::deleteNode(int pos) {
    auto p = node_list.begin() + pos;
    node_list.erase(p);
}

void huffman::printCode() {
    for (int i = 0; i < code.size(); ++i) {
        std::cout << char(code[i][0]) << " ";
        for (int j = 1; j < code[i].size(); ++j) {
            std::cout << code[i][j];
        }
        std::cout << std::endl;
    }
}

Node *huffman::returnNode() {
    return root;
}

void huffman::decode(std::string str) {
    Node * node = root;
    for (int i = 0; i < str.size() + 1; ++i) {
        if (node->c){
            std::cout << node->c << " ";
            node = root;
        }
        if (str[i] == '0' and node->c == '\0'){
            node = node->lChild;
        }
        else if (str[i] == '1' and node->c == '\0'){
            node = node->rChild;
        }
    }
}

void huffman::encode() {
    std::string str;
    std::cin >> str;
    for (int i = 0; i < str.size(); ++i) {
        std::cout << codeMap[str[i]];
    }
}

MAIN.C

#include <iostream>
#include "huffman.h"
#include "unordered_map"
int main() {
    int num;
    std::cin >> num;
    std::map<char, int> l;
    std::string s = "abcdefghijklmnopqrstuvwxyz";
    for (int i = 0; i < num; ++i) {
        int weight;
        char c = s[i];
        std::cin >> weight;
        l.insert(std::make_pair(c,weight));
    }
    huffman tree(l, num);
    tree.generateTree();
    tree.generateCode();
    tree.printCode();
    std::cout << "encode data: ";
    tree.encode();
    std::cout << std::endl;
    std::cout << "decode data: ";
    std::string code;
    std::cin >> code;
    tree.decode(code);
}

声明:Hello World|版权所有,违者必究|如未注明,均为原创|本网站采用BY-NC-SA协议进行授权

转载:转载请注明原文链接 - Huffman Tree


我的朋友,理论是灰色的,而生活之树是常青的!