哈夫曼树
哈夫曼树就是一棵带权二叉树、它的WPL是最小的、也就是从根节点到每一个节点的路径长度(经过的边数)与权值乘积的总和是最小的、就称为哈夫曼树。
哈夫曼编码
把各个字符在整个串中出现的频率作为它的权重、通过使用0、1表示来缩短整个串的长度、可用于无损压缩。
完成哈夫曼编码首先要先建立哈夫曼树、根据树中节点的路径、计算出对应节点的编码。
下面我写了一个类其中就包含了建立哈夫曼树和完成编码的过程:
#ifndef HUFFMAN_H
#define HUFFMAN_H
#include <string>
#include <vector>
#include <iostream>
using namespace std;
class CHuffman
{
private:
struct HuffNode
{
int parent;
int lchild;
int rchild;
int weight;
HuffNode(int w = 0,int l = -1,int r = -1,int p = -1):
parent(p),lchild(l),rchild(r),weight(w){}
};
struct HuffCode
{
char value;
string bits;
HuffCode():value(),bits(){}
};
vector<int> weights; //权值数组
int nodeNum; //真实有效的节点个数(还有需要的nodeNum - 1个节点)
HuffNode* hu; //节点数组
HuffCode* hc; //编码数组
bool releaseFlag; //资源释放标志
public:
CHuffman(vector<char>& vals,vector<int>& w):weights(w),hu(0),hc(0)
{//构造参数:字符数组、对应的权值
nodeNum = weights.size();
hc = new HuffCode[nodeNum];
hu = new HuffNode[2 * nodeNum - 1]; //需要另外nodeNum - 1个节点作为组合后的节点
for(int i = 0; i < vals.size(); i++)
{
hc[i].value = vals[i];
}
releaseFlag = false;
SetHuffNode();
SetHuffCode();
}
~CHuffman(){release();}
private:
void SetHuffNode();
void SetHuffCode();
void SelectPos(int n,int& p1,int& p2);
public:
vector<pair<char,string>> get();
bool release();
};
void CHuffman::SelectPos(int n,int& p1,int& p2)
{
int s1,s2;
s1 = s2 = INT_MAX;
p1 = p2 = 0;
for(int i = 0; i < n; i++)
{
if(hu[i].parent == -1 && hu[i].weight < s1)
{
s2 = s1;
p2 = p1;
s1 = hu[i].weight;
p1 = i;
}else if(hu[i].parent == -1 && hu[i].weight < s2)
{
s2 = hu[i].weight;
p2 = i;
}
}
}
void CHuffman::SetHuffNode()
{
for(int i = 0; i < 2 * nodeNum - 1; i++)
{
hu[i].parent = -1;
hu[i].lchild = -1;
hu[i].rchild = -1;
hu[i].weight = 0;
}
for(int i = 0; i < nodeNum; i++)
{
hu[i].weight = weights[i];
}
int p1,p2;
for(int i = nodeNum; i < 2 * nodeNum - 1; i++)
{
SelectPos(i,p1,p2); //选择两个权值最小的
hu[i].lchild = p1;
hu[i].rchild = p2;
hu[p1].parent = i;
hu[p2].parent = i;
hu[i].weight = hu[p1].weight + hu[p2].weight;
}
}
void CHuffman::SetHuffCode()
{
int pp = -1;
int pos = 0;
for(int i = 0; i < nodeNum; i++)
{
pp = hu[i].parent;
pos = i;
while(pp != -1)
{
if(hu[pp].lchild == pos)
hc[i].bits = '0' + hc[i].bits;
else if(hu[pp].rchild == pos)
hc[i].bits = '1' + hc[i].bits;
pos = pp;
pp = hu[pp].parent;
}
}
}
vector<pair<char,string>> CHuffman::get()
{
vector<pair<char,string>> strs(nodeNum);
for(int i = 0; i < nodeNum; i++)
{
strs[i].first = hc[i].value;
strs[i].second = hc[i].bits;
}
return strs;
}
bool CHuffman::release()
{
if(releaseFlag == false){
delete[] hu;
delete[] hc;
hu = NULL;
hc = NULL;
releaseFlag = true;
}
return true;
}
#endif