C++ 哈夫曼树,哈夫曼编码

C++ 哈夫曼树,哈夫曼编码

一、题目要求:

给26个大写英文字母设计哈夫曼编码,使总编码长度最短。

输入一段由26个大写英文字母组成的字符串,输出其哈夫曼编码。

输入一段哈夫曼编码,输出其对应的由26个英文字母组成的字符串。

二、代码实现:

1、HufTree.h文件:

#ifndef HUFTREE_H
#define HUFTREE_H

#include <iostream>
#include <iomanip>

using namespace std;

char charlist[28] = {'0',
                 'A', 'B', 'C', 'D',
                 'E', 'F', 'G', 'H',
                 'I', 'J', 'K', 'L',
                 'M', 'N', 'O', 'P',
                 'Q', 'R', 'S', 'T',
                 'U', 'V', 'W', 'X',
                 'Y', 'Z'};

double weightlist[27] = {26.0,
                         0.0856,0.0139,0.0297,0.0378,
                         0.1304,0.0289,0.0199,0.0528,
                         0.0627,0.0013,0.0042,0.0339,
                         0.0249,0.0707,0.0797,0.0199,
                         0.0012,0.0677,0.0607,0.1045,
                         0.0249,0.0092,0.0149,0.0017,
                         0.0199,0.0008};
class HufNode
{
public:
    char ch;  //结点字符
    double weight;  //结点权值
    int parent, lchild, rchild;  //结点的父、左孩子、右孩子下标
};

class HufTree
{
public:
    static void Create_HufTree(HufNode*&, int);  //创建哈夫曼树
    static void Travel_HufTree(HufNode*);  //遍历哈夫曼树
    static void Create_HufCode(HufNode*, char**&, int);  //根据哈夫曼树求哈夫曼编码
};

void Select(HufNode*& nt, int m, int& s1, int& s2)  //在 1 ~ i - 1 中选择两个无父结点且权值最小的结点,返回下标s1,s2
{
    double minum1 = 10, minum2 = 10;
    for(int i = 1; i <= m; i++)
    {
        if(nt[i].weight < minum1 && nt[i].parent == 0)
        {
            minum1 = nt[i].weight;
            s1 = i;
        }
    }
    for(int j = 1; j <= m; j++)
    {
        if(nt[j].weight < minum2 && nt[j].parent == 0 && j != s1)
        {
            minum2 = nt[j].weight;
            s2 = j;
        }
    }
}

void HufTree::Create_HufTree(HufNode*& nt, int n = 26)  //创建哈夫曼树
{
   //存储初始化

   if(n <= 1) return;
   nt = new HufNode[2 * n];  //0号单元存储哈夫曼树的长度,故数组大小为 2 * n
   nt[0].weight = 2 * n - 1; nt[0].ch = '0'; nt[0].parent = 0; nt[0].lchild = 0; nt[0].rchild = 0;
   for(int i = 1; i <= 2 * n - 1; i++)  //所有单元全部初始化为0
   {   nt[i].ch = '0'; nt[i].weight = 0; nt[i].parent = 0; nt[i].lchild = 0; nt[i].rchild = 0;   }
   for(int j = 1; j <= n; j++)
   {
       nt[j].ch = charlist[j];
       nt[j].weight = weightlist[j];  //前n个单元存储叶子结点
   }

   //创建哈夫曼树
   int s1 = 0, s2 = 0;
   for(int i = n + 1; i <= 2 * n - 1; i++)  //通过n - 1次的选择、删除、合并来创建哈夫曼树
   {
       Select(nt, i - 1, s1, s2);  //在 1 ~ i - 1 中选择两个无父结点且权值最小的结点,返回下标s1,s2
       nt[s1].parent = i; nt[s2].parent = i;  //将s1和s2的父结点改为i,也即删除s1,s2
       nt[i].lchild = s1; nt[i].rchild = s2;  //s1和s2分别作为左右孩子
       nt[i].weight = nt[s1].weight + nt[s2].weight;  //新结点权值为s1,s2权值之和
   }
}

void HufTree::Travel_HufTree(HufNode* nt)  //遍历哈夫曼树
{
    cout << "下标" << "    " << "字符" << "    " << "weight" << "    " << "parent" << "    " << "lchild" << "    " << "rchild" << endl;
    for(int i = 1; i <= nt[0].weight; i++)
        cout
        << std::left << setw(8) << i
        << std::left << setw(8) << nt[i].ch
        << std::left << setw(8) << nt[i].weight
        << std::right << setw(8) << nt[i].parent
        << std::right << setw(8) << nt[i].lchild
        << std::right << setw(8) << nt[i].rchild
        << endl;
}

void HufTree::Create_HufCode(HufNode* nt, char**& hclist, int n = 26)  //根据哈夫曼树求哈夫曼编码
{
    hclist = new char*[n + 1];  //分配存储 n 个字符编码的编码表(指针数组)空间,0单元不用,故指针数组大小为 n + 1
    char *hc = new char[n];  //分配临时存放每个字符编码的数组空间,字符编码长度一定小于 n
    for(int i = 1; i <= n; i++)  //逐个字符求哈夫曼编码
    {
        hc[n - 1] = '\0';  //数组末尾为编码结束符
        int start = n - 1;  //start初始位置为数组末尾(编码结束符)
        int c = i, f = nt[i].parent;  // c 初始为当前待编码字符 i ,f 用于记录 i 的父结点下标
        while(f != 0)  //从叶子结点向上回溯,直到根结点
        {
            start--;
            if(nt[f].lchild == c)  //如果 c 是 f 的左孩子,则编码为0
                hc[start] = '0';
            else  //反之编码为1
                hc[start] = '1';
            c = f;  //向上回溯
            f = nt[f].parent;
        }
        hclist[i] = new char[n - start];  //为第 i 个字符的编码分配空间
        for(int j = 0; j < n - start; j++)  //将求得的编码从临时空间 hc 复制到 hclist[i] 中
            hclist[i][j] = hc[j + start];
    }
    delete [] hc;  //释放临时空间
}

#endif // HUFTREE_H

2、main.cpp文件:

#include <iostream>
#include <iomanip>
#include "HufTree.h"

using namespace std;

int main()
{
    HufNode *h = nullptr;
    char **hclist = nullptr;
    HufTree::Create_HufTree(h);
    HufTree::Travel_HufTree(h);
    HufTree::Create_HufCode(h, hclist);
    for(int i = 1; i <= 26; i++)
    {
        cout << charlist[i] << ' ';
        for(int j = 0; hclist[i][j] != '\0'; j++)
        {
           cout << hclist[i][j] << ' ';
        }
        cout << endl;
    }


    cout << "请输入一串由‘A’~‘Z’构成的字符:";
    string s_ch; getline(cin, s_ch);
    cout << "该串字符的哈夫曼编码为:";
    for(int i = 0; s_ch[i] != '\0'; i++)  //遍历字符串的每一个字符
    {
        for(int j = 1; j <= 26; j++)
        {
            if(s_ch[i] == charlist[j])  //如果在字母表中找到匹配的字符
            {
                for(int k = 0; hclist[j][k] != '\0'; k++)  //输出该字符对应的哈夫曼编码
                    cout << hclist[j][k] << ' ';
            }
        }
    }


    cout << endl << "请输入一串由‘0’和‘1’构成的编码:";
    string s_code; getline(cin, s_code);
    int flag, dex, pos = 0;
    cout << "该串哈夫曼编码所对应的字符为:";
    while(pos < s_code.size())  //遍历哈夫曼编码的每一段编码
    {
        for(int i = 1; i <= 26; i++)  //遍历字母表
        {
            flag = 1; dex = i;  //先假定当前字符与这段哈夫曼编码匹配
            for(int j = 0; hclist[i][j] != '\0'; j++)
            {
                if(hclist[i][j] != s_code[pos + j])  //如果不匹配则flag置为0,dex置为-1
                {
                    flag = 0;
                    dex = -1;
                    break;
                }
            }
        if(flag == 1)  //如果匹配则输出该字符,且pos向后移动,移动的长度为:该字符所对应的哈夫曼编码的长度
            {
                cout << charlist[dex] << ' ';
                for(int j = 0; hclist[dex][j] != '\0'; j++)
                    pos += 1;
                break;
            }
        }
    }
    return 0;
}

三、运行测试:

下标    字符    weight    parent    lchild    rchild
1       A       0.0856        44       0       0
2       B       0.0139        32       0       0
3       C       0.0297        37       0       0
4       D       0.0378        38       0       0
5       E       0.1304        47       0       0
6       F       0.0289        36       0       0
7       G       0.0199        33       0       0
8       H       0.0528        40       0       0
9       I       0.0627        41       0       0
10      J       0.0013        28       0       0
11      K       0.0042        30       0       0
12      L       0.0339        37       0       0
13      M       0.0249        35       0       0
14      N       0.0707        43       0       0
15      O       0.0797        44       0       0
16      P       0.0199        34       0       0
17      Q       0.0012        27       0       0
18      R       0.0677        42       0       0
19      S       0.0607        41       0       0
20      T       0.1045        45       0       0
21      U       0.0249        35       0       0
22      V       0.0092        31       0       0
23      W       0.0149        32       0       0
24      X       0.0017        28       0       0
25      Y       0.0199        34       0       0
26      Z       0.0008        27       0       0
27      0       0.002         29      26      17
28      0       0.003         29      10      24
29      0       0.005         30      27      28
30      0       0.0092        31      11      29
31      0       0.0184        33      22      30
32      0       0.0288        36       2      23
33      0       0.0383        38      31       7
34      0       0.0398        39      16      25
35      0       0.0498        39      13      21
36      0       0.0577        40      32       6
37      0       0.0636        42       3      12
38      0       0.0761        43       4      33
39      0       0.0896        45      34      35
40      0       0.1105        46       8      36
41      0       0.1234        46      19       9
42      0       0.1313        47      37      18
43      0       0.1468        48      14      38
44      0       0.1653        48      15       1
45      0       0.1941        49      39      20
46      0       0.2339        49      40      41
47      0       0.2617        50       5      42
48      0       0.3121        50      43      44
49      0       0.428         51      45      46
50      0       0.5738        51      47      48
51      0       1.0018         0      49      50
A 1 1 1 1
B 0 1 0 1 0 0
C 1 0 1 0 0
D 1 1 0 1 0
E 1 0 0
F 0 1 0 1 1
G 1 1 0 1 1 1
H 0 1 0 0
I 0 1 1 1
J 1 1 0 1 1 0 1 1 1 0
K 1 1 0 1 1 0 1 0
L 1 0 1 0 1
M 0 0 0 1 0
N 1 1 0 0
O 1 1 1 0
P 0 0 0 0 0
Q 1 1 0 1 1 0 1 1 0 1
R 1 0 1 1
S 0 1 1 0
T 0 0 1
U 0 0 0 1 1
V 1 1 0 1 1 0 0
W 0 1 0 1 0 1
X 1 1 0 1 1 0 1 1 1 1
Y 0 0 0 0 1
Z 1 1 0 1 1 0 1 1 0 0
请输入一串由‘A’~‘Z’构成的字符:BUY
该串字符的哈夫曼编码为:0 1 0 1 0 0 0 0 0 1 1 0 0 0 0 1
请输入一串由‘0’和‘1’构成的编码:1110110001101011
该串哈夫曼编码所对应的字符为:O N S R
Process returned 0 (0x0)   execution time : 15.130 s
Press any key to continue.

  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值