DS二叉树——Huffman编码与解码(不含代码框架)

DS二叉树——Huffman编码与解码(不含代码框架)

题目描述

1、问题描述

给定n个字符及其对应的权值,构造Huffman树,并进行huffman编码和译(解)码。

构造Huffman树时,要求左子树根的权值小于、等于右子树根的权值。

进行Huffman编码时,假定Huffman树的左分支上编码为‘0’,右分支上编码为‘1’。

2、算法

构造Huffman树算法:

⑴ 根据给定的n个权值(w1, w2, …, wn)构成n棵二叉树的集合F={T1, T2, …, Tn},其中每棵二叉树Ti中只有一个权值为wi的根结点。

⑵ 在F中选取两棵根结点的权值最小的树,作为左、右子树构造一棵新的二叉树,且置其根结点的权值为其左、右子树权值之和。

⑶ 在F中删除这两棵树,同时将新得到的二叉树加入F中。

(4) 重复⑵, ⑶,直到F只含一棵树为止。

3、Huffman编码算法:

⑴ 从Huffman树的每一个叶子结点开始。

⑵ 依次沿结点到根的路径,判断该结点是父亲结点的左孩子还是右孩子,如果是左孩子则得到编码‘0’,否则得到编码‘1’,先得到的编码放在后面。

⑶ 直到到达根结点,编码序列即为该叶子结点对应的Huffman编码。

4、Huffman译(解)码算法:

⑴ 指针指向Huffman树的根结点,取第一个Huffman码。

⑵ 如果Huffman码为‘0’,将指针指向当前结点的左子树的根结点;如果Huffman码为‘1’,将指针指向当前结点的右子树的根结点。

⑶ 如果指针指向的当前结点为叶子结点,则输出叶子结点对应的字符;否则,取下一个Huffman码,并返回⑵。

⑷ 如果Huffman码序列未结束,则返回⑴继续译码。

输入

第一行测试次数

第2行:第一组测试数据的字符个数n,后跟n个字符

第3行:第一组测试数据的字符权重

待编码的字符串s1

编码串s2

其它组测试数据类推

输出

第一行~第n行,第一组测试数据各字符编码值

第n+1行,串s1的编码值

第n+2行,串s2的解码值,若解码不成功,输出error!

其它组测试数据类推

样例输入

2
5 A B C D E
15 4 4 3 2
ABDEC
00000101100
4 A B C D
7 5 2 4
ABAD
1110110

样例输出

A :1
B :010
C :011
D :001
E :000
1010001000011
error!
A :0
B :10
C :110
D :111
0100111
DAC

#include <iostream>
#include <string>
using namespace std;

class HuffmanNode{
    int lChild;
    int rChild;
    int parents;
    int weight;
public:
    HuffmanNode():lChild(0),rChild(0),parents(0),weight(0){}
    friend class HuffmanTree;
};

class HuffmanTree{
    int leafNum;
    HuffmanNode *tree;
    char *strs;
    string *code;
    void selectMin(int pos,int *min1,int *min2);
    int Index(char c);
public:
    HuffmanTree();
    void createTree();
    void encode(string str);
    void decode(string str);
};

HuffmanTree::HuffmanTree() {
    cin>>leafNum;
    tree = new HuffmanNode[2*leafNum];
    strs = new char[leafNum];
    code = new string[leafNum];
    for(int i=0;i<leafNum;i++)
        cin>>strs[i];

    for(int i=1;i<=leafNum;i++)
        cin>>tree[i].weight;
}

void HuffmanTree::selectMin(int pos, int *min1, int *min2) {
    int w1=99999,w2=99999;
    for(int i=1;i<pos;i++)
    {
        if(w1>tree[i].weight && tree[i].parents == 0)
        {
            w2=w1;
            *min2 = *min1;
            w1 = tree[i].weight;
            *min1 = i;
        }
        else if(w2>tree[i].weight && tree[i].parents == 0)
        {
            w2 = tree[i].weight;
            *min2 = i;
        }
    }
}

void HuffmanTree::createTree() {
    for(int i =leafNum+1;i<2*leafNum;i++)
    {
        int min1=0,min2=0;
        selectMin(i,&min1,&min2);
        tree[i].weight = tree[min1].weight+tree[min2].weight;
        tree[i].lChild = min1;
        tree[i].rChild = min2;
        tree[min1].parents = i;
        tree[min2].parents = i;
    }
}

void HuffmanTree::encode(string str) {
    for(int i=0;i<leafNum;i++)
    {
        int m=i+1;
        int n = tree[m].parents;
        while (n!=0) {
            if (tree[n].lChild == m)
                code[i] = "0" + code[i];
            else if (tree[n].rChild == m)
                code[i] = "1" + code[i];

            m = n;
            n = tree[m].parents;
        }
        cout<<strs[i]<<" :"<<code[i]<<endl;
    }

    int len = str.size();
    for(int i=0;i<len;i++)
    {
        int pos = Index(str[i]);
        cout<<code[pos];
    }
    cout<<endl;
}

int HuffmanTree::Index(char c) {
    for(int i=0;i<leafNum;i++)
        if(c==strs[i])
            return i;
    return -1;
}

void HuffmanTree::decode(string str) {
    int p= 2*leafNum-1;
    string msg;
    for(int i=0;i<str.size();i++)
    {
        if(str[i]=='0' && tree[p].lChild!=0)
            p=tree[p].lChild;
        else if(str[i]=='1' && tree[p].rChild!=0)
            p=tree[p].rChild;

        if(tree[p].lChild==0 && tree[p].rChild==0) {
            msg += strs[p-1];
            p= 2*leafNum-1;
        }
    }
    if(p==2*leafNum-1)
        cout<<msg<<endl;
    else
        cout<<"error!"<<endl;

}


int main()
{
    int t;
    cin>>t;
    while (t--)
    {
        HuffmanTree myTree;
        myTree.createTree();
        string str1;
        cin>>str1;
        myTree.encode(str1);
        string str2;
        cin>>str2;
        myTree.decode(str2);
    }
    return 0;
}
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值