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编码实现压缩解压缩