哈夫曼树编码与译码(完整C/C++实现代码)

哈夫曼编码的设计与应用

问题需求分析

用哈夫曼编码(Huffman Coding),又称霍夫曼编码,是一种编码方式,哈夫曼编码是可变字长编码(VLC)的一种。Huffman于1952年提出一种编码方法,该方法完全依据字符出现概率来构造异字头的平均长度最短的码字,有时称之为最佳编码,一般就叫做Huffman编码(有时也称为霍夫曼编码)。
霍夫曼树又称最优二叉树,是一种带权路径长度最短的二叉树。所谓树的带权路径长度,就是树中所有的叶结点的权值乘上其到根结点的路径长度(若根结点为0层,叶结点到根结点的路径长度为叶结点的层数)。树的路径长度是从树根到每一结点的路径长度之和,记为WPL=(W1L1+W2L2+W3L3+…+WnLn),N个权值Wi(i=1,2,…n)构成一棵有N个叶结点的二叉树,相应的叶结点的路径长度为Li(i=1,2,…n)。

数据结构的定义

哈夫曼树结构体包含如下内容:节点权重,当前节点的父节点,左右子树,节点信息。
哈夫曼编码结构体包含如下内容:存编码的数组,编码数组的开始标志。

功能详细设计

构建哈夫曼树:使用一维数组,每个节点存储权重,父节点,左子树,右子树,以及数值的信息。遍历整个数组,根据每个节点的权重去找到最小以及第二小的节点,然后对各自的父节点,左右子树赋值,建立两个节点的联系将他们的联系填入该结构体数组中。
哈夫曼树如下图:
a权重45; b权重15; c权重12; d权重16; e权重9; f权重5
在这里插入图片描述
哈夫曼树结构体数组如下图(使用a, b, 58举例):
在这里插入图片描述
根据哈夫曼树建立哈夫曼编码:从树的根节点开始,根据每个叶子节点与父节点之间的联系,使用哈夫曼编码结构体中的编码数组储存树种每个叶子节点的编码, 往左边遍历是0, 往右边遍历是1, 举例: a, 由建立好的哈夫曼树可得, 当遍历查找到a的时候, a到root的路径是: 100->86->58->a, 所以可得编码就是000;

根据哈夫曼编码将指定的编码转化为字符串:读取到哈夫曼编码后,当编码为0表示节点是左子树,当编码为1的时候表示右子树,根据已经建立好的哈夫曼树,利用顺序遍历的方式,根据左0右1,寻找哈夫曼树中的叶子节点,当某一节点在哈夫曼树中左右子树都为空的时候,表示该节点即使叶子节点,然后输出对应叶子节点在哈夫曼编码数组中的位置, 其原理与编码的方式恰恰相符, 而是根据01数字查找对应的叶子节点.

函数调用图:

在这里插入图片描述

编写代码体会

遇到的问题是数组下标没有弄好,导致建立哈夫曼树时出现各种错误, 进行编码过程没有将lchild与rchild的”变化写在一起”导致出现错误,其实最大的问题是:没有将代码的逻辑思路考虑清楚,还有边界条件值,最蠢的是没有打一下草稿,写一下伪代码,把程序的思想理解,导致编程的过程中出现各种问题,以后写代码之前还是把逻辑理清楚再动手写代码,最后再将代码写到电脑上测试。

完整代码

#include<iostream>
#include<string>
#include<fstream> 
using namespace std;
struct Htnode{int weight,parent,lchild,rchild;char c; 
};
struct Htcode{int bit[25],start;
};
int type(int a[]){string s;int sum = 0; cout<<"输入需要编码的字符串"<<endl;cin>>s;for(int i = 0; i < s.size(); i++){a[s[i]-'a']++;}cout<<"出现的字母种类以及频率:"<<endl; for(int i = 0; i < 26; i++){if(a[i] != 0){char c = char(i+'a');cout<<"i:"<<i<<" c:"<<c<<":"<<a[i]/(s.size()*1.0)<<endl;sum++;	}}return sum;
} 
//通过数组的方式构建哈夫曼树 
void HufmanTree(Htnode h[],int n, int a[]){int i,j,max1,max2,x1,x2;for(i=0;i<2*n;i++){h[i].weight=0;h[i].parent=-1;h[i].lchild=-1;h[i].rchild=-1;h[i].c='\0';}for(i=0;i<26;i++){if(a[i] != 0){h[i].c = i + 'a';h[i].weight = a[i]; }}for(i=0;i<n-1;i++){max1=1000,max2=1000;x1=-1,x2=-1; for(j=0;j<n+i;j++){if(h[j].weight<max1 && h[j].parent==-1){max2=max1;x2=x1;max1=h[j].weight;x1=j;}else if(h[j].weight<max2 && h[j].parent==-1){max2=h[j].weight;x2=j;}}//根据每个节点信息, 将其信息存储到节点数组中h[x1].parent=n+i; h[x2].parent=n+i; h[n+i].weight=h[x1].weight+h[x2].weight;h[n+i].lchild=x1;h[n+i].rchild=x2;}for (i=0;i<2*n-1;i++){cout<<h[i].weight<<" "<<h[i].parent<<" "<<h[i].lchild<<" "<<h[i].rchild<<" "<<h[i].c<<endl; }
}
//哈夫曼编码
//根据叶子节点的位置, 将其path路径01数字填充到编码数组中
void  HuffmandeCode(Htnode h[], int n, int a[], Htcode hcode[]){HufmanTree(h, n, a);ofstream out;out.open("HuffmandeCode.txt", ios::out);int i,j;for(i=0;i<n;i++){j=0;int parent=h[i].parent;//记录当前节点的父亲 int c=i;while(c!=-1){//parent造成根节点不会被访问 hcode[i].bit[j++]=h[parent].lchild==c?0:1;//从叶子节点到根节点, 应该使用栈结构 c=parent;parent=h[parent].parent;}hcode[i].start=j-1;}for(i=0;i<n;i++){cout<<h[i].c<<":";for(j=hcode[i].start-1;j>=0;j--){cout<<hcode[i].bit[j];out<<hcode[i].bit[j];}cout<<endl;}out.close(); 
}
string load(){ifstream in("HuffmandeCode.txt");string str;char buffer[256];if(!in.is_open()){cout<<"加载文件错误"<<endl; return NULL;} cout << "载入编码文件" << endl;in.getline(buffer, 100, ' ');return string(buffer);
}//哈夫曼译码
void  HuffmanenCode(string s,int n,Htnode h[]){int i=0,j=0,lchild=2*n-2,rchild=2*n-2;while(s[i]!='\0'){if(s[i]=='0'){//出现的问题是,最初将lchild,rchild分开计算,导致在左右子树间相互变化出现//lchild,rchild不同同时表示同一个节点,最后想到lchild=rchild就能解决问题lchild=h[lchild].lchild;rchild=j=lchild;}if(s[i]=='1'){rchild=h[rchild].rchild;lchild=j=rchild;}if(h[lchild].lchild==-1 && h[rchild].rchild==-1){cout<<h[j].c;lchild=rchild=2*n-2;j=0;}i++;}
}
int main(){Htnode h[30];Htcode hcode[10];int a[26]={0};string s;int n = type(a);cout<<"n:"<<n<<endl;HuffmandeCode(h, n, a, hcode);HuffmanenCode(load(),n,h);return 0;
}

上面有错, 还请指出, 如果认为我写的还不错, 还请点个赞, 多多支持一下, O(∩_∩)O~~

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/468656.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

移动应用开发实例_物联网改变移动应用开发的4种方式

图片来源&#xff1a;pixabay.com来源&#xff1a;物联之家网(iothome.com)转载请注明来源&#xff01;物联网改变了移动应用程序的开发格局。那么&#xff0c;为物联网开发移动应用程序有何不同&#xff1f;物联网与移动应用程序开发齐头并进。物联网改变了人类与机器的互动方…

谁都能看懂的网络模型知识

&#xff11;.网络是我们做嵌入式 避无可避的知识点&#xff0c;但是网络的层次很多&#xff0c;很多时候我们根本理解不了其中的层次和作用&#xff0c;今天跟我们公司的 X 总聊到这个&#xff0c;给我普及了一些知识&#xff0c;我觉得非常有用&#xff0c;分享给大家。最近事…

Java微信公众平台获取签名

如果想使用微信的JSSDK&#xff0c;需要注册公众号和获取签名&#xff0c;Java代码实现如附件&#xff1a; 使用的是servlet&#xff0c;access_token和ticket缓存在application作用域里 附件为源代码&#xff1a;wx.zip转载于:https://www.cnblogs.com/yrcn/p/6831808.html

常用排序算法以及算法性能测试(完整C/C++代码实现)

排序算法性能的比较 注: 由于只是测试算法性能, 所以不会对排序算法做深入讲解, 在随后的时间将会推出排序的详细讲解 问题需求分析 排序算法经过了很长时间的演变&#xff0c;产生了很多种不同的方法。每种算法主要针对不同的数列进行排序&#xff0c;这些排序算法具有各自…

jquery点击事件传值加载页面_jQuery添加options点击事件并传值

var formStr "{supplierId:供应链企业|%-jm-sprt-%|93794498-3}";$.ajax({type : "post",dataType : "json",cache : false,url : "../../../webservice/gmall.json", // 提交到一般处理程序请求数据data :"businessCode6100100…

我就随便BB一下

&#xff11;.如果我开始写文章的时候&#xff0c;停顿了几分钟&#xff0c;那结果应该很明显&#xff0c;这一定是一篇比较垃圾的文章&#xff0c;没什么东西值得看&#xff0c;所以我把之前的删除了&#xff0c;重新开头来写&#xff0c;我认为&#xff0c;一个好的开头一定是…

JS代码优化工具Prepack

最近&#xff0c;Facebook 发布 Prepack :一个优化 JavaScript 源代码的工具&#xff0c;实际上它是一个 JavaScript 部分求值器(Partvaluator)&#xff0c;可在编译时执行原本在运行时的计算过程&#xff0c;并通过重写 JavaScript 代码来提高其执行效率。(西安尚学堂&#xf…

读Java并发编程实践记录_原子性_锁_同步容器详解_任务执行

原子性: 单独的,不可分割的操作 不要使用过期状态值来决策当下的状态, 一定要先检查再执行(不检查, 将引发数据修改,丢失)避免延迟初始化(懒加载: 先查看对象 null, 然后new), 有可能查看对象状态的时候, 对象已经new出来, 只不过还没将对象赋给引用避免复合操作, 例: count;…

和我一起探索嵌入式

&#xff11;.本文为微信群管理员小磊投稿作品&#xff0c;作者计划编写一系列文章&#xff0c;该篇为第一篇&#xff0c;如果有做STM32的同学这将是一个非常好的系列教程&#xff0c;欢迎关注。我15年刚建立了一个BLE的QQ群&#xff0c;很有幸认识了小磊同学&#xff0c;一个非…

经纬度坐标系转东北天_大地坐标系(WGS-84)、地心地固坐标系(ECEF)与东北天坐标系(ENU)的相互转换C语言代码分享...

//ECEF ---> WGS84//pcg为WGS-84坐标系结构体指针&#xff0c;pcc为ECEF坐标系结构体指针void ECEFToWGS(PWGS pcg, PECEF pcc){double B0, R, N;double B_, L_;double X pcc->x;double Y pcc->y;double Z pcc->z;R sqrt(X * X Y * Y);B0 atan2(Z, R);while …

2.简易的登录页面(表单验证)(HTML+JavaScript+Jquery)

//HTML部分 <!DOCTYPE html><html> <head> <meta charset"UTF-8"> <title>登录页面</title> <link rel"stylesheet" type"text/css" href"css/login.css"/> <s…

Java NIO_I/O基本概念_Java中的缓冲区(Buffer)_通道(Channel)_网络I/O

I/O基本概念 缓冲区基础 缓冲区是I/O的基础, 进程使用read(), write()将数据读出/写入从缓冲区中; 当缓冲区写满, 内核向磁盘发出指令, 将缓冲区中数据写入磁盘中(这一步不需要CPU), 当磁盘控制器将缓冲区装满, 内核将缓冲区数据拷贝到进程中指定的缓冲区; 操作如下图: 当中…

跟一个大佬前辈交流了一下

&#xff11;.最近&#xff0c;跟我们公司的测试总监聊天&#xff0c;我随便问了下他几个问题&#xff0c;他也给出了答案&#xff0c;在这里随便聊下&#xff0c;希望给大家的职业生涯中有一些借鉴的作用。也能给新入职场的同学一些方向和指引。2.先介绍下这个技术总监&#x…

python获取目录树_Python读取文件目录树——os.walk

os.walk是Python的内置函数用来遍历文件目录树。[python]import osrootDir d:\assafor dirName, subdirList, fileList in os.walk(rootDir):print(Folder: %s % dirName)for fname in fileList:print(t%s % fname)import osrootDir d:\assafor dirName, subdirList, fileLis…

LINQ简记(1):基本语法

关于LINQ&#xff08;语言集成查询&#xff09;是.NET 3.5和Visual Studio 2008以上版本中引入的一种有趣的全新概念&#xff0c;语言版本有VB和C#&#xff0c;由于C#与.NET平台结合最为紧密&#xff0c;也是MS当初首推的语言&#xff0c;因此&#xff0c;本系列文章的示例代码…

我认识的一位前辈~

&#xff11;.我最近认识了一个老前辈&#xff0c;关注了我的公众号加了我的好友认识的&#xff0c;我想介绍一下这位前辈&#xff0c;不是因为他有多成功&#xff0c;也不是因为他给了我很多钱&#xff0c;我觉得他是一个在平常不过的人了&#xff0c;因为太过于平凡的思考方式…

软件测试缺陷等级划分_缺陷等级的各种划分方法 - 测试新客~~小懒~~ - 51Testing软件测试网 51Testing软件测试网-软件测试人的精神家园...

《缺陷等级标准》缺陷严重级别定义:o 最高级--导致运行中断(应用程序崩溃),预期的功能没有得到实现,测试工作无法继续进行等.o 紧急---事件非常重要,并且需要马上给予关注.o 高级---事件是重要的,并且应该在紧急的事件处理之后尽快得到解决.o 中级---事件是重要的,但是由于解决…

机器学习_决策树_ID3算法_C4.5算法_CART算法及各个算法Python实现

下面的有些叙述基于我个人理解, 可能与专业书籍描述不同, 但是最终都是表达同一个意思, 如果有不同意见的小伙伴, 请在评论区留言, 我不胜感激. 参考: 周志华-机器学习 https://blog.csdn.net/xiaohukun/article/details/78112917 https://blog.csdn.net/fuqiuai/article/d…

http数据绑定spring mvc详解

转载于:https://www.cnblogs.com/panxuejun/p/6834365.html

ESP32 入门教学,不入门,不教学

&#xff11;.Internet of things &#xff08;iot&#xff09;这个概念非常火&#xff0c;物联网是什么&#xff1f;把所有物品通过射频识别等信息传感设备与互联网连接起来&#xff0c;实现智能化识别和管理。 物联网通过智能感知、识别技术与普适计算、泛在网络的融合应用&a…