zoukankan      html  css  js  c++  java
  • 哈夫曼树、哈夫曼编码

    简单的写了一下哈夫曼树和哈夫曼编码的类,用的是顺序存储。

    #include<bits/stdc++.h>
    
    using namespace std;
    
    struct node{
        int weight; // 权值
        int parent; // 双亲结点,在选取两个最小权值结点时也会用到
        int left; // 左孩子
        int right; // 右孩子
    };
    
    class Huffman{
    public:
        Huffman(int n, const int w[]); // 构造哈夫曼树
        void HuffmanCode(int n); // 哈夫曼编码
        void Decode(int m, char *s); // 译码
        ~Huffman(); // 删除哈夫曼树
    private:
        node *root; // 动态数组方式存储哈弗曼树结点,1~n为叶子结点
        char **code; // 存储哈夫曼编码
        int getMin(int n); // 获取最小值
        void Select(int n, int &s1, int &s2); // 选取两个最小值结点
    };
    
    Huffman:: Huffman(int n, const int w[]) { 
        int m = 2*n-1, i;
        int s1, s2;
    
        if(n <= 1) {
            cout << "Size error!" << endl;
            return;
        }
    
        root = new node[m+5];
        if(!root) {
            cout << "Malloc error!" << endl;
            exit(-1);
        }
    
        // 初始化
        node *p = root+1;
        for (i = 1; i <= n; ++i, ++(p)) {
            p->weight = w[i];
            p->parent = 0;
            p->right = 0;
            p->left = 0;
        }
        while(i <= m) {
            p->parent = 0;
            p++;
            i++;
        }
    
        // 选取两个最小值结点,和作为结点值建立双亲节点
        for (i = n+1; i <= m; ++i) {
            Select(i-1, s1, s2);
            root[s1].parent = root[s2].parent = i;
            root[i].left = s1;
            root[i].right = s2;
            root[i].weight = root[s1].weight+root[s2].weight;
        }
    }
    
    void Huffman:: HuffmanCode(int n) {
        code = new char*[n+5];
        if(!*code) {
            cout << "Malloc error1" << endl;
            exit(-1);
        }
    
        char *tmp = new char[n+5]; // 临时数组存储存储单个编码
        //char debug[100], dd;
        if(!tmp) {
            cout << "Malloc error2";
            exit(-1);
        }
        tmp[n-1] = 0;
        int st;
        for (int i = 1; i <= n; ++i) {
            st = n-1; // 从叶子结点找到根结点
            for (int j = i, f = root[j].parent; f; j = f, f = root[f].parent) {
                if(root[f].left == j)
                    tmp[--st] = '0';
                else if(root[f].right == j)
                    tmp[--st] = '1';
                //dd = tmp[st+1]; // debug
                //cout << "dd: " << dd << endl;
            }
            code[i] = new char[n-st];
            //strcpy(debug, tmp+st);
            //cout << "debug: " << debug << endl;
            strcpy(code[i], tmp+st);
        }
        delete []tmp;
        
        // 编码结果输出一下 
        for (int i = 1; i <= n; ++i) {
            cout << "The Huffmancode is " << root[i].weight << " : " << code[i] << endl;
        }
    }
    
    void Huffman:: Decode(int n, char *s) {
        int len = strlen(s), pt = 2*n-1;
        // 从根结点开始,若为0找左子树,为1找右子树
        for (int i = 0; i < len; ++i) {
            if(s[i] == '0') {
                pt = root[pt].left;
                if(pt <= n) { // 找到叶子结点输出权值,还原游标pt
                    cout << root[pt].weight << " ";
                    pt = 2*n-1;
                }
            } else if(s[i] == '1') {
                pt = root[pt].right;
                if(pt <= n) {
                    cout << root[pt].weight << " ";
                    pt = 2*n-1;
                }
            } else {
                cout << "Code error" << endl;
                exit(-1);
            }
        }
        cout << endl;
    }
    
    Huffman:: ~Huffman() {
        delete []root;
        delete []code;
        cout << "The Huffmantree has been destroyed." << endl;
    }
    
    int Huffman:: getMin(int n) {
        int Min = 100;
        int flag = 0; //用来记录已遍历过的结点
        for(int i = 1; i <= n; ++i) {
            if ((root + i)->weight < Min && (root + i)->parent == 0) {
                Min = (root + i)->weight;
                flag = i;
            }
        }
        //给选中的结点置 1, 下次不需要再遍历
        (root + flag)->parent = 1;
        return flag;
    }
    
    void Huffman:: Select(int n, int &s1, int &s2) {
        s1 = getMin(n);
        s2 = getMin(n);
        //目的是 s1 的权值要不大于 s2 的权值
        if ((root + s1)->weight > (root + s2)->weight) {
            swap(s1, s2);
        }
    }
    
    int main() {
        int n;
        cin >> n;
        int w[5];
        for (int i = 1; i <= n; ++i) {
            cin >> w[i];
        }
        Huffman h_test(n, w);
        h_test.HuffmanCode(n);
        h_test.Decode(n, "10011");
        return 0;
    }
    
    /*4
     *1 3 6 9*/
    
    
    
  • 相关阅读:
    工具资源系列之给 windows 虚拟机装个 mac
    工具资源系列之 github 上各式各样的小徽章从何而来?
    php 学习笔记之日期时间操作一箩筐
    2018-12-03 VS Code英汉词典插件v0.0.7-尝试词性搭配
    2018-11-29 VS Code英汉词典插件v0.0.6-改为TS实现, 加测试
    2018-11-27 中文代码示例之Programming in Scala笔记第七八章
    2018-11-23 手工翻译Vue.js源码:尝试重命名标识符与文本
    2018-11-21 手工翻译Vue.js源码第一步:14个文件重命名
    2018-11-16 中文代码示例之Programming in Scala笔记第四五六章
    2018-11-13 中文代码示例之Programming in Scala学习笔记第二三章
  • 原文地址:https://www.cnblogs.com/knightoflake/p/14801576.html
Copyright © 2011-2022 走看看