哈夫曼树与哈夫曼编码实验报告(直接运行)

一.实验目的:

理解二叉树的基本逻辑结构,完成最优二叉树的构建、遍历。

通过对简单哈夫曼编/译码系统的设计与实现来熟练掌握树型结构在实际问题中的应用。

二.实验内容:

题目:哈夫曼编码/译码

问题描述:

利用哈夫曼编码进行通信可以大大提高信道利用率,缩短信息传输时间,降低传输成本。但是,这要求在发送端通过一个编码系统对待传数据预先编码,在接收端将传来的数据进行译码(复原)。对于双工信道(即可以双向传输信息的信道),每端都需要一个完整的编/译码系统。试为这样的u信息收发编写一个哈夫曼码的编/译码系统。

基本要求:

  1. 接收原始数据(电文):从终端输入电文(电文为一个字符串,假设仅由26个小写英文字母构成)。

(2)编码:利用已建好的哈夫曼树,对电文进行编码。

(3)打印编码规则:即字符与编码的一一对应关系。

(4)打印显示电文以及该电文对应的哈夫曼编码。

(5)接收原始数据(哈夫曼编码):从终端输入一串哈二进制哈夫曼编码(由

0和1构成)。

(6)译码:利用已建好的哈夫曼树对该二进制编码进行译码。

(7)打印译码内容:将译码结果显示在终端上。

三. 实验方案

(一)算法设计思路:

1.遍历电文获取各个字符的权重传递到哈夫曼树

2、建立哈夫曼树:

遍历整体,把两个最小的权重相加,作为新的权重 和剩余的权重重新排列,再把最小的两个权重相加,再重新排列,直到最后变成1。

3、根据哈夫曼树获取哈夫曼编码 打印对应关系

4、利用建立好的哈夫曼树进行解码

(二)使用模块及变量的说明(例如结构体的定义、含义)

1、typedef struct HNodeType        //定义哈夫曼树的叶结点

2、HNodeType HFMTree[2 * n - 1];   //建立存储哈夫曼树的数组

3、void Creat_HuffMTree(HNodeType HFMTree[],int num[])

                                   //建立哈夫曼树

4、typedef struct HCodeType        //定义哈夫曼编码的结点

5、HCodeType HuffCode[n];          //建立存储编码的数组

6、void HaffmanCode(HNodeType HFMTree[], HCodeType HuffCode[]);

                                   //按照左0右1获取哈夫曼编码

    7、int qnum(string str, int num[]);//获取电文中每个字母出现次数

    8、void print(HNodeType HFMTree[], HCodeType HuffCode[], int num[]);

                                       //打印字母出现次数及对应编码

    9、void translate_CI(string str);  //将电文字符串编码并输出

    10、int length(string str);        //获取字符串长度

    11、void decode(HNodeType HFMTree[], HCodeType HuffCode[], string str);                                  //译码,将0-1转为字符串

四. 实验步骤或程序(经调试后正确的源程序)

#include <iostream>

#include<string>

using namespace std;

#define n 26         //26个字母

#define MAXVALUE 1000

typedef struct

{

    int weight;

    int parent;

    int lchild;

    int rchild;

   

}HNodeType ;

HNodeType HFMTree[2 * n - 1];

void Creat_HuffMTree(HNodeType HFMTree[],int num[])//叶结点为n=4

{

    int m1, m2, x1, x2;//x1 x2 存放最小和次小权值 m1 m2存放下标

    int i, j;

    for (i = 0; i < 2 * n - 1; i++)

    {

        HFMTree[i].weight = 0;

        HFMTree[i].parent = -1;

        HFMTree[i].rchild = -1;

        HFMTree[i].lchild = -1;



    }

    for (i = 0; i < n; i++)

    {

        //cin >> HFMTree[i].weight;//输入n个叶结点的权重

        HFMTree[i].weight = num[i];

    }

    for (i = 0; i < n-1; i++)

    {

        x1 = x2 = MAXVALUE;

        m1 = m2 = -1;

        for (j = 0; j < n + i; j++)

        {

            if (HFMTree[j].parent == -1 && HFMTree[j].weight < x1)

            {

                x2 = x1; m2 = m1;

                x1 = HFMTree[j].weight; m1 = j;

            }

            else if (HFMTree[j].parent == -1 && HFMTree[j].weight < x2)

            {

                x2 = HFMTree[j].weight; m2 = j;

            }



        }

        HFMTree[m1].parent = n + i; HFMTree[m2].parent = n + i;

        HFMTree[n + i].weight = HFMTree[m1].weight + HFMTree[m2].weight;

        HFMTree[n + i].lchild = m1; HFMTree[n + i].rchild = m2;

    }



}

typedef struct

{

    int bit[n];

    int start;

}HCodeType;

HCodeType HuffCode[n];

void HaffmanCode(HNodeType HFMTree[], HCodeType HuffCode[])

{

    HCodeType cd;

    int i, j, c, p;//p是父母 c是孩子

    for (i = 0; i < n; i++)

    {

        cd.start = n - 1;

        c = i;

        p = HFMTree[c].parent;

        while (p != -1)

        {

            if (HFMTree[p].lchild == c)

            {

                cd.bit[cd.start] = 0;

            }

            else

            {

                cd.bit[cd.start] = 1;

            }

            cd.start--;

            c = p;

            p = HFMTree[c].parent;

        }

        for (j = cd.start + 1; j < n; j++)

            HuffCode[i].bit[j] = cd.bit[j];

        HuffCode[i].start = cd.start + 1;

       



    }

}

int qnum(string str, int num[]);

void print(HNodeType HFMTree[], HCodeType HuffCode[], int num[]);

void translate_CI(string str);

int length(string str);

void decode(HNodeType HFMTree[], HCodeType HuffCode[], string str);

int main()

{

  





    int num[n] = {0};//1.注意初始化

    



    string str,str1;

        cout << "输入电文:";

        cin >> str;

        qnum(str, num);

        Creat_HuffMTree(HFMTree, num);//形成哈夫曼树

        HaffmanCode(HFMTree, HuffCode);

        print(HFMTree, HuffCode, num);

        translate_CI(str);

   

        cout << endl;

        while (1)

        {

            cout << endl<<"输入0—1二进制串(按e退出):";

            cin >> str1;

            if (str1 == "e")

                break;

            int len = length(str1);

          //  translate_IC(str1, len);

         

            decode(HFMTree, HuffCode, str1);

        }

       

   

    system("pause");

  

    return 0;

}



int length(string str)

{

    int i = 0;

    while (str[i] != '\0')

    {

        i++;

    }



    return i;

}

int qnum(string str,int num[]) //获取每个字母出现次数

{

   

    int j,k;

    for (int i = 0; i < length(str); i++)

    {  

        k = str[i];

       j= (int)k - 97;

       num[j]++;

    }

    return 1;

}

void print(HNodeType HFMTree[], HCodeType HuffCode[], int num[])//输出各个字符出现的次数及对应的编码

{

    int m = 2 * n - 1;

    char ch;

    cout << endl<<"电文中出现的字符及其数字如下:"<<endl;

    for (int i = 0; i < 26; i++)

    {

        ch = (char)(i + 97);

        cout << ch << "出现的次数:" << num[i] << endl;



    }

    cout <<endl<< "电文中出现的字符的哈夫曼编码如下:"<<endl;

    for (int i = 0; i < 26; i++)

    {  

        ch= (char)(i + 97);

        cout << ch << "的HFM编码:";

        for (int j = HuffCode[i].start; j < n; j++)

        {

            cout<<HuffCode[i].bit[j];

        }

        cout << endl;

    }

    cout << endl;

}



void translate_CI(string str)    //将字符转为0-1编码

{

    int k;

    cout << "转换前字符:";

    for (int i = 0; i < length(str); i++)

    {

        cout << str[i]<<" ";

    }

    cout <<endl<< "转换后:";

    for (int i = 0; i < length(str); i++)

    {

        k = str[i] - 97;

        for (int j = HuffCode[k].start; j < n; j++)//输出对应字母的哈夫曼编码

        {

            cout << HuffCode[k].bit[j];

        }

        cout << " ";

    }

   

}



void decode(HNodeType HFMTree[], HCodeType HuffCode[], string str)//将0-1编码转为电文

{  

    int p;

 

    string str2="";

    p = 2 * n - 2;

    for (int i = 0; i < length(str); i++)

    {

        if (str[i] == '0')

        {

            p = HFMTree[p].lchild;

        }

        else if (str[i] == '1')

        {

            p = HFMTree[p].rchild;

        }



        if (HFMTree[p].lchild == -1 && HFMTree[p].rchild == -1)

        {

            str2 += char(p + 97);

            str2 += " ";

         

           if(i<length(str)-1)//如果是最后一次遍历可以不要在恢复了

            p = 2 * n - 2;

        }



    

    }

    if (HFMTree[p].lchild == -1 && HFMTree[p].rchild == -1)

    {

        cout <<"编码转换的电文为:"<<str2;

    }

    else

        cout << "编码错误,无法转换";



}

五.程序运行结果(程序运行结果的一些截图)

 

 

 

六.实验总结(调试过程中遇到哪些问题,怎么解决的)

问题一:26个字母如何建立好哈夫曼树

      我想了一下就以数组的形式在下标为0-25的空间中依次逻辑对应a-z,因为在建立哈夫曼树时会遍历整体,所以怎么在这26个空间存无所谓只需要逻辑对应就行;

问题二:每个叶节点权重怎么传递

      开辟一个num[25],遍历整个电文,利用ascll-97就能依次存num[i]中利用HFMTree[i].weight=num[i],完美传递权重.

问题三:解码的时候不知道如何截取一截对应

      刚开始想要依靠字符串拼接一次一次的遍历循环找对应,但算法太累,循环次数过多等缺点过于明显放弃。

       之后通过查找CSDN理解原来可以依靠哈夫曼树,只要这个结点左右孩子下标都是-1就是找到了对应的字符,然后存进数组就行,可行性高,逻辑明确。

  • 5
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
综合实验: 1. 问题描述 利用哈夫曼编码进行通信可以大大提高信道利用率,缩短信息传输时间,降低传输成本。这要求在发送端通过一个编码系统对待传输数据预先编码,在接收端将传来的数据进行译码(复原)。对于双工信道(即可以双向传输信息的信道),每端都需要一个完整的编/译码系统。试为这样的信息收发站编写一个哈夫曼码的编/译码系统。 2. 基本要求 一个完整的系统应具有以下功能: (1) I:初始化(Initialization)。从终端读入字符集大小n,以及n个字符和n个权值,建立哈夫曼树,并将它存于文件hfmTree中。 (2) E:编码(Encoding)。利用已建好的哈夫曼树(如不在内存,则从文件hfmTree中读入),对文件ToBeTran中的正文进行编码,然后将结果存入文件CodeFile中。 (3) D:译码(Decoding)。利用已建好的哈夫曼树将文件CodeFile中的代码进行译码,结果存入文件Textfile中。 (4) P:印代码文件(Print)。将文件CodeFile以紧凑格式显示在终端上,每行50个代码。同时将此字符形式的编码文件写入文件CodePrin中。 (5) T:印哈夫曼树(Tree printing)。将已在内存中的哈夫曼树以直观的方式(比如树)显示在终端上,同时将此字符形式的哈夫曼树写入文件TreePrint 中。 3. 测试数据 用下表给出的字符集和频度的实际统计数据建立哈夫曼树,并实现以下报文的编码和译码:“THIS PROGRAME IS MY FAVORITE”。 字符 A B C D E F G H I J K L M 频度 186 64 13 22 32 103 21 15 47 57 1 5 32 20 字符 N O P Q R S T U V W X Y Z 频度 57 63 15 1 48 51 80 23 8 18 1 16 1

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

五敷有你

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值