哈弗曼编码需要用到哈弗曼树。如果不知道可以随便看看这里------------>构建哈弗曼树
什么是哈夫曼编码?
哈夫曼编码是一种可变字长编码。根据给定信息中字符出现的频次动态生成最优编码。常用于数据压缩。
哈夫曼编码实现:
哈夫曼编码要用到哈弗曼树,在一棵哈弗曼树的基础上,将哈弗曼树每个节点的左分支当做0,右分支当做1。与二进制编码01相对应。
哈弗曼树中,节点对应哈夫曼编码应该为:
A :1100
B:1101
C:111
D:10
E:0
实现哈弗曼编码主要数据和函数:
1、哈弗曼树节点结构体:数据、编码、左子树、右子树、队列升序判断函数
//哈弗曼树节点和权重比较方法,优先队列会使用这个权重比较方法
typedef struct HuffmanNode
{
char data; //数据
string code; //编码
int weight; //权重
struct HuffmanNode *lChild; //左节点
struct HuffmanNode *rChild; //右节点
//重写()作为队列比较函数
bool operator()(struct HuffmanNode*nodeA, struct HuffmanNode *nodeB)
{
return nodeA->weight > nodeB->weight;
}
}HuffNode;
2、创建哈弗曼树
//构建哈夫曼树
HuffNode * createHuffmanTree(vector<char>data, vector<int> weight) //data:数据 weight:节点权重
{
//优先队列
priority_queue<HuffmanNode*, vector<HuffmanNode*>, HuffNode > huffQue;
//按照权重构造节点,并将节点插入队列中
for (size_t i = 0;i < weight.size();i++)
{
HuffNode *node = new HuffNode;
node->weight = weight[i];
node->lChild = NULL;
node->rChild = NULL;
node->code = "";
node->data = data[i];
huffNodes[i] = node; //用作哈弗曼编码遍历
huffQue.push(node);
}
//将权重最小和次小的节点弹出,将两个节点的权重相加,作为构造新节点的权重
//将这个新节点作为根节点,权重最小的节点作为左孩子,次小的作为右孩子。
//将新的根节点插入队列中
while (huffQue.size() > 1)
{
HuffNode *lChild = huffQue.top();
huffQue.pop();
HuffNode *rChild = huffQue.top();
huffQue.pop();
HuffmanNode *parent = new HuffmanNode;
parent->lChild = lChild;
parent->rChild = rChild;
parent->code = "";
parent->data = NULL;
parent->weight = lChild->weight + rChild->weight;
huffQue.push(parent);
}
//弹出队列中最后一个节点,作为哈弗曼树的根节点
HuffmanNode *root = huffQue.top();
huffQue.pop();
return root;
}
3、编码函数(递归,贼简单)
//填充二进制编码
void encodeToNode(HuffmanNode *root, string code)
{
if (NULL == root)
{
return;
}
root->code = code;
encodeToNode(root->lChild,root->code + "0"); //左节点编码为 0
encodeToNode(root->rChild,root->code + "1"); //右节点编码为 1
}
验证结果,直接看全部代码:
#include<iostream>
#include<vector>
#include<queue>
#include<functional>
#include<string>
using namespace std;
//哈弗曼树节点和权重比较方法,优先队列会使用这个权重比较方法
typedef struct HuffmanNode
{
char data; //数据
string code; //编码
int weight; //权重
struct HuffmanNode *lChild; //左节点
struct HuffmanNode *rChild; //右节点
//重写()作为队列比较函数
bool operator()(struct HuffmanNode*nodeA, struct HuffmanNode *nodeB)
{
return nodeA->weight > nodeB->weight;
}
}HuffNode;
HuffNode *huffNodes[5]; //遍历哈弗曼树编码的时候用起来方便
//构建哈夫曼树
HuffNode * createHuffmanTree(vector<char>data, vector<int> weight) //data:数据 weight:节点权重
{
//优先队列
priority_queue<HuffmanNode*, vector<HuffmanNode*>, HuffNode > huffQue;
//按照权重构造节点,并将节点插入队列中
for (size_t i = 0;i < weight.size();i++)
{
HuffNode *node = new HuffNode;
node->weight = weight[i];
node->lChild = NULL;
node->rChild = NULL;
node->code = "";
node->data = data[i];
huffNodes[i] = node; //用作哈弗曼编码遍历
huffQue.push(node);
}
//将权重最小和次小的节点弹出,将两个节点的权重相加,作为构造新节点的权重
//将这个新节点作为根节点,权重最小的节点作为左孩子,次小的作为右孩子。
//将新的根节点插入队列中
while (huffQue.size() > 1)
{
HuffNode *lChild = huffQue.top();
huffQue.pop();
HuffNode *rChild = huffQue.top();
huffQue.pop();
HuffmanNode *parent = new HuffmanNode;
parent->lChild = lChild;
parent->rChild = rChild;
parent->code = "";
parent->data = NULL;
parent->weight = lChild->weight + rChild->weight;
huffQue.push(parent);
}
//弹出队列中最后一个节点,作为哈弗曼树的根节点
HuffmanNode *root = huffQue.top();
huffQue.pop();
return root;
}
//填充二进制编码
void encodeToNode(HuffmanNode *root, string code)
{
if (NULL == root)
{
return;
}
root->code = code;
encodeToNode(root->lChild,root->code + "0"); //左节点编码为 0
encodeToNode(root->rChild,root->code + "1"); //右节点编码为 1
}
//先序遍历哈弗曼树
void preOrder(HuffmanNode *root)
{
if (NULL == root)
{
return;
}
cout << root->weight << " "; //输出哈弗曼树各节点对应权重,包括各个生成的父节点
preOrder(root->lChild);
preOrder(root->rChild);
}
//释放哈弗曼树
void freeHuffManTree(HuffNode* root)
{
if (NULL == root)
{
return;
}
freeHuffManTree(root->lChild);
freeHuffManTree(root->rChild);
free(root);
root = NULL;
}
//输出哈弗曼树叶子结点的编码
void printNodeCode()
{
for (size_t i = 0; i < sizeof(huffNodes)/sizeof(huffNodes[0]); i++)
{
cout << huffNodes[i]->data << "---权重: " << huffNodes[i]->weight << "\t编码: " << huffNodes[i]->code << endl;
}
}
int main()
{
vector<char> data = {'A','B','C','D','E'};
vector<int> weight = { 4,5,10,15,20 };
//构造哈夫曼树
HuffmanNode *root = createHuffmanTree(data,weight);
//前序遍历哈弗曼树
cout << "哈弗曼树的前序遍历结果为:" << endl;
preOrder(root);
cout << endl;
cout << "哈弗曼树叶子结点对应编码为:"<< endl;
encodeToNode(root, "");
printNodeCode();
cout << endl;
freeHuffManTree(root);
system("pause");
return 0;
}
运行结果:和上面哈弗曼树推导结果一致 。