哈夫曼编码实验报告

二.实验内容:

题目:哈夫曼编码/译码

问题描述:

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

基本要求:

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

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

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

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

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

0和1构成)。

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

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

三. 实验方案

(一)算法设计思路:

    1.实现哈夫曼编码首先需要构建最优二叉树,权值越大的叶节点越靠近根节点,其算法为:键盘输入的字符串长度决定最优二叉树的节点数,遍历这个字符串长度,创建具有字符长度n的单节点树。选取根节点权值最小和次小的两个根节点合成一棵树,重复这个过程——把根节点最小和次小的结合直到每个节点都出现在最优二叉树上。

  2.构造哈夫曼编码:

左分支为0,右分支为1,各结点所对应的二进制编码为该节点的哈夫曼编码。采用叶节点向上回溯的方法,每退回一个就记录一位数字。将所得编码存入code[]。

 3.编码:

  根据所得哈夫曼树对比字符串,根据左分支为0右分支为1输出其对应编码。

 4.解码:根据哈夫曼树回溯编码。

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

  Huffmancode为根据哈夫曼编码求出编码函数。

Maxval为最大值。

typedef struct

{

    int weight;

    int lchild, rchild;

    int parent;

}HTNode, * HuffmanTree;树的结点结构体

void Select(HuffmanTree& ht, int i, int& s1, int& s2)构建最优二叉树

void HuffmanCoding(HuffmanTree& HT, HuffmanCode& HC, int* w, int n);//根据哈夫曼树求出哈夫曼编码

void decode(hufmtree tree[]);//依次读入电文,根据哈夫曼树译码

Huffman()为建立哈夫曼树函数。

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

#pragma warning(disable:4996)

#include 

#include

#include 

using namespace  std;

typedef struct

{

    int weight;

    int lchild, rchild;

    int parent;

}HTNode, * HuffmanTree;

typedef char** HuffmanCode;

void Select(HuffmanTree& ht, int i, int& s1, int& s2)

{

    int j, k;

    k = s1;

    for (j = 1; j < i + 1; j++)

        if (s1 != j && j != s2 && ht[j].parent == 0)

        {

            s1 = j; break;

        }

    for (j = 1; j < i + 1; j++)

        if (s2 != j && s1 != j && j != k && ht[j].parent == 0)

        {

            s2 = j; break;

        }

    for (j = 1; j <= i; j++)

        if (ht[j].weight < ht[s1].weight && ht[j].parent == 0)s1 = j;

    if (s1 == s2)

    {

        for (j = 1; j < i + 1; j++)

            if (s2 != j && s1 != j && j != k && ht[j].parent == 0)

            {

                s2 = j; break;

            }

    }

    for (j = 1; j <= i; j++)

        if (ht[j].weight < ht[s2].weight && ht[j].parent == 0 && j != s1)

            s2 = j;

}

void HuffmanCoding(HuffmanTree& HT, HuffmanCode& HC, int* w, int n)

{

    int i, s1, m, s2, start;

    char* cd;

    int c, f;

    if (n <= 1) return;

    m = 2 * n - 1;

    HT = new HTNode[m + 1];

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

    {

        HT[i].weight = w[i - 1];

        HT[i].parent = 0;

        HT[i].lchild = 0;

        HT[i].rchild = 0;

    }

    for (i = n + 1; i <= m; i++)

    {

        HT[i].weight = 0;

        HT[i].parent = 0;

        HT[i].lchild = 0;

        HT[i].rchild = 0;

    }

    cout << "\n哈夫曼树的构造过程如下所示:" << 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;

    }

    HC = new  char* [n + 1];

    cd = new  char[n];

    cd[n - 1] = '\0';

    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] = new  char[n - start];

        strcpy(HC[i], &cd[start]);

    }

    delete cd;

}

int main()

{

    HuffmanTree HT;

    HuffmanCode HC;

    char s[50], s2[20];  int i = 0, count = 0;  int  w[50] = { 0 };

   

    cout << "请输入需要编码的字符串:" << endl;

    cin >> s;

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

    {

        int j;

        for (j = 0; j < count; j++)

            if (s[i] == s2[j])

            {

                w[j]++; i++; break;

            }

        if (j == count)

        {

            s2[count] = s[i];

            w[count]++;

            i++; count++;

        }

    }

    HuffmanCoding(HT, HC, w, count);

    cout << "字符\t\t 频数\t\t编码" << endl;

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

        cout << s2[i] << "\t\t" << w[i] << "\t\t" << HC[i + 1] << endl;

    string s1, s3;

    cout << "输入要编码的英文:" << endl;

    cin >> s1;

    cout << "编码:" << endl;

    for (i = 0; i < s1.length(); i++)

    {

        for (int j = 0; j < count; j++)

        {

            if (s1[i] == s2[j])

            {

                cout << HC[j + 1];

                break;

            }

        }

    }

    cout << endl;

    cout << "输入要解码的哈弗曼码:" << endl;

    cin >> s3;

    char h[10];

    int k = 0, l, j;

    cout << "解码:" << endl;

    while (k <= s3.length())

    {

        for (int i = 1; i <= count; i++)

        {

            l = k;

            for (j = 0; j < strlen(HC[i]); j++, l++)

            {

                h[j] = s3[l];

            }

            h[j] = '\0';

            if (strcmp(HC[i], h) == 0)

            {

                cout << s2[i - 1];

                k = k + strlen(HC[i]);

                break;

            }

        }

    }

    cout << endl;

    return 0;

}

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

哈夫曼编码实验报告_第1张图片

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

  这次的实验是对树的综合运用,其过程基本为根据键盘输入的字符串构造最优二叉树,构造字符串对应的哈夫曼编码,实现解码与编码的操作。这次的操作是对于数据转为树的操作,涉及到树的构建和处理。其中遇到了许多算法方式得问题和对于软件实验不熟悉的问题。例如遇到的c4996问题是没有遇过的问题,经过查询得知在头文件加入#pragma warning(disable:4996)可无视这个错误。这次的实验我做了很久,主要是对于树的知识掌握不够详细,许多问题需要暂停下来查阅才能做到,希望在之后的学习中更加用心,争取做到更好。

 

你可能感兴趣的:(算法,p2p,c++,数据结构)