Huffman树又叫最优二叉树,它的特点是带权路径最短。
Huffman树的一个重要应用是Huffman编码,Huffman编码是长度最短的前缀编码。即给定要传送的字符的权值,根据权值求出Huffman编码,它一定是前缀编码(指任意字符的编码都不是另一个字符编码的前缀),并且在传送过程由字符组成的文字时,编码长度最小。
因此Huffman编码可以对文字进行加密解密还有压缩。加密的工作就是将文字转换为编码,解密工作是将编码转换为文字,如何转换本文不做详解(严蔚敏的《数据结构》书中有代码)。那么如何进行压缩?当字符转变为编码,如果数字编码用char数组存储,则size并未减少。因此我们考虑用位操作。
由于编码完成后,码的形式是0和1组成的串,因此按位存储比原来将节省空间,假设平均编码长度为5位(若平均编码长度超过8位则没有压缩效果了,毕竟char是一个字节,但不可能超过8位,因为根据Huffman编码性质编码长的出现频率低,编码短的出现频率高,后面结果也得到了验证),则64位8个字节可以存储12.8个字符,而char只能存储8个字符。因此文字得到了压缩。
整个程序执行过程如图所示:
其中最难的是writeFile,利用位操作将编码组合在一起并写入文件,这里我们定义一个Unit单元,它包含64位数据,每次编码塞满64位数据,则写入文件。
按照上面的思想,写成的代码如下:
// HuffmanCode.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#include <IOSTREAM>
#include <stdlib.h>
#include <cstdio>
#include <string.h>
#include <FSTREAM>
#include <iomanip>
#include <map>
#include <iterator>
using namespace std;
typedef unsigned __int64 Dcode;
//Aesop_Fables.txt graph.txt
char *readFileName = "graph.txt"; //读的文件名称
char *writeFileName = "graph_compress.dat"; //写的文件名称
typedef struct HCBinary
{
Dcode binaryCode; //哈弗曼编码的二进制表示方法
int length; //编码长度
}HCBinary;
typedef struct Unit
{
Dcode content;
int remain;
}Unit;
Unit tempUnit;
typedef struct
{
long long int weight;
int parent, lchild, rchild;
char ch;
}HTNode, *HuffmanTree;
map<char, long long int> frequencyMap;
map<char, HCBinary> codeMap;
void select(HuffmanTree &HT, int dest, int &s1, int &s2)//选择两个最小的元素,获得它们的位置
{
long long int min1 = 9999999999; //先让min1,min2为一个足够大的数
long long int min2 = 9999999999;
int tempS1 = 0;