Huffman树及其编码(STL array实现)
这篇随笔主要是Huffman编码,构建哈夫曼树有各种各样的实现方法,如优先队列,数组构成的树等,但本质都是堆。
这里我用数组来存储数据,以堆的思想来构建一个哈弗曼树,并存入vector中,进而实现哈夫曼编码
步骤: 1生成哈夫曼树 (取最小权值树和次小权值树生成新树,排列后重新取树,不断重复)
2编码 (遵循左零右一的原则)
3解码(是编码的逆向,本文还未实现,日后有机会补充)
data.txt 测试数据:
5 |
结果:
下面贴代码:
#include <iostream>
#include <fstream>
#include <algorithm>
#include <vector>
#include <array> using namespace std; #define ARR_SIZE 100 //缓冲区大小 typedef struct Tree
{
int freq;
char key = '\0';
Tree *left, *right;
Tree()
{
freq = ;
key = '\0';
left = NULL;
right = NULL;
}
} Tree, *pTree;
union key_or_point
{
char key;
pTree point;
};
enum infor_type
{
key_s,
point_s
};
class infor
{
public:
int freq;//权值
key_or_point kp;//记录键值或者 新生成的树的地址
infor_type type;// 联合体key_or_point的类型由infor_type标志
infor()
{
freq = ;
kp.key = NULL;
type = key_s;
}
}; array<infor, ARR_SIZE> arr;//用来读取要处理的数据
vector<pTree> trees; //所有生成的树都放在vector里面 int num; //要处理的数据个数 bool cmp(infor a, infor b)
{
return a.freq > b.freq;
} void Huffman()
{
//找出最小权值和次小权值
sort(&arr[], &arr[num], cmp);
int cal = num - ;
while (cal > )
{ pTree pta = new Tree();
vector<pTree>::iterator it; pTree ptl = new Tree();
ptl->freq = arr[cal].freq;
// pt all 的左子树
if (arr[cal].type == point_s)
{
pta->left = arr[cal].kp.point;//如果存放的是地址,那么该树已入vector
//无需重复操作
}
else
{
ptl->key = arr[cal].kp.key;
trees.push_back(ptl);
it = trees.end() - ;
pta->left = *it;
} pTree ptr = new Tree();
ptr->freq = arr[cal - ].freq;
// pt all 的右子树
if (arr[cal - ].type == point_s)
{
pta->right = arr[cal - ].kp.point; //如果存放的是地址,那么该树已入vector
//无需重复操作
}
else
{
ptr->key = arr[cal - ].kp.key;
trees.push_back(ptr);
it = trees.end() - ;
pta->right = *it;
} pta->freq = arr[cal].freq + arr[cal - ].freq;
trees.push_back(pta);//pt all 本树 it = trees.end() - ;
arr[cal - ].kp.point = *it;
arr[cal - ].type = point_s;//保存新生成树的地址 arr[cal - ].freq = arr[cal - ].freq + arr[cal ].freq;
//最小权值的树和次权值的树组成新树后,放回原数组
//新树的key_or_point此时类型变为point_s指针指向vector存放的位置 //第一次循环会有三棵树入vector,重新排列后,新树无需重复入vector
cal--;
sort(&arr[], &arr[cal + ], cmp); } } void traversTree(pTree pt, string st = "")
{
//中序遍历二叉树
//遵循左0右1的原则
if (pt->left == NULL && pt->right == NULL)
{
cout.flags(ios::left);
cout.width();
cout << st.c_str() << " ";
cout << pt->key << endl;
return;
}
if (pt->left != NULL)
{
st += '';
traversTree(pt->left, st);
st.pop_back();//从左边出来后要回退一个字符,避免进入右边时多出一个字符
} if (pt->right != NULL)
{
st += '';
traversTree(pt->right, st);
}
return ;
} void printCode()
{
vector<pTree>::iterator it;
it = trees.end() - ;
pTree pt = *it; //取出最顶端的树
cout << "print HuffmanCode:" << endl;
traversTree(pt);
}
int main()
{
ifstream filein("data.txt");
cin.rdbuf(filein.rdbuf());//重定向输入
cin >> num;//要处理的数据个数
for (int i = ; i < num; i++)
{
cin >> arr[i].freq;
}
for (int i = ; i < num; i++)
{
cin >> arr[i].kp.key;
}
Huffman();
printCode();
return ;
}
分析:
这是以上测试数据生成的树的情况。
只有叶子节点表示有效的符号,所以遍历树时返回条件是叶子节点(如果是叶子节点则返回)
总结:
1 编程时用的一些小技巧总结:
1.1 输出调试信息:可以采用如下方式
#ifdef DEBUG
cout调试信息....
#endif
1.2 联合体union需要取得类型时,可以加一个enum来记录和标志uninon的类型
2 编程方法反思:
可以看到源码中用到了两次sort,这是省事的做法了。
目前想到的改进的方法是用二分插入(数据已经排序)
对比起来,我觉得优先队列的方式更易懂且效率更高,但此文也算是一次小探索,值得记录下来
3 感想:
本人入园第一次随笔,如有不足或错误,还望指出。
以上
Huffman树及其编码(STL array实现)的更多相关文章
- Huffman树的编码译码
上个学期做的课程设计,关于Huffman树的编码译码. 要求: 输入Huffman树各个叶结点的字符和权值,建立Huffman树并执行编码操作 输入一行仅由01组成的电文字符串,根据建立的Huffma ...
- Huffman树与编码
带权路径最小的二叉树称为最优二叉树或Huffman(哈夫曼树). Huffman树的构造 将节点的权值存入数组中,由数组开始构造Huffman树.初始化指针数组,指针指向含有权值的孤立节点. b = ...
- Huffman树与编码的简单实现
好久没写代码了,这个是一个朋友问的要C实现,由于不会C,就用JAVA写了个简单的.注释掉的代码属性按照原来朋友发的题里带的参数,发现没什么用就给注释掉了. package other; import ...
- Huffman树进行编码和译码
//编码#include<iostream> #include<cstdio> #include<cstring> #include<cstdlib> ...
- Huffman树及其编解码
Huffman树--编解码 介绍: Huffman树可以根据输入的字符串中某个字符出现的次数来给某个字符设定一个权值,然后可以根据权值的大小给一个给定的字符串编码,或者对一串编码进行解码,可以用于 ...
- 构造数列Huffman树总耗费_蓝桥杯
快排! /** 问题描述 Huffman树在编码中有着广泛的应用.在这里,我们只关心Huffman树的构造过程. 给出一列数{pi}={p0, p1, …, pn-1},用这列数构造Huffman树的 ...
- Java蓝桥杯练习题——Huffman树
Huffman树在编码中有着广泛的应用.在这里,我们只关心Huffman树的构造过程. 给出一列数{pi}={p0, p1, -, pn-1},用这列数构造Huffman树的过程如下: 找到{pi}中 ...
- [数据结构与算法]哈夫曼(Huffman)树与哈夫曼编码
声明:原创作品,转载时请注明文章来自SAP师太技术博客( 博/客/园www.cnblogs.com):www.cnblogs.com/jiangzhengjun,并以超链接形式标明文章原始出处,否则将 ...
- huffman树即Huffma编码的实现
自己写的Huffman树生成与Huffman编码实现 (实现了核心功能 ,打出了每个字符的huffman编码 其他的懒得实现了,有兴趣的朋友可以自己在我的基础增加功能 ) /* 原创文章 转载请附上原 ...
随机推荐
- echarts细节的修改(2):矩形数图,柱状图,折线图,雷达图等
1.矩形数图的配置,是直接拿饼图的配置 然后将type换成treemap. 修改类型 option.series.type = 'treemap'; 关闭面包屑导航 option.series.bre ...
- MATLAB常用函数, 常见问题
MATLAB常用函数 1.常用取整函数 round(x):四舍五入函数 floor(x) : 向下取整, 即 floor(1.2)=1, floor(1.8) = 1 ceil(x) : 向上取整, ...
- Vue 2 难点汇总
数据侦听 Vue.$watch watch提供了观察和响应实例上数据变动的办法,当有一些数据需要跟随其他数据变化而变化时,如子组件某个数据依赖来自于父组件的prop计算.很直观的会想到计算这功能和 ...
- Java Integer类的缓存
首先看一段代码(使用JDK 5),如下: public class Hello { public static void main(String[] args) { int a = 1000, b = ...
- vector容器、
一. vector 向量容器1. 创建 vector 对象(1)不指定容器大小vector<int> V;(2)指定容器大小vector<int> V(10);(3) ...
- python模块之random模块
random模块 随机模块,用于处理随机问题. import random # 随机整数 print(random.randint(0, 9)) # 0到9之间随机一个整数 print(random. ...
- 用一篇文章了解ppi,dpr,物理像素,逻辑像素,以及二倍图
这篇文章能让你了解到什么是分辨率.dpr.dip.ppi (dpi相当于ppi,dpi用点表示物理像素密度,ppi是逻辑像素密度) 首先从最简单的ppi开始: 一部手机,有大有小,怎么知道手机的大小用 ...
- JS的防抖与节流学习笔记
防抖(debounce):当持续触发事件时,在一定的时间段内,只有最后一次触发的事件才会执行. 例: function debounce(fn, wait) { var timer = null; r ...
- C# 自动翻页 PPT 测试脚本
本文告诉大家一个可以使用的 C# 脚本,可以用来自动打开 PPT 文件,然后不断执行翻页.每次翻页都截图.翻页之后自动关闭 PPT 再次打开 最近发现给 Office 做的插件,会在一定翻页次数的时候 ...
- UTF-8、UTF-16、UTF-32编码的相互转换(不使用现成的函数)
最近在考虑写一个可以跨平台的通用字符串类,首先需要搞定的就是编码转换问题. vs默认保存代码文件,使用的是本地code(中文即GBK,日文即Shift-JIS),也可以使用带BOM的UTF-8.gcc ...