3001基于哈夫曼树的数据压缩算法(附思路及注释)
输入一串字符串,根据给定的字符串中字符出现的频率建立相应哈夫曼树,构造哈夫曼编码表,在此基础上可以对待压缩文件进行压缩(即编码),同时可以对压缩后的二进制编码文件进行解压(即译码)。
输入
多组数据,每组数据一行,为一个字符串(只考虑26个小写字母即可)。当输入字符串为“0”时,输入结束。
输出
每组数据输出2n+3行(n为输入串中字符类别的个数)。第一行为统计出来的字符出现频率(只输出存在的字符,格式为:字符:频度),每两组字符之间用一个空格分隔,字符按照ASCII码从小到大的顺序排列。第二行至第2n行为哈夫曼树的存储结构的终态(形如教材139页表5.2(b),一行当中的数据用空格分隔)。第2n+1行为每个字符的哈夫曼编码(只输出存在的字符,格式为:字符:编码),每两组字符之间用一个空格分隔,字符按照ASCII码从小到大的顺序排列。第2n+2行为编码后的字符串,第2n+3行为解码后的字符串(与输入的字符串相同)。
输入样例 1
aaaaaaabbbbbccdddd
aabccc
0
输出样例 1
a:7 b:5 c:2 d:4 1 7 7 0 0 2 5 6 0 0 3 2 5 0 0 4 4 5 0 0 5 6 6 3 4 6 11 7 2 5 7 18 0 1 6 a:0 b:10 c:110 d:111 00000001010101010110110111111111111 aaaaaaabbbbbccdddd a:2 b:1 c:3 1 2 4 0 0 2 1 4 0 0 3 3 5 0 0 4 3 5 2 1 5 6 0 3 4 a:11 b:10 c:0 111110000 aabccc
思路:
比较详细了。。希望你看过后可以先自己动手尝试实现~
哈夫曼树的节点说明一下:一个节点存的除了左右节点,parent,权值、还包括字符和它的编码。
看第一行输出,是每个字母及其出现频率,那么可以想到用map来存储相关信息,字母是key,出现次数通过遍历字符串累加作为value。
之后是创建树,先让题目里给的那几个节点初始化,双亲和子节点都是0,利用刚才的map的迭代器,存每个结点的data和weight。ass是辅助map,用来记录当前权值(key)和是否已经被使用过了(value,0表示用过了,1表示没有,一会创建新节点的权值要从这里面挑选value里是1且最小的返回key),故ass[it->second]=1.
FindParent返回的是一个嵌套的对组。设置最小权值min1,min2以及其对应的节点序号i,j,先遍历ass,依据上述选择标准选出min1。min2不能与min1相同——若不存在相同的权值,则min1!=min2;若存在相同的权值,那么min2不会被赋值,仍然是30000(一开始设个比较大的初始值),这种情况下再修改min2=min1。在哈夫曼树里遍历min1,min2,记录其对应的节点序号,此时又要考虑min1=min2的情况,若发生了,那么再单独遍历一次树,设一个flag记录第二次出现树里某个节点权值=min2的时候再赋值j=节点序号。返回一个包含两个最小权值和孩子序号的对组。
回到Create函数里,用上述返回值创建新节点,新权值是两个老权值相加,子节点序号也有了,顺便更新子节点的parent是现在节点的序号。最后别忘了令最后一次构造的节点parent=0!!
接下来是为每个节点创建哈夫曼编码,从每个叶子节点开始向上求parent,再看它是parent的左节点还是右节点,判断code是加一个0还是加一个1.注意:代码中code每次赋值不能写+=,不然顺序是反着的!!
接下来就到了轻松愉快的输出环节~第一行map m解决;表格和code就遍历树输出即可;解码如果想省事的话就直接输出原字符串xd,如果想写的话就在输出编码的时候用string decode记录下编码后的字符串,解码输出即可;
解码函数思路如下:在树里从头遍历编码字符串的每一位,是0就走左边,是1就走右边,直到到了叶子节点,输出那个节点的data即可,别忘了每次输出完了之后回到根节点呀!!
代码如下:
#include<iostream>
#include<string>
#include<algorithm>
#include<vector>
#include<set>
#include<map>
using namespace std;
typedef struct HNode
{char data;//数据 int parent, weight, lchild, rchild;//双亲,权值,左右孩子 string code;//每个节点自己的哈夫曼代码
}*HTree, HNode;
void DeCode(HTree ht, string s, int m)//解码
{int i = m, j = 0;while (s[j]){if (s[j] == '0')i = ht[i].lchild;elsei = ht[i].rchild;if (ht[i].lchild == 0 && ht[i].rchild == 0)//是叶子节点{cout << ht[i].data;i = m;//回到根节点}j++;}
}
void Cout(map<char, int> m, int size, HTree ht, string s)
{//打印字符和频率for (map<char, int>::iterator it = m.begin(); it != m.end(); it++){if (it != m.begin())cout << " ";printf("%c:%d", it->first, it->second);}cout << endl;//打印表格for (int i = 1; i <= size * 2 - 1; i++)printf("%d %d %d %d %d\n", i, ht[i].weight, ht[i].parent, ht[i].lchild, ht[i].rchild);//打印字符及其对应的Huffman Codefor (int i = 1; i <= size; i++){if (i != 1)cout << " ";printf("%c:%s", ht[i].data, ht[i].code.c_str());}cout << endl;map<char, int>::iterator it = m.begin();string decode;for (int i = 0; i < s.length(); i++)//i控制输出次数{for (int k = 1; k <= size; k++, it++)//匹配ht里的data和当前字符{if (ht[k].data == s[i])//找到了{cout << ht[k].code;decode += ht[k].code;break;}}it = m.begin();}cout << endl;DeCode(ht, decode, size * 2 - 1);//解码cout << endl;
}
pair<pair<int, int>, pair<int, int>> FindParent(map<int, int>& ass, HTree ht, int size,int nowsize)//小蝌蚪找妈妈(大雾)
{int min1 = 30000, min2 = 30000;//记录当前的两个最小权值 int p1 = 0, p2 = 0;int i = 0, j = 0;//记录当前节点的两个孩子 for (map<int, int>::iterator it = ass.begin(); it != ass.end(); it++){if (it->first < min1 && it->second == 1){min1 = it->first;it->second = 0;}}for (map<int, int>::iterator it = ass.begin(); it != ass.end(); it++){if (it->first < min2 && it->first != min1 && it->second == 1){min2 = it->first;it->second = 0;}}if (min2 == 30000)//测试用例2min2 = min1;for (int k = 1; k < size; k++){if (ht[k].weight == min1)i = k;if (ht[k].weight == min2)j = k;if (i != 0 && j != 0)break;}if (min1 == min2)//测试用例2{int flag = 0;for (int k = 1; k <= nowsize; k++){if (min1 == ht[k].weight)flag++;if (flag == 2){j = k; break;}}}pair<int, int > weight = make_pair(min1, min2);pair<int, int > parent = make_pair(i, j);pair< pair<int, int>, pair<int, int>>ans = make_pair(weight, parent);return ans;
}
void Create(HTree& ht, int size, map<char, int> mp, map<int, int>ass)//构造哈夫曼树
{if (size <= 1)return;else{int m = size * 2 - 1;//最多有这么多个节点int patch = m + 1;//如果不这么写,在下面的[]里写m+1的话,oj会报错compile error ht = new HNode[patch];//0号下标不用,HT[m]表示根结点map<char, int>::iterator it = mp.begin();for (int i = 1; i <= size; i++, it++)//初始化前面几个有数值的已知节点{ht[i].lchild = 0;ht[i].rchild = 0;ht[i].parent = 0;ht[i].data = it->first;ht[i].weight = it->second;ass[it->second] = 1;}//补齐后面几个节点的weight,lch,rchfor (int i = size + 1; i <= m; i++){pair<pair<int, int>, pair<int, int>>ans = FindParent(ass, ht, m,i);ht[i].weight = ans.first.first + ans.first.second;ht[i].lchild = ans.second.first;ht[i].rchild = ans.second.second;ht[ans.second.first].parent = i;ht[ans.second.second].parent = i;ass[ht[i].weight] = 1;}ht[m].parent = 0;}
}
void SetCode(HTree ht, int size)
{for (int i = 1; i <= size; i++){int fammem = ht[i].parent;while (fammem != 0){if (ht[fammem].lchild == i)ht[i].code = '0' + ht[i].code;elseht[i].code = '1' + ht[i].code;fammem = ht[fammem].parent;}}
}
int cmp(char a, char b)
{return a < b;}
void SetMap(map<char, int>& m, string s)
{for (int i = 0; i < s.length(); i++)m[s[i]]++;
}
int main()
{char temp[100];while (cin >> temp && temp[0] != '0'){HTree ans;string s = temp;//为了获取长度string cd = temp;//为了记录下原式字符串sort(temp, temp + s.length(), cmp);//ASCII排序s = temp;//现在再次赋值,是排好序的了map<char, int>m;//记录字母种类以及出现次数map<int, int>ass;//辅助,为了让min2和min1不一样SetMap(m, s); //存每个字符以及他们的频率到map中,记得参数写引用!!!Create(ans, m.size(), m, ass);//创建二叉树SetCode(ans, m.size());//为每个节点创建Huffman CodeCout(m, m.size(), ans, cd);//输出啦!}return 0;
}
3001基于哈夫曼树的数据压缩算法(附思路及注释)相关推荐
- 数据结构“基于哈夫曼树的数据压缩算法”的实验报告
一个不知名大学生,江湖人称菜狗 original author: jacky Li Email : 3435673055@qq.com Last edited: 2022.11.20 目录 数据结构& ...
- BJFU_数据结构习题_262基于哈夫曼树的数据压缩算法
欢迎登录北京林业大学OJ系统 http://www.bjfuacm.com 262基于哈夫曼树的数据压缩算法 描述 输入一串字符串,根据给定的字符串中字符出现的频率建立相应哈夫曼树,构造哈夫曼编码表, ...
- 基于哈夫曼树的数据压缩算法
计算机科学与技术系 实 验 报 告 专业名称 计算机科学与技术 课程名称 数据结构与算法 班 级 17计科2班 综合实验2 基于哈夫曼树的数据压缩算法 实验日期 2019.04.29 综合实验二 基于 ...
- 数据结构 基于哈夫曼树的数据压缩算法
数据结构 基于哈夫曼树的数据压缩算法 实验目的 实验内容 实验提示 实验代码 实验小结 实验目的 1.掌握哈夫曼树的构造算法. 2.掌握哈夫曼编码的构造算法. 实验内容 问题描述 输入一串字符串,根据 ...
- 数据结构实验——基于哈夫曼树的数据压缩算法
/* 注:输入为多行字符串,以"0"结尾:例:abc def 0 此程序无法执行由单个字符组成的字符串. */ #include<iostream> #include& ...
- 基于哈夫曼树的英文文本数据压缩算法
基于哈夫曼树的英文文本数据压缩算法 (1)问题描述 输入一串字符串,根据给定的字符串中字符出现的频率建立相应的哈夫曼树,构造哈夫曼编码表,在此基础上可以对压缩文件进行压缩(即编码),同时可以对压 ...
- 赫夫曼编码(基于赫夫曼树的实现)
上一篇文章中我们探讨了赫夫曼树的基本原理和构造方式,而赫夫曼编码可以很有效地压缩数据(通常可以节约20%-90%的空间,具体压缩率依赖于数据的特性). 名词:定长编码,边长编码,前缀码(装B用的) 定 ...
- 哈夫曼编码(基于哈夫曼树-最优二叉树,不唯一)、B树(b-树)、B+树
整合自: http://blog.csdn.net/shuangde800/article/details/7341289 http://www.cnblogs.com/Jezze/archive/2 ...
- 哈夫曼树建立与二叉树WPL算法以及相关例题
目录 哈夫曼树静态数组形式建立 哈夫曼树二叉链表形式建立 求WPL 哈夫曼树编码解码 更新 哈夫曼树的建立有两种方式,一种是通过静态数组的方式来建立(这种方式比较简洁明了好理解),由于不想篇幅太长了, ...
最新文章
- 积神经网络的参数优化方法——调整网络结构是关键!!!你只需不停增加层,直到测试误差不再减少....
- bzoj1564: [NOI2009]二叉查找树
- (十)Java B2B2C o2o多用户商城 springcloud架构- SSO单点登录之OAuth2.0登录认证(1)
- halcon select_shape_xld按区域大小描绘xld
- 计算机应用基础期中上机考试,期中考试计算机应用基础试卷
- c语言中二维数组中产生随机数,C语言中是如何进行随机数生成的[多图]
- linux sh expr冒号,linux expr命令参数及用法详解
- PHP课程第一次实验作业提交
- LAMP架构mariadb/apache的安装及基本使用
- 计算机网络实验四协议分析心得,计算机网络原理实验_使用网络协议分析仪Wireshark...
- App小程序开发外包的费用大约是多少?
- 类型多样的数码配件免抠元素素材,速来收藏
- 基于深度学习的物体识别系统
- 算法日志:python把终端的信息存为log和logging
- 为什么C语言要有头文件(补充)
- 吐槽一下Win10的输入法管理器
- 使用getsockopt函数判断TCP/IP异常
- GMT北京时间表示的时间算法
- 国外博士后申请心得,博后位置,CV,电话面试面经,签证等
- windows7 旗舰版下载地址