哈夫曼编码/译码系统(树应用)

[问题描述]

利用哈夫曼编码进行通信,可以压缩通信的数据量,提高传输效率,缩短信息的传输时间,还有一定的保密性。现在要求编写一程序模拟传输过程,实现在发送前将要发送的字符信息进行编码,然后进行发送,接收后将传来的数据进行译码,即将信息还原成发送前的字符信息。

[实现提示]

在本例中设置发送者和接受者两个功能,

发送者的功能包括:

①输入待传送的字符信息;

②统计字符信息中出现的字符种类数和各字符出现的次数(频率);

②根据字符的种类数和各自出现的次数建立哈夫曼树;

③利用以上哈夫曼树求出各字符的哈夫曼编码;

④将字符信息转换成对应的编码信息进行传送。

接受者的功能包括:

①接收发送者传送来的编码信息;

②利用上述哈夫曼树对编码信息进行翻译,即将编码信息还原成发送前的字符信息。

从以上分析可发现,在本例中的主要算法有三个:

1)哈夫曼树的建立;

2)哈夫曼编码的生成;

3)对编码信息的翻译。

 

源代码

#include<iomanip>
#include<stdlib.h>
#include<string.h>
#include<stdio.h>
#include<iostream>
using namespace std;
#define  maxsize 100
struct frequence//统计频率
{
    char a;//存放字符
    int n;//该字符出现的次数
};
typedef struct
{
    unsigned int weight;     // 用来存放各个结点的权值
    unsigned int parent, lchild, rchild;//指向双亲、 孩子结点的指针
}HTNode, *HuffmanTree;   //动态分配数组存储赫夫曼树
typedef char **HuffmanCode;//动态分配数组存储赫夫曼编码表     
int W[maxsize], *w;//存放字符的权值 
int c1 = 0;//输入报文的长度 
frequence ch[27];//26个英文字母,0号位置不存储字符,用来存储总共的字符个数,多次出现的只记一次
char a[maxsize];//存放所有的字符 
int Frequent()
{
    int i = 0;
    for (; i <= 26; i++)//初始化结构体数组
    {
        ch[i].n = 0;
    }
    cout << "输入电报:(输入#键结束输入):";
    char c;
    cin >> c;
    while (c != '#')
    {
        a[c1] = c;
        bool flag;
        i = 1;
        flag = false;
        for (; i <= ch[0].n; i++)
        {
            if (c == ch[i].a)
            {

                flag = true;
                break;
            }
        }
        if (flag)//已存在
        {
            ch[i].n++;
        }
        else//不存在
        {
            ch[0].n++;
            ch[ch[0].n].n++;
            ch[ch[0].n].a = c;
        }
        c1++;
        cin >> c;
    }
    cout << "报文的长度:" << c1 << endl;
    for (int j = 1; j <= ch[0].n; j++)
    {
        cout << ch[j].a << " " << ch[j].n << "\t\t";
        W[j - 1] = ch[j].n;

    }
    cout << endl;
    cout << "不重复字符的总个数:" << ch[0].n << endl;
    w = W;
}
void Select(HuffmanTree HT, int i, int &s1, int &s2)
{
    int j, k = 1;
    while (HT[k].parent != 0)
        k++;
    s1 = k;
    for (j = 1; j <= i; ++j)
        if (HT[j].parent == 0 && HT[j].weight<HT[s1].weight)
            s1 = j;
    k = 1;
    while ((HT[k].parent != 0 || k == s1))
        k++;
    s2 = k;
    for (j = 1; j <= i; ++j)
        if (HT[j].parent == 0 && HT[j].weight<HT[s2].weight&&j != s1)
            s2 = j;
}
void HuffmanCoding(HuffmanTree &HT, HuffmanCode&HC, int *w, int n)
{  //w存放n个权值, 构造哈夫曼树p, 并求出哈夫曼编码hc 
    int m, i, s1, s2, start, c, f;
    HuffmanTree p;
    if (n <= 1)
        return;
    m = 2 * n - 1;//总结点数 
    HT = (HuffmanTree)malloc((m + 1)*sizeof(HTNode));//0号单元未用
    for (p = HT + 1, i = 1; i <= n; ++i, ++p, ++w)
    {
        p->weight = *w;
        p->parent = 0;
        p->lchild = 0;
        p->rchild = 0;
    }
    for (; i <= m; ++i, ++p)
    {
        p->weight = 0;
        p->parent = 0;
        p->lchild = 0;
        p->rchild = 0;
    }
    cout << endl << endl << "建立的哈夫曼树如下列次序:";
    for (i = n + 1; i <= m; ++i)//建立赫夫曼树
    {
        Select(HT, i - 1, s1, s2);
        HT[s1].parent = i;
        HT[s2].parent = i;
        HT[i].lchild = s1;
        HT[i].rchild = s2;
        HT[i].weight = HT[s1].weight + HT[s2].weight;
        cout << endl << "HT[" << s1 << "] and HT[" << s2 << "] create";
        cout << " HT[" << i << "], weight=" << HT[i].weight << endl;
    }
    //从叶子到根逆向求每个字符的赫夫曼编码
    HC = (HuffmanCode)malloc((n + 1)*sizeof(char *));//分配n个字符编码的走指针向量
    char *cd;
    cd = (char *)malloc(n*sizeof(char));//分配求编码的工作空间
    cd[n - 1] = '\0';//编码结束符
    //system("pause");
    cout << "哈夫曼编码如下:" << endl;
    for (i = 1; i <= n; ++i)//逐个字符求赫夫曼编码
    {
        start = n - 1;
        for (c = i, f = HT[i].parent; f != 0; c = f, f = HT[f].parent)//从叶子到根逆向求编码
            if (HT[f].lchild == c)
                cd[--start] = '0';
            else
                cd[--start] = '1';
        HC[i] = (char*)malloc((n - start)*sizeof(char));//为第i个字符编码分配空间
        strcpy(HC[i], &cd[start]);//从cd复制编码到HC
        cout << ch[i].a << " 哈夫曼编码是" << HC[i] << endl;
    }
    cout << endl;
    free(cd);//释放空间
}
void Decode(HuffmanTree &HT, HuffmanCode&HC, int n)//依次读入电文,根据哈夫曼树译码

{
    cout << "电报内容:";
    for (int k = 0; k <= c1; k++)
        cout << a[k];
    cout << endl;
    for (int k = 0; k <= c1; k++)
        for (int y = 1; y <= ch[0].n; y++)
            if (a[k] == ch[y].a)
                cout << a[k] << "------哈夫曼编码是" << HC[y] << endl;
    cout << "电报内容哈夫曼编码:";
    for (int k = 0; k <= c1; k++)
        for (int y = 1; y <= ch[0].n; y++)
            if (a[k] == ch[y].a)
                cout << HC[y];
    cout << endl;
    int p, i = 0;    
    char h[50];
    p = 2 * n - 1;             //从根结点开始往下搜索
    cout << "输入原码:";
    cin >> h;
    cout << "\n译码完成:";
    while (h[i] != '\0' && p != 0)
    {
        if (h[i] == '0')
            p = HT[p].lchild;   //走向左孩子
        else
            p = HT[p].rchild;   //走向右孩子
        if (!HT[p].lchild && !HT[p].rchild)     //tree[i]是叶结点
        {
            cout << ch[p].a;
            p = 2 * n - 1;      //回到根结点
        }
        i++;
    }
    cout << endl;
    if (HT[i].lchild && h[i] != '\0')   //电文读完,但尚未到叶子结点
        cout << "\n输入原码错误\n";  //输入电文有错
}

void menu()
{
    cout << "===================================" << endl;
    cout << "         哈夫曼编码/译码系统       " << endl;
    cout << "          1.哈夫曼编码             " << endl;
    cout << "          2.译码系统               " << endl;
    cout << "          0.退出                   " << endl;
    cout << "===================================" << endl;
}
int  main()
{
    HuffmanTree HT;
    HuffmanCode HC;
    int in;
    menu();
    do{
        cout << "请输入操作序号:";
        cin >> in;
        system("cls");
        menu();

        switch (in){
        case 1:
            Frequent();
            HuffmanCoding(HT, HC, w, ch[0].n);
            system("pause");
            break;
        case 2:
            Decode(HT, HC, ch[0].n);
            system("pause");
            break;
        case 0:
            break;
        default:
            cout << "输入错误,请重新输入:";
        }

    } while (in != 0);
}

 



转载于:https://www.cnblogs.com/Cyan-W/p/5080366.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值