zoukankan      html  css  js  c++  java
  • 哈夫曼编码/译码系统(树应用)

    [问题描述]

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

    [实现提示]

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

    发送者的功能包括:

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

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

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

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

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

    接受者的功能包括:

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

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

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

    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 << "		";
            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] = '';//编码结束符
        //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 << "
    译码完成:";
        while (h[i] != '' && 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] != '')   //电文读完,但尚未到叶子结点
            cout << "
    输入原码错误
    ";  //输入电文有错
    }
    
    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);
    }



  • 相关阅读:
    js-添加删除记录-修改
    js-添加删除记录-添加
    js-添加删除记录-删除
    dom增删改
    事件的冒泡
    div随鼠标在浏览器的窗口任意移动
    多选框全选练习
    python-day3
    python-day2
    python-day1
  • 原文地址:https://www.cnblogs.com/Cyan-W/p/5080366.html
Copyright © 2011-2022 走看看