哈弗曼编码

来源:互联网 发布:mac 打开系统文件夹 编辑:程序博客网 时间:2024/06/05 02:34
#include "iostream"#include "queue"#include "vector"#include "string"using namespace std;struct huffmanTree{    char data;  //表示的字符    int weight;   //字符出现的频率,权值    int parent;  //父亲的下标    int lchild;  //左孩子下标    int rchild;  //右孩子下标    int index;   //自己的下标    int dir;     //本树的标识,dir=0为父亲的左孩子,dir=1为父亲的右孩子,dir=-1都不是    int size;    //本字符编码所需的位数;    string code;  //本字符的编码值,为一串二进制字符    huffmanTree()    {        weight = parent = lchild = rchild = dir = -1;        data = ' ';        size = 0;        code = "";    }    bool operator < (const huffmanTree &t) const    {        return weight > t.weight;    }};vector<huffmanTree> h; //相当于一个并查集,存储所有的父子关系priority_queue<huffmanTree> pq;  //存储数的优先队列,字符出现频率小的树先出队列int size = 0; // 待编码字符数目//初始化,将每一个字符作为一棵树//n为字符个数,c[]为字符,w[]为字符出现频率void init(int n, char c[], int w[]){    int i;    for(i=0; i<n; i++)    {        huffmanTree ht;  //树中只有一个节点        ht.parent = ht.lchild = ht.rchild = ht.dir = -1;        ht.data = c[i];        ht.weight = w[i];        ht.index = size++;        h.push_back(ht);          pq.push(ht);  //单节点树入队列    }}//进行编码void encode(){    huffmanTree ht1, ht2, ht;    while(pq.size()>=2)  //一直合并下去,当优先队列中只剩下一棵树时结束    {        ht1 = pq.top(); pq.pop();  //选择权值最小的两个根        ht2 = pq.top(); pq.pop();         ht.weight = ht1.weight + ht2.weight;  //将它们作为左右子树构造新树        ht.index = h[ht1.index].parent = h[ht2.index].parent = h.size(); //建立父子关系        ht.lchild = ht1.index;  //较小的为左子树        ht.rchild = ht2.index;  //较大的为右子树        ht.dir = -1;  //当前树为树根        h[ht1.index].dir = 0; //左子树编码为0        h[ht2.index].dir = 1; //右子树编码为1        h.push_back(ht);        if(pq.empty())            break;        pq.push(ht);    }    int i;    for(i=0; i<size; i++)    {        int index = i;        string s = "";        while(h[index].parent != -1)  //自底向上搜索并查集        {            s = (h[index].dir?"1":"0") + s;  //因为是自底向上,所以要倒过来            h[i].size++;   //编码所占位数增加            index = h[index].parent;        }        h[i].code = s;  //得到字符的二进制编码    }}void print(int n) //打印字符编码、编码所占总空间{    int i;    int sum = 0;    for(i=0; i<n; i++)    {        cout << h[i].data << "(" << h[i].weight << " k): " << h[i].code << endl;        sum += (h[i].size * h[i].weight);    }    printf("文件需要总的存储位数为:%d kbits\n", sum);}int main(){    int n = 6;    char c[] = {'a', 'b', 'c', 'd', 'e', 'f'};    int w[] =  {45,  13,  12,  16,   9,   5 };    init(n, c, w);     encode();    print(n);    return 0;}
0 0