哈夫曼编码-译码器的设计与实现 (数据结构课设)

数据结构课程设计。用的C++写的。

一、问题描述

打开一篇英文文章,统计该文章中每个字符出现的次数,然后以它们作为权值,对每一个字符进行编码,编码完成后再对其编码进行译码。

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

测试数据(ToBeTran.txt)

Next morningthey met at breakfast. All three were somewhat silent. It was as if the weightof the matter which was that day to be discussed pressed upon their spirits.The smallest of the trio, Septimus Codd by name, who was habitually taciturn,spoke scarcely a word. He was a strange little man, a nineteenth centuryvillain in a sense. He was a rogue and a vagabond, yet his one hobby, apartfrom his business, was a study of the Past, and many an authority on EasternHistory would have been astonished at the extent of his learning. He was neverso happy as when burrowing amongst ancient records, and it was mainly due tohis learning in the first place, and to a somewhat singular accident in thesecond, that the trio were now foregathered in Singapore. His personalappearance was a peculiar one. His height was scarcely more than four feet sixinches. His face was round, and at a distance appeared almost boyish. It wasonly when one came to look into it more closely, that it was seen to be scoredby numberless small lines. Moreover it was unadorned by either beard ormoustache. His hair was grey, and was worn somewhat longer than is usual. Hecould speak fluently almost every language of the East, and had been imprisonedby the Russians for sealing in prohibited waters, had been tortured by theChinese on the Yang-tse, and, to his own unextinguishable disgrace, flogged bythe French in Tonquin. Not the least curious trait in his character was theaffection he entertained for Kitwater. The pair had been together for years,had quarrelled repeatedly, but had never separated. The record of their doingswould form an interesting book, but for want of space cannot be more thanreferred to here. Hayle had been their partner in not a few of their curiousundertakings, for his courage and resource made him a valuable ally, though howfar they trusted each other it is impossible to say.

三、数据与结构说明

1.typedef struct

{

char ch;//出现的各字符种类

char bits[15];//各字母的码字

int len;

}CodeNode;

typedef CodeNode HuffmanCode[256];//结构体数组表示译码部分数据

2.typedef struct

{

//数据成员

int weight;//权数据域

int parent, lchild,rchild;//双亲,左右孩子域

char key;

}HufNode ;

typedef HufNode nodes[256];// 用结构体数组表示编码部分数据

3. void Getfrequen(int d[256], int& n,char page[])//字符统计函数

4. void Getfrequen(int d[256], int& n,char page[])//字符统计函数

5. void starttree(nodes& HT,int& n)//哈夫曼树初始化

6. void select(nodes HT,int k, int& r1, int& r2)//挑选最小的和次小的二叉树

7. void Savefile(nodes& HT, HuffmanCode& HC)//保存文件

8. void HufTree(nodes& HT, HuffmanCode& HC, int d[256], char str[],char page[])//哈夫曼树建立

9. void encode(nodes& HT, HuffmanCode& HC)//对各字符进行哈夫曼编码

10. void coding(nodes& HT, HuffmanCode& HC, char st[], char get[])//对文本正文进行编码

11. void decode(HuffmanCode& HC, char code[],char result[])//译码

12. void Cout(char code[], int& c)//读取需译码的文件并统计文件码字数

四、运行截图

(1)初始化(Initialization)。从文件ToBeTran.txt中读入英文字符集,统计字符出现次数,作为权值建立哈夫曼树,获得哈夫曼编码,并存放于文件hfmCode.txt中。

ToBeTran.txt如下图

hfmCode.txt

(2)编码(Encoding)。利用已建好的哈夫曼编码,对文件ToBeTran.txt中的正文进行编码,然后将编码后的结果存入文件CodeFile.txt中。

CodeFile.txt如图

(3)译码(Decoding)。利用哈夫曼编码将文件CodeFile.txt中的代码进行译码,结果存入文件TextFile.txt中。

TextFile.txt如图

源码:

PS:文件路径自己修改,本人用的VS2022运行是没问题的

#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<fstream>
#include <algorithm>
#include <string>
#include <math.h>
using namespace std;

int n;//字符种类个数
typedef struct
{
    char ch;//出现的各字符种类
    char bits[15];//各字母的码字
    int len;
}CodeNode;
typedef CodeNode HuffmanCode[256];

typedef struct 
{
    //数据成员
    int weight;//权数据域
    int parent, lchild, rchild;//双亲,左右孩子域
    char key;
}HufNode ;
typedef HufNode nodes[256];//用结构体数组表示编码部分数据

void Getfrequen(int d[256], int& n,char page[])//字符统计函数
{
    int p = 0;
    ifstream binafile("d://杀鸡结构//ToBeTran.txt", ios::binary);
    n = 0; 
    while (!binafile.eof())//遍历文件,读取文本文件内容,存至类哈希数组中
    {
        unsigned int temp = binafile.get();
        if (temp > 128)break;
        if (d[temp] == 0)
        {
            d[temp] = 1; n++;
        }
        else d[temp]++;
        page[p] = temp;p++; 
    }
    binafile.close();
}

void starttree(nodes& HT,int& n)//哈夫曼树初始化
{
   for (int i = 0; i < 2 * n - 1; i++)
    {
        HT[i].lchild = -1;
        HT[i].rchild = -1;
        HT[i].parent = -1;
        HT[i].weight = -1;
    }
}

void select(nodes HT,int k, int& r1, int& r2)//挑选最小的和次小的二叉树
{
    r1 = r2 = -1;
    for (int i = 0; i < k; i++)        //查找树值最小
    {
        if (HT[i].parent == -1)     //只处理根节点
            if (r1 == -1)
                r1 = i;
            else if (HT[i].weight < HT[r1].weight)
            {
                r2 = r1; r1 = i;
            }
            else if (r2 == -1 || HT[i].weight < HT[r2].weight)
                r2 = i;
    }
}

void Savefile(nodes& HT, HuffmanCode& HC)//保存文件
{
    ofstream savefile2;
    savefile2.open("d://杀鸡结构//hfmCode.txt");
    if (!savefile2) {
        cerr << "CodeFile.txt文件打开失败" << endl;
        exit(1);
    }
    for(int h=0;h<n;h++)
        savefile2 <<"权值(频率):" <<HT[h].weight << "       " <<
        "字符:" << HT[h].key << "       " <<"码字:"<<HC[h].bits<< endl;
}

void HufTree(nodes& HT, HuffmanCode& HC, int d[256], char str[],char page[])//哈夫曼树建立
{
    int w, num;
    int i, s1, s2;
    Getfrequen(d, n,page);
    num = n;
    starttree(HT, n);
    
    while(num>0)
   {
      ifstream binafile("d://杀鸡结构//ToBeTran.txt", ios::binary);
      while (!binafile.eof())//遍历文件
      {
         unsigned int temp= binafile.get(); 
          if (d[temp] <= 0)continue;
          w = *max_element(d, d + 256);
          if (d[temp] == w)//对结点的权值进行赋值
          {
              HT[num - 1].weight = w;
              HT[num - 1].key = temp;
              str[num - 1] = temp;
              d[temp] = 0; num--; break;
          }
      }
      binafile.close();
    }
    for (i = n ; i < 2 * n - 1; i++)
    {
        select(HT,i, s1, s2);//选出最小的两个结点(结点位置存放在s1、s2中)
        //往HT序列后一位i放置新生成的父亲结点
        HT[s1].parent = i;//s1结点的父结点为i结点
        HT[s2].parent = i;//s2结点的父结点为i结点
        HT[i].lchild = s1;//父结点的左孩子结点为s1结点
        HT[i].rchild = s2;//父结点的右孩子结点为s2结点
        HT[i].weight = HT[s1].weight + HT[s2].weight;//计算父结点的权值
    }
    for (i = 0; i < n; i++)//初始化哈夫曼编码
    {
        HC[i].ch = str[i];
    }
}

void encode(nodes& HT, HuffmanCode& HC)//对各字符进行哈夫曼编码
{
    int c, p, i; 
    char cd[256] = {};//记录当前编码
    int start;//记录编码起始位置(结尾位置为n)
    cd[n] = '\0';//设置编码结尾位置
    for (i = 0; i < n; i++)
    {
        start = n-1;
        c = i;
        while ((p = HT[c].parent) > 0)//倒序编码
        {
            start--;
            cd[start] = (HT[p].lchild == c) ? '0' : '1';
            c = p;
        }
        strcpy(HC[i].bits, &cd[start]);
        HC[i].len = n - start;
    }
}

void coding(nodes& HT, HuffmanCode& HC, char  st[], char get[])//对文本正文进行编码
{
    int i, j = 0,length=0;
    while (st[j] != '\0')//根据文本的字符顺序,用字符和哈夫曼编码进行编码
    {
        for (i = 0; i < n; i++)
        {
            if (HC[i].ch == st[j])
            {
                strcat(get, HC[i].bits);
                length += HC[i].len;
                break;
            }
        }
        j++;
    }
    strcat(get, "\0");
    ofstream savefile;
    savefile.open("d://杀鸡结构//CodeFile.txt", ios::binary);
    if (!savefile) {
        cerr << "CodeFile.txt文件打开失败" << endl;
        exit(1);
    }
    savefile<<get;
    savefile.close();
}

void decode(HuffmanCode& HC, char code[],char result[])//译码
{
    char cd[15] ;
    int i, j, k = 0, p = 0, flag;
    while (code[p] != '\0'&&code[p] != '/0')
    {
        flag = 0;
        for (i = 0; i < n && flag == 0 && code[p] != '/0'; i++)
        {
            cd[i] = ' ';                //码字不相等时跳出循环,读取码字长度加1位
            cd[i + 1] = '\0';
            cd[i] = code[p++];
            for (j = 0; j <= n; j++)
            {
                if (strcmp(HC[j].bits, cd) == 0)//字符的码和读出来的码是否相等
                {
                    result[k] = HC[j].ch;
                    k++;
                    flag = 1;
                    break;
                }
            }
        }
    }
    result[k] = '\0';
    ofstream savefile3;
    savefile3.open("d://杀鸡结构//TextFile.txt");
    if (!savefile3) {
        cerr << "TextFile.txt文件打开失败" << endl;
        exit(1);
    }
    savefile3 << result;
    savefile3.close();
}

void Cout(char code[], int& c)//读取需译码的文件并统计文件码字数
{
    ifstream fin;
    fin.open("d://杀鸡结构//CodeFile.txt", ios::binary);
    if (!fin.is_open())
    {
        cerr << "没有此文件或读取错误" << endl;
    }
    while (!fin.eof())//遍历文件
    {
        unsigned int t = fin.get();
        code[c] = t;
        c++;
    }
    fin.close();
}

int main()
{
    n = 0;
    char str[256] = { }; // 出现的字符种类
    char st[20000] = {};// 输入编码字符
    char result[20000] = {};// 为译码结果
    int d[256] = { };//存放字符权值,下标为字符的ASCⅡ码
    nodes HT;

    //1.初始化
    HuffmanCode HC;
    HufTree(HT, HC, d,str,st);
    str[n] = '\0';
    encode(HT, HC);
    Savefile(HT,HC);

    //2.编码
    char get[20000];
    get[0] = '\0';
    coding(HT,HC, st, get);//输入编码字符串的哈夫曼编码
    cout<<"上述字符串的霍夫曼码为:"<< get<<endl<<endl;
    cout<<"编码后结果已存储在CodeFile.txt中"<<endl;

    //3.译码
    char code[20000] = {};//读出来的码
    int c = 0;
    Cout(code, c);
    code[c-1] = '\0';
    decode(HC, code, result);
    cout << endl<<"译码得:";
    for (int f = 0; f < c; f++)
        cout << result[f];
}
  • 4
    点赞
  • 39
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,您想了解关于C语言哈夫曼编码译码器课设数据结构课程设计哈夫曼编码译码器的相关知识,我可以为您提供一些基本的信息。 哈夫曼编码是一种基于统计概率的编码方法,可以将每个字符使用不同长度的二进制编码表示,使得出现频率较高的字符使用较短的编码,出现频率较低的字符使用较长的编码,从而达到压缩数据的效果。 哈夫曼编码译码器实现需要用到数据结构中的哈夫曼树和哈夫曼编码表。哈夫曼树是一种特殊的二叉树,它的叶子节点对应着每个字符,而每个字符的编码可以通过从根节点到该字符的路径上的边的方向来表示。哈夫曼编码表则是一个字符与其对应的二进制编码之间的映射表。 在C语言中,可以使用结构体来表示哈夫曼树和哈夫曼编码表。哈夫曼树的节点可以定义为一个结构体,包含字符、权值和左右子节点指针等属性。而哈夫曼编码表则可以定义为一个数组,每个元素表示一个字符与其对应的编码。 哈夫曼编码译码器实现过程可以分为两个步骤:编码和译码。编码过程中,需要先统计原始数据中各个字符出现的频率,然后根据频率构建哈夫曼树,生成哈夫曼编码表,并将原始数据按照哈夫曼编码进行压缩。译码过程中,则需要通过哈夫曼编码表将压缩后的二进制数据还原成原始数据。 以上是关于C语言哈夫曼编码译码器课设数据结构课程设计哈夫曼编码译码器的基本介绍,希望对您有所帮助。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值