写在最前:我的思路用到了stl的map,对组pair相关知识。
描述

输入一串字符串,根据给定的字符串中字符出现的频率建立相应哈夫曼树,构造哈夫曼编码表,在此基础上可以对待压缩文件进行压缩(即编码),同时可以对压缩后的二进制编码文件进行解压(即译码)。

输入

多组数据,每组数据一行,为一个字符串(只考虑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基于哈夫曼树的数据压缩算法(附思路及注释)相关推荐

  1. 数据结构“基于哈夫曼树的数据压缩算法”的实验报告

    一个不知名大学生,江湖人称菜狗 original author: jacky Li Email : 3435673055@qq.com Last edited: 2022.11.20 目录 数据结构& ...

  2. BJFU_数据结构习题_262基于哈夫曼树的数据压缩算法

    欢迎登录北京林业大学OJ系统 http://www.bjfuacm.com 262基于哈夫曼树的数据压缩算法 描述 输入一串字符串,根据给定的字符串中字符出现的频率建立相应哈夫曼树,构造哈夫曼编码表, ...

  3. 基于哈夫曼树的数据压缩算法

    计算机科学与技术系 实 验 报 告 专业名称 计算机科学与技术 课程名称 数据结构与算法 班 级 17计科2班 综合实验2 基于哈夫曼树的数据压缩算法 实验日期 2019.04.29 综合实验二 基于 ...

  4. 数据结构 基于哈夫曼树的数据压缩算法

    数据结构 基于哈夫曼树的数据压缩算法 实验目的 实验内容 实验提示 实验代码 实验小结 实验目的 1.掌握哈夫曼树的构造算法. 2.掌握哈夫曼编码的构造算法. 实验内容 问题描述 输入一串字符串,根据 ...

  5. 数据结构实验——基于哈夫曼树的数据压缩算法

    /* 注:输入为多行字符串,以"0"结尾:例:abc def 0 此程序无法执行由单个字符组成的字符串. */ #include<iostream> #include& ...

  6. 基于哈夫曼树的英文文本数据压缩算法

    基于哈夫曼树的英文文本数据压缩算法 (1)问题描述    输入一串字符串,根据给定的字符串中字符出现的频率建立相应的哈夫曼树,构造哈夫曼编码表,在此基础上可以对压缩文件进行压缩(即编码),同时可以对压 ...

  7. 赫夫曼编码(基于赫夫曼树的实现)

    上一篇文章中我们探讨了赫夫曼树的基本原理和构造方式,而赫夫曼编码可以很有效地压缩数据(通常可以节约20%-90%的空间,具体压缩率依赖于数据的特性). 名词:定长编码,边长编码,前缀码(装B用的) 定 ...

  8. 哈夫曼编码(基于哈夫曼树-最优二叉树,不唯一)、B树(b-树)、B+树

    整合自: http://blog.csdn.net/shuangde800/article/details/7341289 http://www.cnblogs.com/Jezze/archive/2 ...

  9. 哈夫曼树建立与二叉树WPL算法以及相关例题

    目录 哈夫曼树静态数组形式建立 哈夫曼树二叉链表形式建立 求WPL 哈夫曼树编码解码 更新 哈夫曼树的建立有两种方式,一种是通过静态数组的方式来建立(这种方式比较简洁明了好理解),由于不想篇幅太长了, ...

最新文章

  1. 积神经网络的参数优化方法——调整网络结构是关键!!!你只需不停增加层,直到测试误差不再减少....
  2. bzoj1564: [NOI2009]二叉查找树
  3. (十)Java B2B2C o2o多用户商城 springcloud架构- SSO单点登录之OAuth2.0登录认证(1)
  4. halcon select_shape_xld按区域大小描绘xld
  5. 计算机应用基础期中上机考试,期中考试计算机应用基础试卷
  6. c语言中二维数组中产生随机数,C语言中是如何进行随机数生成的[多图]
  7. linux sh expr冒号,linux expr命令参数及用法详解
  8. PHP课程第一次实验作业提交
  9. LAMP架构mariadb/apache的安装及基本使用
  10. 计算机网络实验四协议分析心得,计算机网络原理实验_使用网络协议分析仪Wireshark...
  11. App小程序开发外包的费用大约是多少?
  12. 类型多样的数码配件免抠元素素材,速来收藏
  13. 基于深度学习的物体识别系统
  14. 算法日志:python把终端的信息存为log和logging
  15. 为什么C语言要有头文件(补充)
  16. 吐槽一下Win10的输入法管理器
  17. 使用getsockopt函数判断TCP/IP异常
  18. GMT北京时间表示的时间算法
  19. 国外博士后申请心得,博后位置,CV,电话面试面经,签证等
  20. windows7 旗舰版下载地址

热门文章

  1. 开发成本谁更高:Android PK iOS
  2. 一杯水怎么测试_每滴都是“芯”鲜好水,碧然德新款净水器实测
  3. python中range语法
  4. Redis入门(三)Redis的基本数据类型
  5. vue自定义全局和局部指令
  6. bootstrap 辅助类
  7. 创建表空间、用户和赋权
  8. 北航校赛2014 预赛 题解
  9. Slackware Linux 14.0 RC5 发布
  10. 修改折半查找算法进行范围查找