哈夫曼树与哈夫曼编码实现

题目内容

对于给定的一组字符,可以统计字符出现的频率,然后根据其出现的频率进行哈夫曼编码,并能输出对应的哈夫曼树和哈夫曼编码;实现哈夫曼解码。

输入和输出

输入

字符长度
一组字符
01字符长度
一组01字符

例子

100
gggaaaaahhhhhhhhhhhfffffffffffffffffffffffbbbbbbbbbbbbbbbbbbbbbbbbbbbbbeeeeeeeeeeeeeecccccccdddddddd
2
10

输出

各个字符对应的哈夫曼编码
输入的字符对应的哈夫曼编码
哈夫曼树
01字符对应的字符

例子

a 0001
b 10
c 1110
d 1111
e 110
f 01
g 0000
h 001
0000000000000001000100010001000100100100100100100100100100100100101010101010101010101010101010101010101010101011010101010101010101010101010101010101010101010101010101010110110110110110110110110110110110110110110111011101110111011101110111011111111111111111111111111111111
输出哈夫曼树
下标    权值    父结点  左孩子  右孩子  结点
0       3       8       -1      -1      g
1       5       8       -1      -1      a
2       11      10      -1      -1      h
3       23      12      -1      -1      f
4       29      13      -1      -1      b
5       14      11      -1      -1      e
6       7       9       -1      -1      c
7       8       9       -1      -1      d
8       8       10      0       1
9       15      11      6       7
10      19      12      8       2
11      29      13      5       9
12      42      14      10      3
13      58      14      4       11
14      100     -1      12      13
b

代码

#include <iostream>
#include <algorithm>
#include <map>
#include<vector>
using namespace std;

struct HTNode
{
    char data;                  //代表字母
    int weight;                 //权值
    int parent, lchild, rchild; //双亲和孩子
    HTNode()
    {
        weight = parent = lchild = rchild = -1; //初始化为-1
    }
};

int len;   //代表输入字符的长度(个数)
int n = 0; //代表输入字符的种类
//vector<HTNode*> arr;
HTNode *arr;//用来存放二叉树
map<char, string> mp;//存放字符和字符对应的哈夫曼编码
string str;          //暂时存放生成的哈夫曼编码
char *char_huffman;  //存放输入的元素
string *str_huffman; //存放输入元素最终的哈夫曼编码
char *a;             //存放传入的二进制编码
char *b;             //存放译出的字符

void CreateHuffmanTree()
{ //生成哈夫曼树
    for (int i = n; i < 2 * n - 1; i++)
    {
        int min1 = 65522; int min2 = min1;//min1第一小,min2第二小 
        int x1 = -1, x2 = -1;//分别记录两者下标
        for (int j = 0; j < i; j++)
        {
           if (arr[j].parent == -1)
            {
                if (arr[j].weight < min1)
                {
                    min2 = min1;
                    x2 = x1;
                    min1 = arr[j].weight;
                    x1 = j;
                }
                else if (arr[j].weight < min2)
                {
                    min2 = arr[j].weight;
                    x2 = j;
                }
            }
        }
        arr[x1].parent = arr[x2].parent = i;
        arr[i].weight = min1 + min2;
        arr[i].lchild = x1;
        arr[i].rchild = x2;
    }
}


//哈夫曼编码
void HaffmanCode()
{
    for (int i = 0; i < n; i++)
    {
        int t = i; //代表儿子
        str = "";
        int parent = arr[i].parent;
        for (int j = parent; j != -1; t = j, j = arr[j].parent)
        {
            if (arr[j].lchild == t)
            {
                str += '0';
            }
            else
            {
                str += '1';
            }
        }
        reverse(str.begin(), str.end());
        mp[arr[i].data] = str;
    }
}

//哈夫曼译码
void HaffmanDecode(int q,int &k)
{
    for (int i = 0; a[i] != '\0'; i++){
        if (a[i] == '0')
        {
            q = arr[q].lchild;
        }
        else if (a[i] == '1')
        {
            q = arr[q].rchild;
        }
        if (arr[q].lchild == -1 && arr[q].rchild == -1)
        {
            b[k++] = arr[q].data;
            q = 2 * n - 2;
        }
    }
    b[k] = '\0';
}

int main()
{
    freopen("in.txt", "r", stdin);
    char c; //带输入的字符
    cin >> len;
    char_huffman = new char[len];
    str_huffman = new string[len];
    arr = new HTNode[2 * len - 1];//此时未得出字母类型,只能用len来建立数组 
    getchar();//去掉回车符
    for (int i = 0; i < len; i++)
    {
        cin >> c;
        //scanf(" %c", &c);
        char_huffman[i] = c;
        int flag = 0;
        for (int j = 0; j < n; j++)
        {
            if (arr[j].data == c)
            {
                flag = 1;
                arr[j].weight++;
                break;
            }
        }
        if (!flag)
        {
            arr[n].data = c;
            arr[n].weight = 1;
            n++;
        }
    }

    /*用来测试上述代码
    for (int i = 0; i < n; i++)
    {
            cout << arr[i].data << " : ";
        cout << arr[i].weight << endl;
    }
    */

    int q = 2 * n - 2; //初始化为根结点的下标
    int k = 0;         //记录译出字符数组的下标
    int len2;
    char d;
    cin >> len2;
    a = new char[len2]; //存放二进制代码
    b = new char[len2]; //存放二进制代码译出的字符
    getchar();//去掉回车符
    for (int i = 0; i < len2; i++)
    {
        cin >> d;
        a[i] = d;
    }

    CreateHuffmanTree();

    HaffmanCode();

    HaffmanDecode(q,k);
    
    for (auto p : mp)
    {
        cout << p.first << " " << p.second << endl;
    }
    for (int i = 0; i < len; i++)
    {
        str_huffman[i] = mp[char_huffman[i]];
    }
    for (int i = 0; i < len; i++)//输出输入的所有元素的哈夫曼编码
    {
        cout << str_huffman[i];
    }
    cout<<endl;

    //输出哈夫曼树
    cout<<"输出哈夫曼树"<<endl;
    cout<<"下标"<<" 权值"<<" 父结点"<<" 左孩子"<<" 右孩子"<<" 结点"<<endl;
    for(int i=0;i<2*n-1;i++){
        cout<<i<<" "<<arr[i].weight<<" "<<arr[i].parent<<" "<<arr[i].lchild<<" "<<arr[i].rchild<<" "<<arr[i].data<<endl;
    }
    //输出二进制代码转换成的字符
    for(int i=0;i<k;i++){
        cout<<b[i]<<" ";
    }
    return 0;
}

题目参考来处

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值