Huffman编码
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <string>
using namespace std; struct Node {
char character;
unsigned int weight;
unsigned int parent;
unsigned int lchild;
unsigned int rchild;
}; Node *HT = NULL;
char **HC = NULL;
int n = ; void CreatHuffmanTree(void);
void CodeHuffman(void);
void Encode(void);
void Decode(void);
void Free(void);
void Select(const int len, int &a, int &b);
int Search(const char &key); int main(void)
{
freopen("cin.txt", "r", stdin);
freopen("cout.txt", "w", stdout);
while (cout << "请输入字符个数:\n", cin >> n) { // n>=2
getchar(); // 吸收回车,防止空格字符的输入异常 CreatHuffmanTree(); // 建哈夫曼树 CodeHuffman(); // 为每个字符编码 Encode(); // 为明文编码 Decode(); // 从密文译码 Free(); // 释放动态分配的空间
}
system("pause");// 有用?
return ;
} void CreatHuffmanTree(void)
{
// weight存放n个字符的权值(均>0),构造哈夫曼树HT,
// 并求出n个字符的哈夫曼编码HC
if (n <= )
return;
int m = * n - ; HT = (Node *)malloc((m + ) * sizeof(Node)); // 0号单元未用
if( HT == NULL) {
cerr << "Allocate failed!" << endl;
exit(OVERFLOW);
}
memset(HT, , (m + ) * sizeof(Node)); cout << "请输入各字符及其权值:" << endl;
for (int i = ; i <= n; i++) {
HT[i].character = getchar();
cin >> HT[i].weight; // 输入字符及权值的信息
getchar();
}
cout << n << "个字符及其权值:" << endl;
for (int i = ; i <= n; i++) {
printf("%c(%3d) ", HT[i].character, HT[i].weight);
if (i % == )
cout << endl;
}
cout << endl; /* printf("\n哈夫曼树的构造过程如下所示:\n");
printf("HT初态:\n 结点 weight parent lchild rchild");
for (int i = 1; i <= m; i++)
printf("\n%4d%8d%8d%8d%8d", i, HT[i].weight, HT[i].parent, HT[i].lchild, HT[i].rchild);
printf(" 按回车键,继续 ...");
// getchar();*/ for (int i = n + ; i <= m; i++) {
// 在HT[1..i-1]中选择parent为0且weight最小的两个结点,
// 其序号分别为s1和s2。
int s1();
int s2();
Select(i - , s1, s2);
HT[s1].parent = i;
HT[s2].parent = i;
HT[i].lchild = s1;
HT[i].rchild = s2;
HT[i].weight = HT[s1].weight + HT[s2].weight; /* printf("\nselect: s1=%d s2=%d\n\n", s1, s2);
printf(" 结点 weight parent lchild rchild");
for (int j = 1; j <= i; j++)
printf("\n%4d%8d%8d%8d%8d", j, HT[j].weight, HT[j].parent, HT[j].lchild, HT[j].rchild);
printf(" 按回车键,继续 ...");
// getchar();*/
}
} void CodeHuffman(void)
{
//--- 从叶子到根逆向求每个字符的哈夫曼编码 ---
HC = (char **)malloc((n + ) * sizeof(char *)); // 指针数组
if (HC == NULL) {
cerr << "Allocate failed!" << endl;
exit(OVERFLOW);
}
memset(HC, , (n + ) * sizeof(char *)); // 0号单元未用 char *cd = (char *)malloc(n * sizeof(char)); // 分配求编码的工作空间
if (cd == NULL) {
cerr << "Allocate failed!" << endl;
exit(OVERFLOW);
}
memset(cd, , n * sizeof(char)); // 编码结束符。 for (int i = ; i <= n; ++i) { // 逐个字符求哈夫曼编码
int start = n - ; // 编码结束符位置
unsigned int c();
unsigned int f();
for (c = i, f = HT[i].parent; f != ; c = f, f = HT[f].parent) {
if (HT[f].lchild == c) // 从叶子到根逆向求编码
cd[--start] = '';
else
cd[--start] = '';
} HC[i] = (char *)malloc((n - start) * sizeof(char)); // 为第i个字符编码分配空间
if (HC[i] == NULL) {
cerr << "Allocate failed!" << endl;
exit(OVERFLOW);
} strcpy(HC[i], &cd[start]); // 从cd复制编码(串)到HC
}
free(cd);
cd = NULL; printf("\n\n各字符的哈夫曼编码如下:\n");
for(int i = ; i <= n; i++) {
printf("%c(%3d): %s\n" ,HT[i].character, HT[i].weight, HC[i]);
}
} void Encode(void)
{
cout << "请输入报文:" << endl;
string str;
getline(cin, str);
for (unsigned int i = ; i < str.size(); i++) {
int loc = Search(str[i]);
cout << HC[loc] << endl;
}
cout << endl;
} void Decode(void)
{
cout << "请输入密文:" << endl;
string str;
cin >> str;
for (unsigned int i = ; i < str.size();) {
int cursor = * n - ;
while (HT[cursor].lchild != && HT[cursor].rchild != ) { // 全非0
switch (str[i++]) { case '':
cursor = HT[cursor].lchild;
break; case '':
cursor = HT[cursor].rchild;
break; default:
cerr << "Input error!" << endl;
exit ();
}
}
if (!(HT[cursor].lchild == && HT[cursor].rchild == )) { // 此时应是全0
cerr << "Input error!" << endl;
exit ();
}
cout << HT[cursor].character << endl;
}
} void Free(void)
{
free(HT); // 释放动态分配的空间
HT = NULL;
for(int i = ; i <= n; i++) {
free(HC[i]);
HC[i] = NULL;
}
free(HC);
HC = NULL;
} void Select(const int len, int &a, int &b)
{
// 在HT[1..len]中选择parent为0且weight最小的两个结点,
// 其序号分别为a和b。
for (int i = ; i <= len; i++) {
if (HT[i].parent == ) {
a = i;
break;
}
}
for (int i = a + ; i <= len; i++) {
if (HT[i].parent == ) {
b = i;
break;
}
}
if (HT[a].weight > HT[b].weight) // 保持a的始终小于b的,有序
swap(a, b);
for (int i = max(a, b) + ; i <= len; i++) {
if (HT[i].parent == ) {
if (HT[i].weight > HT[b].weight)
continue;
else if (HT[i].weight < HT[a].weight) {
b = a;
a = i;
}
else
b = i;
}
}
if ( !(HT[a].parent == && HT[b].parent == ) ) {
cerr << "Error!" << endl;
exit();
}
} int Search(const char &key) // 找到key在HT中的下标,找不到则返回0
{
HT[].character = key; // 哨兵,顺序查找
int i;
for (i = n; HT[i].character != key; --i);
if (i == ) {
cerr << "Inexistence!" << endl;
exit();
}
return i;
} /*
cin.txt:
27
186
a 64
b 13
c 22
d 32
e 103
f 21
g 15
h 47
i 57
j 1
k 5
l 32
m 20
n 57
o 63
p 15
q 1
r 48
s 51
t 80
u 23
v 8
w 18
x 1
y 16
z 1
this program is my favorite
*/
输出:
请输入字符个数:
请输入各字符及其权值:
27个字符及其权值:
(186) a( 64) b( 13) c( 22) d( 32) e(103) f( 21) g( 15) h( 47) i( 57)
j( 1) k( 5) l( 32) m( 20) n( 57) o( 63) p( 15) q( 1) r( 48) s( 51)
t( 80) u( 23) v( 8) w( 18) x( 1) y( 16) z( 1)
各字符的哈夫曼编码如下:
(186): 111
a( 64): 1010
b( 13): 100000
c( 22): 00000
d( 32): 10110
e(103): 010
f( 21): 110011
g( 15): 100010
h( 47): 0001
i( 57): 0110
j( 1): 1100001000
k( 5): 11000011
l( 32): 10111
m( 20): 110010
n( 57): 0111
o( 63): 1001
p( 15): 100001
q( 1): 1100001010
r( 48): 0010
s( 51): 0011
t( 80): 1101
u( 23): 00001
v( 8): 1100000
w( 18): 110001
x( 1): 1100001011
y( 16): 100011
z( 1): 1100001001
请输入报文:
1101
0001
0110
0011
111
100001
0010
1001
100010
0010
1010
110010
111
0110
0011
111
110010
100011
111
110011
1010
1100000
1001
0010
0110
1101
010
请输入密文:
请按任意键继续. . .
请输入字符个数:
考研机试题
/**************************************
created: 2014/03/14
filename: 13_07_huffman.cpp
purpose: Huffman encode
**************************************/ #pragma warning(disable: 4786)
#include <iostream>
#include <queue>
#include <string>
#include <cmath>
#include <map>
#include <cassert>
using namespace std; struct Node {
double weight;
Node *left;
Node *right;
int num; // 记录输入时的次序,为了按输入顺序输出 Node(double w = 0.0, int n = -) : weight(w), left(NULL), right(NULL), num(n) {} bool is_leaf() const {
return NULL == left && NULL == right;
}
}; struct Cmp {
bool operator()(Node *a, Node *b) const {
return a->weight > b->weight;
}
}; /*
** 使两个结点成为兄弟,返回他们的父亲的地址
*/
Node * conjoin(Node *left, Node *right) {
Node *father = new Node(left->weight + right->weight); // 这里产生的结点都是分支结点
father->left = left;
father->right = right; return father;
} /*
** 根据优先队列建 Huffman 树
*/
Node * create_tree(priority_queue<Node *, vector<Node *>, Cmp> &Q) {
while ( != Q.size()) {
Node *left = Q.top();
Q.pop();
Node *right = Q.top();
Q.pop();
Q.push(conjoin(left, right));
}
Node *tree = Q.top();
Q.pop(); return tree;
} /*
** 前序遍历 Huffman 树得到叶子的编码存储在 code_map 中
*/
void get_code(Node const *const tree, const string str, map<int, string> &code_map) {
if (NULL == tree) {
return ;
}
if (tree->is_leaf()) {
code_map[tree->num] = str;
return ;
}
get_code(tree->left, str + "", code_map);
get_code(tree->right, str + "", code_map);
} /*
** 后序遍历释放树
*/
void free_tree(Node *&tree) {
if (NULL == tree) {
return ;
} free(tree->left);
free(tree->right);
delete tree;
tree = NULL;
} int main(int argc, char **argv) {
FILE *in_stream = freopen("7.in", "r", stdin);
if (NULL == in_stream) {
cerr << "Can not open file." << endl;
exit();
}
FILE *out_stream = freopen("7.out", "w", stdout); priority_queue<Node *, vector<Node *>, Cmp> Q;
double elem;
int n;
cin >> n;
int i;
for (i = ; i < n; ++i) {
cin >> elem;
Q.push(new Node(elem, i));
} Node *tree = create_tree(Q); // 根据输入数据建 Huffman 树
assert(Q.empty());
map<int, string> code_map;
get_code(tree, string(), code_map); // 根据 Huffman 树获取 Huffman 编码 for (i = ; i < n; ++i) {
cout << code_map[i] << endl;
} free_tree(tree); fclose(in_stream);
fclose(out_stream); return ;
} /* 7.in
4
0.3 0.1 0.4 0.2
*/
Huffman编码的更多相关文章
- [老文章搬家] 关于 Huffman 编码
按:去年接手一个项目,涉及到一个一个叫做Mxpeg的非主流视频编码格式,编解码器是厂商以源代码形式提供的,但是可能代码写的不算健壮,以至于我们tcp直连设备很正常,但是经过一个UDP数据分发服务器之后 ...
- 【数据压缩】Huffman编码
1. 压缩编码概述 数据压缩在日常生活极为常见,平常所用到jpg.mp3均采用数据压缩(采用Huffman编码)以减少占用空间.编码\(C\)是指从字符空间\(A\)到码字表\(X\)的映射.数据压缩 ...
- 优先队列求解Huffman编码 c++
优先队列小析 优先队列的模板: template <class T, class Container = vector<T>,class Compare = less< ...
- Huffman编码实现电文的转码与译码
//first thing:thanks to my teacher---chenrong Dalian Maritime university /* 构造Huffman Tree思路: ( ...
- huffman 编码
huffman压缩是一种压缩算法,其中经典的部分就是根据字符出现的频率建立huffman树,然后根据huffman树的构建结果标示每个字符.huffman编码也称为前缀编码,就是每个字符的表示形式不是 ...
- 基于二叉树和数组实现限制长度的最优Huffman编码
具体介绍详见上篇博客:基于二叉树和双向链表实现限制长度的最优Huffman编码 基于数组和基于链表的实现方式在效率上有明显区别: 编码256个符号,符号权重为1...256,限制长度为16,循环编码1 ...
- uvalive 2088 - Entropy(huffman编码)
题目连接:2088 - Entropy 题目大意:给出一个字符串, 包括A~Z和_, 现在要根据字符出现的频率为他们进行编码,要求编码后字节最小, 然后输出字符均为8字节表示时的总字节数, 以及最小的 ...
- Jcompress: 一款基于huffman编码和最小堆的压缩、解压缩小程序
前言 最近基于huffman编码和最小堆排序算法实现了一个压缩.解压缩的小程序.其源代码已经上传到github上面: Jcompress下载地址 .在本人的github上面有一个叫Utility的re ...
- DS二叉树--Huffman编码与解码
题目描述 1.问题描述 给定n个字符及其对应的权值,构造Huffman树,并进行huffman编码和译(解)码. 构造Huffman树时,要求左子树根的权值小于.等于右子树根的权值. 进行Huffma ...
随机推荐
- Java的常用对象①②
Java的常用对象① Java的常用对象有很多,这里只对lang包中常用的Object,Date(Calendar,DateFormat,Math),System,Runtime进行介绍.㈠Objec ...
- autoit小贴士
如何防止程序重复运行? #include <Misc.au3>_Singleton("test") 如何删除脚本程序自身? ;删除脚本程序自身 Run(@ComSpec ...
- JS-为金额添加千分位逗号分割符
前言:这个功能在前端页面中使用的还是比较多的,正好我们的项目中也有使用此功能,不过YY同学写的代码不像个方法的样子,一个入口中间又插了几道子,所 以,我写了下面这个方法,经过测 ...
- onethink入门笔记(一)
由于公司需求所以大概花了一个星期搞了一个一个基于onethink的数据管理平台demo不得不说onethink这个基于thinkphp3.2.3的框架还是很棒的 让我这个没基础过php的人也能在一星期 ...
- javaScript 相关笔记
1.js中对象复制 思路:将js对象先转成json字符串,然后再将json字符串转换为两个对象
- CentOS6上无法启动NFS服务
CentOS6上无法启动NFS服务 1.系统环境 物理机:Windows 7(32位)旗舰版 虚拟机:CentOS 6.5 2.问题描述 安装好nfs应用程序之后,打算启动nfs服务,却出现以下的报错 ...
- Electronic Payment App analysis
Electronic Payment App is getting more and more popular now. People don't have to bring credit cards ...
- 25. vm安装redhat步骤
详见:http://jingyan.baidu.com/article/49ad8bce532c525834d8fa19.html
- rt—移植笔记1
将rtt源码往stm32f407移植的时候,源码串口打印引脚设置有误,以下是源码引脚配置. 以下是原理图 可见配置有误.
- 高可用Hadoop平台-Flume NG实战图解篇
1.概述 今天补充一篇关于Flume的博客,前面在讲解高可用的Hadoop平台的时候遗漏了这篇,本篇博客为大家讲述以下内容: Flume NG简述 单点Flume NG搭建.运行 高可用Flume N ...