算法练习七–哈夫曼编码C++实现
- 好久没写博客了,今天在九度上遇到了个哈夫曼编码的oj题目,实现了下,发现自己大一时视之如恶魔的哈夫曼树的构造如今也能轻易实现了,哇哈哈,特此记一笔
一、哈夫曼树介绍
在一般的数据结构的书中,树的那章后面,著者一般都会介绍一下哈夫曼(HUFFMAN)树和哈夫曼编码。哈夫曼编码是哈夫曼树的一个应用。哈夫曼编码应用广泛,如JPEG中就应用了哈夫曼编码。 首先介绍什么是哈夫曼树。哈夫曼树又称最优二叉树,是一种带权路径长度最短的二叉树。所谓树的带权路径长度,就是树中所有的叶结点的权值乘上其到根结点的 路径长度(若根结点为0层,叶结点到根结点的路径长度为叶结点的层数)。树的带权路径长度记为WPL(W1*L1+W2*L2+W3*L3+…+Wn*Ln),N个权值Wi(i=1,2,…n)构成一棵有N个叶结点的二叉树,相应的叶结点的路径长度为Li(i=1,2,…n)。可以证明哈夫曼树的WPL是最小的。
二、算法步骤
一、对给定的n个权值{W1,W2,W3,…,Wi,…,Wn}构成n棵二叉树的初始集合F= {T1,T2,T3,…,Ti,…,Tn},其中每棵二叉树Ti中只有一个权值为Wi的根结点,它的左右子树均为空。
二、在F中选取两棵根结点权值最小的树作为新构造的二叉树的左右子树,新二叉树的根结点的权值为其左右子树的根结点的权值之和。
三、从F中删除这两棵树,并把这棵新的二叉树同样以降序排列(因为在末尾进行删除和增加更加方便)加入到集合F中。
四、重复二和三两步,直到集合F中只有一棵二叉树为止。
PS:网上有很多对哈夫曼树手动构造生动形象的图文描述,这里不再赘述,重点说明算法的实现
三、talk is cheap show the code
#include<iostream>
#include <vector>
#include <algorithm>
using namespace std;
/**********************************************************
// Method:
// Description: http://ac.jobdu.com/problem.php?pid=1172
// Author:
// Date: 2016/03/18 19:47
// Returns:
// Parameter:
// History:
// G:\VisualStudio2013Projects\algorithmNew\algorithmNew\哈夫曼编码.h
**********************************************************/
class huffumanNode
{
public:
int weight;
huffumanNode *left;
huffumanNode *right;
//用来构造叶子节点
huffumanNode(int setWeight)
{
this->weight = setWeight;
this->left = NULL;
this->right = NULL;
}
//用来构造中间的节点
huffumanNode(int setWeight, huffumanNode *setLeft, huffumanNode *setRight)
{
this->weight = setWeight;
this->left = setLeft;
this->right = setRight;
}
//判断是否是叶子节点
bool isLeaf()
{
return this->left == NULL && this->right == NULL;
}
};
//降序排序比较函数,以wieght的大小降序排列
bool myHuffumanComepare(huffumanNode *node1, huffumanNode *node2)
{
return node1->weight > node2->weight;
}
/*得到带权路径长度。所谓树的带权路径长度,就是树中所有的叶结点
的权值乘上其到根结点的 路径长度(若根结点为0层,叶结点到根结点的路径长度
为叶结点的层数)*/
void getHuffmanSum(huffumanNode *root,int length,int &sum)
{
if (!root)
{
return;
}
if (root->isLeaf())
{
sum += root->weight*length;
}
length++;
getHuffmanSum(root->left, length, sum);
getHuffmanSum(root->right, length, sum);
}
//前序遍历打印,提交时不要调用这个哈,仅为调试
void prePrint(huffumanNode *root)
{
if (!root)
{
return;
}
cout << root->weight << " ";
prePrint(root->left);
prePrint(root->right);
}
int buildHuffuman()
{
int n;
while (cin >> n)
{
vector<huffumanNode*> weightArray;
while (n--)
{
int tempWeight;
cin >> tempWeight;
huffumanNode *newNode = new huffumanNode(tempWeight);
weightArray.push_back(newNode);
}
sort(weightArray.begin(), weightArray.end(), myHuffumanComepare);
while ((int)weightArray.size() > 1)
{
huffumanNode *minNode1 = weightArray[weightArray.size() - 1];
huffumanNode *minNode2 = weightArray[weightArray.size() - 2];
int fatherWeight = minNode1->weight + minNode2->weight;
/*根据最小的两个权重节点,构造新节点*/
huffumanNode *fatherNode = new huffumanNode(fatherWeight, minNode1, minNode2);
weightArray.pop_back();
weightArray.pop_back();
weightArray.push_back(fatherNode);
sort(weightArray.begin(), weightArray.end(), myHuffumanComepare);
}
prePrint(weightArray[0]);
cout << endl;
int length = 0;
int sum = 0;
getHuffmanSum(weightArray[0], length, sum);
cout << "weightSum: " << sum << endl;
}
return 0;
}
运行: