一.Huffman编码与解码 (Huffman编码、二叉树)
[问题描述]
对一篇英文文章(大于2000个英文字符),统计各字符出现的次数,实现Huffman编码,以及对编码结果的解码。
[基本要求]
(1) 输出每个字符出现的次数和编码,其中求最小权值要求用堆实现。
(2) 在Huffman编码后,要将编码表和英文文章编码结果保存到文件中,编码结果必须是二进制形式,即0 1的信息用比特位表示,不能用字符’0’和’1’表示。
(3) 提供读编码文件生成原文件的功能。

二.数据结构说明
在该程序中使用了两个个结构体来完成编码,用位域来实现bite流存储,字符的种类是根据ascll码表里的字符对应匹配存储的:

const charsourcef = “d:\Cpp-charcode\EnglishSC.txt”;//英文源文章
const char
transf = “d:\Cpp-charcode\EnglishT.txt”;//通过编码翻译的英文文章
const charsortf = “d:\Cpp-charcode\EnglishST.txt”;//分类好的字符及频数编码
const char
codef = “d:\Cpp-charcode\EnglishCode.dat”;//整篇英文文章的编码
const char*bitef = “d:\Cpp-charcode\EnglishBite.dat”; //每一种字符的比特位编码
注意:这里的路径,其中文件夹是要事先手动创建的。

//哈夫曼树
typedef struct HTNode
{
int Ascll;//字符对应的ASCLL码
int weight;//权值
int LC, RC, P;//左,右,父结点下标
}HTNode,*LinkHTNode;

//存储叶子节点编码在哈夫曼树对应的位置及,编码
typedef struct HTStr
{
int pos;//叶子节点的字符在哈夫曼树中的位置
int s;//ASCLL码值
char *code;//字符对应的哈夫曼编码
}*LinkHTStr;

//位域bite
typedef struct Bite
{
unsigned int bit : 1;//占一个位的无符号整形
}Bite;

三、执行结果

原英文文章

哈夫曼树结构(子结点和父结点的情况):
ASCLL为0表示为内节点,并非叶子节点



字符统计情况:


整个文章的哈夫曼码:


通过哈夫曼树解码出的结果:

四、代码情况
所需头文件&结构定义:

#include "stdafx.h"
#include<iostream>
#include<fstream>
#include<iomanip>
using namespace std;const char*sourcef = "d:\\Cpp-charcode\\EnglishSC.txt";//英文源文章
const char*transf = "d:\\Cpp-charcode\\EnglishT.txt";//通过编码翻译的英文文章
const char*sortf = "d:\\Cpp-charcode\\EnglishST.txt";//分类好的字符及频数编码
const char*codef = "d:\\Cpp-charcode\\EnglishCode.dat";//整篇英文文章的编码
const char*bitef = "d:\\Cpp-charcode\\EnglishBite.txt"; //每一种字符的比特位编码//哈夫曼树
typedef struct HTNode
{int Ascll;//字符对应的ASCLL码int weight;//权值int LC, RC, P;//左,右,父结点下标
}HTNode,*LinkHTNode;//存储叶子节点编码在哈夫曼树对应的位置及,编码
typedef struct HTStr
{int pos;//叶子节点的字符在哈夫曼树中的位置int s;//ASCLL码值char *code;//字符对应的哈夫曼编码
}*LinkHTStr;//位域bite
typedef struct Bite
{unsigned int bit : 1;//占一个位的无符号整形
}Bite;

PS:值得再次强调,文件路径里的文件夹需要自己手动创建好,程序执行过程是不会创建文件夹的。

函数定义&实现:

//分类函数
void sort_str(const char*file1,LinkHTNode &HT)
{char ch;//临时存储每次拿到的字符int s;//用于转换ASCLL码对应的十进制数值int *strw = new int[100];//临时存储英文文章统计后的每种字符的个数//初始化统计字符频数数组for (int i = 0; i < 100; i++){strw[i] = 0;}// 分类文件字符ifstream ifile(file1, ios::in);while (ifile.get(ch)){s = ch;if (s == 10) { strw[0]++; }//换行符if ((s - 31)>0) { strw[s - 31]++; }//32-127号的字符}//统计出现的字符种类s = 0;for (int i = 0; i < 100; i++){if (strw[i] != 0)s++;}//初始化哈夫曼树HT = new HTNode[2 * s ];//0号位不存,需要多开一个单元内存for (int i = 0; i < 2 * s ; i++){HT[i].Ascll = 0; HT[i].weight = 0;HT[i].LC = HT[i].RC = HT[i].P = 0; }HT[0].weight = s;//叶子结点数//剔除未出现的字符,存储字符和权值int  k;if (strw[0] != 0)//换行符单独判断存储{HT[1].Ascll = 10;HT[1].weight = strw[0];HT[0].Ascll += HT[1].weight;k = 2;//有换行符就从2位置开始存储之后的字符}else { k = 1; }//否则,从1号位开始for (int i=1;i <100; i++){if (strw[i] != 0){HT[k].Ascll = i + 31;HT[k].weight = strw[i];HT[0].Ascll += HT[k].weight;k++;}}delete []strw;//销毁临时空间
}//初建堆
void HeapAdjust(LinkHTNode &HT, int s, int m)//哈夫曼树,堆头,堆尾
{HTNode rc = HT[s];//暂存堆顶结点for (int j = 2 * s; j <= m; j *= 2){if (j < m&&HT[j].weight > HT[j + 1].weight)++j;//左右孩子比较大小,取小的一个if (rc.weight <= HT[j].weight)break;HT[s] = HT[j]; s = j;//较小的孩子与父节点比较,小的最后作为的父节点}HT[s] = rc;
}
void CreatHeap(LinkHTNode &HT)
{int n = HT[0].weight;//初始堆的个数,即叶子节点数for (int i = n / 2; i > 0; --i)HeapAdjust(HT, i, n);
}//堆排序
void HeapSort(LinkHTNode &HT,LinkHTStr &Str)//哈夫曼树,叶子结点表
{CreatHeap(HT);Str = new HTStr[HT[0].weight];//动态建立Strint n = HT[0].weight;//叶子结点数int k = 0;int i = 2 * n - 1;//哈夫曼树表尾//创建哈夫曼树for ( ;i >1 ;i--){k++;HT[i]= HT[1];//选出的堆顶元素放到哈夫曼树尾if (k % 2) { HT[1] = HT[n]; n--;  }//只选出一个最小数时,堆尾放上上对顶else //选出两个最小数之后,合成新的节点,合成新的结点放在堆顶{ HT[1].weight = HT[i + 1].weight + HT[i].weight; HT[1].Ascll = 0; HT[1].LC = i + 1;HT[1].RC = i;}HeapAdjust(HT, 1, n);//堆排}//挑选叶子节点储存到另一个空间n--;for (; i <= k + 1; i++){if (HT[i].LC) { HT[HT[i].LC].P = i; }if (HT[i].RC) { HT[HT[i].RC].P = i; }if (HT[i].Ascll) { Str[n].pos = i; Str[n].s = HT[i].Ascll; n++; }}
}//哈夫曼编码
void HTFmanCode(LinkHTNode &HT,LinkHTStr &Str)
{char *code = new char[HT[0].weight];//临时的存储每一个字符的编码int n = HT[0].weight-1;int f, c;//f为父结点,c为子结点for (int i = 0; i < HT[0].weight; i++){f = HT[Str[i].pos].P;//父节点c = Str[i].pos;//子节点while (f){if (c == HT[f].LC) { code[n] = '0'; }else { code[n] = '1'; }n--;c = f;//往根的方向回溯,子结点更改为它的父结点f = HT[f].P;}//整理每次编好的字符编码,存储到Str[i].code中int length = HT[0].weight - n - 1;Str[i].code = new char[length+1];Str[i].code[length] = '\0';for(int k=0;k<length;k++){Str[i].code[k] = code[n + 1];n++;}}
}// 存储
void Save(const char*filechar, const char*filecode, LinkHTStr Str,LinkHTNode HT)
{ofstream ofilechar(filechar, ios::out);//储存字符,权值,编码的文件ofstream ofilecode(filecode, ios::binary);//存储整篇文章的编码的文件ofstream ofilebite(bitef, ios::binary);//存储每种字符的编码文件ifstream ifile(sourcef, ios::out);char ch; Bite B_Save;//储存字符,权值,编码到文件ofilechar << "字符" << setw(20) << "频数" << setw(20) << "编码" << endl;for (int i = 0; i < HT[0].weight; i++){if (Str[i].s == 10) { ofilechar << "LF" << setw(20) << HT[Str[i].pos].weight << setw(22) << Str[i].code << endl; continue; }if (Str[i].s == 32) { ofilechar << "Space" << setw(17) << HT[Str[i].pos].weight << setw(22) << Str[i].code << endl; continue; }ofilechar << char(Str[i].s) << setw(21) << HT[Str[i].pos].weight << setw(22) << Str[i].code << endl;//下面的for用于存储编码的比特位(每种字符的)for (int k = 0; Str[i].code[k] != '\0'; k++){if (Str[i].code[k] == '0')B_Save.bit = 0;else B_Save.bit = 1;ofilebite << B_Save.bit;}}//存储整篇文章的编码while (ifile.get(ch)){for (int i = 0; i < HT[0].weight; i++){if (ch == char(Str[i].s)){ofilecode << Str[i].code;}}}//关闭文件ofilechar.close();ofilecode.close();ofilebite.close();ifile.close();}
//通过01文件编码翻译文章
void Translate(const char*filecode, const char*fileTrans,LinkHTNode HT)
{ifstream ifile(filecode, ios::in);ofstream ofile(fileTrans, ios::out);char ch;int f=1;while (ifile.get(ch)){if (ch == '0')f = HT[f].LC;else f = HT[f].RC;if (HT[f].LC == 0&&HT[f].RC == 0) { ofile << char(HT[f].Ascll); f = 1; continue; }}ifile.close();ofile.close();
}

主函数:

int main()
{HTNode *HT;HTStr *Str;sort_str(sourcef,HT);HeapSort(HT, Str);HTFmanCode(HT, Str);Save(sortf, codef, Str, HT);Translate(codef, transf, HT);cout << "字符总个数:  " << HT[0].Ascll <<'\n'<< endl;cout << "字符总类:   " << HT[0].weight << '\n' << endl;cout << "哈夫曼树创建成功\n" << endl;cout << "所有字符以及、字符对应的哈夫曼编码已保存到相应的txt文件\n"<<endl;ofstream of(bitef, ios::out);of << "ASCLL码" << setw(10) << "位置" << setw(10) << "左孩子" << setw(10) << "右孩子" << setw(10)<<"父结点"<<endl;for (int i = 1; i < 2 * HT[0].weight; i++){of << HT[i].Ascll << setw(10) << i << setw(10) << HT[i].LC << setw(10) << HT[i].RC << setw(10) << HT[i].P << endl;}of.close();return 0;}

五、小结

  1. 分类函数是把原文章的字符分好类,并统计好出现的频数,并把出现的次数当作其权值大小。
  2. 在这里用了堆排序进行筛选每次新增结点和原始节点中的最大权值。

哈夫曼编码--英语文章的编码译码(c/c++)相关推荐

  1. 哈夫曼树的构建、编码以及带权路径长计算

    给定n个权值作为n个叶子结点,构造一棵二叉树,若该树的带权路径长度达到最小,称这样的二叉树为最优二叉树,也称为哈夫曼树(Huffman Tree).哈夫曼树是带权路径长度最短的树,权值较大的结点离根较 ...

  2. 哈夫曼树原理及Java编码实现

    文章目录 前言 一.哈夫曼树原理 二.哈夫曼编码(Java题解) 参考资料 前言 所有博客文件目录索引:博客目录索引(持续更新) 源代码:Gitee-Huffman.java.Github-Huffm ...

  3. 【id:179】【20分】C. DS二叉树--赫夫曼树的构建与编码(不含代码框架)

    题目描述 给定n个权值,根据这些权值构造huffman树,并进行huffman编码 参考课本P147算法6.12 HuffmanCoding代码,注意数组访问是从位置1开始 要求:赫夫曼的构建中,默认 ...

  4. c语言最优树的构造,哈夫曼树的构造及编码 Haffman树的构造及其编码

    写出构造完整的哈夫曼树的编码 void HuffmanCoding(HuffmanCode HC[], int w[], int n) // w存放n个字符的权值(均>0),构造哈夫曼树HT, ...

  5. 信息论与编码_哈夫曼编码

    哈夫曼树 哈夫曼树(Huffman Tree)也是一种特殊的二叉树,这种树的所有叶子结点都带有权值,从中构造出带权路径长度最短的二叉树,即哈夫曼树. 哈夫曼树的定义 ​ 设二叉树具有n个带权值的叶子结 ...

  6. [题解] 哈夫曼编码(附图分析)

    "Don't bark up the wrong Binary Tree." [问题描述] 我们称树的带权路径长度(WPL)最小的二叉树为"哈夫曼树"或&quo ...

  7. 文件的哈夫曼编码与解码

    文件的哈夫曼编码与解码 编码过程中,踩了一些小坑,做下记录: 1.全局变量count与std:count矛盾,建议用其他变量名. 2.内存泄漏问题 注意空间要开够 指针不可越界 main函数内开辟的栈 ...

  8. 使用Java实现哈夫曼编码(Huffman Coding)

    文章目录 (一)需求分析 (二)构建哈夫曼树 (三)构建哈夫曼编码 (四)哈夫曼编码的解码 (五)哈夫曼编码压缩的原理 (六)总结 (七)Java代码实现哈夫曼树:构建节点类&二叉树类 (八) ...

  9. 5.1 Python图像处理之图像编码-哈夫曼编码

    5.1 Python图像处理之图像编码-哈夫曼编码 文章目录 5.1 Python图像处理之图像编码-哈夫曼编码 1 算法原理 2 代码 3 效果 1 算法原理 哈夫曼编码是一种根据词频变化的变长二进 ...

最新文章

  1. 年轻人不讲武德,where 1=1 是什么鬼?
  2. SQL Server 2016新特性:列存储索引新特性
  3. 面向对象程序设计案例
  4. 多区域显示(8)-透明花边
  5. android自定义抽奖,Android自定义view制作抽奖转盘
  6. Apache的简单应用
  7. 51单片机—串口通信
  8. 05Prism WPF 入门实战 - Navigation
  9. 多种语言《九九乘法表》荟萃:C、C++、C#、JavaScript、SQL、VB、VBA、Python
  10. 【Unity】Update()和FixedUpdate()
  11. 硬件测试含软件调试,硬件调试与测试规范.doc
  12. css实现圆球旋像水波波动_手机拍屏幕烦人的“水波纹”小米10靠它给解决掉了...
  13. VirtualBox虚拟机如何选中“启用嵌套 VT-x/AMD-V”
  14. 20190905每日一句
  15. iOS录音及播放全解
  16. 微信小程序返回Qcloud\\Cos\\Exception\\NoSuchBucketException: Cos Error Code: NoSuchBucket, Status Code: 404
  17. android夜间模式监控
  18. 云计算现在前景如何?怎么转型成为云计算工程师?
  19. sudoku me_Sudoku,一个完整的MFC应用程序。 第7部分
  20. 开发那些坑之使用百川趣拍sd集成真实项目

热门文章

  1. 迪克体育Dick’s Sporting Goods EDI需求分析
  2. DriverStudio开发PCI设备DMA数据传输
  3. 邮箱申请免费注册163,企业免费邮箱域名注册
  4. 在线音乐迎来产消多维时代,菠萝BOLO要做“原创音乐视频工厂”?
  5. 苹果macOS10.15.7新版本下的SecureFX与SecureCRT破解后显示文件受损解决方法
  6. VM30031:1 Uncaught ReferenceError: xxx is not defined
  7. 【C语言循环结构题目】在屏幕上打印n行*号倒三角形(此处n为6)
  8. flex 教程_完整的flex教程
  9. 异常检测(Anomaly detection)方法小结
  10. 网页无插件实时浏览海康和大华硬盘录像机视频技术解决方案