学习Huffman编码最大的收获是学会了STL中优先队列的使用以及在使用的时候要注意的问题:在使用自定义数据类型的时候,优先队列要重载自己的比较操作符。
关于Huffman树怎么讲解请看算法导论讲解,原理真的很简单,不过要写出完整的代码难点就在于优先队列的使用。不废话了啊,再次强调,想把原理弄清楚,请看算法导论,树上的讲解比网上什么垃圾讲解不知道清晰多少,一看就懂。-----------------终于可以上代码了。
//在优先级队列中存入指针类型的节点
#include<iostream>
#include<queue>
#include<string>
using namespace std;
class Comapre;
class Node
{
public:
friend Comapre;
int key;
char ch;
Node* left;
Node* right;
public:
Node(int num, char c) :key(num), ch(c), left(NULL), right(NULL){}
//
//bool lessthan(const Node* node) const
//{
// return key>node->key;
//}
};
class Comapre
{
public:
//因为优先级队列中传递的指针,所以不能直接在Node类里重载比较运算符
//大家去看看STL中优先级队列使用与heap之间的关系
bool operator()(Node*node1, Node*node2)
{
//bool flag = node1->lessthan(node2);
//return flag;
return node1->key < node1->key;
}
};
//使用优先级队列存储元素,优先级队列能保证队列最顶端的是按照键值key排列的最小的元素
Node* Huffman(priority_queue<Node*, vector<Node*>, Comapre> que)
{
//重复将最顶端的两个元素拿出合并之后再放入队列中
while (que.size()>1)
{
Node *node = new Node(0, 0);
node->left = que.top();
que.pop();
node->right = que.top();
que.pop();
node->key = node->left->key + node->right->key;
que.push(node);
}
return que.top();
}
//利用中序遍历的方法输出霍夫曼编码
//思路是每向左指一个节点s添加0,每向右指一个节点添加1,每迭代完一次要退出s最后一个元素
//用到了string的pop_back函数
void Inorder(Node* node, string s)
{
if (node == NULL)
{
return;
}
else
{
if (node->left != NULL)
{
s += '0';
}
Inorder(node->left, s);
if (node->left == NULL&&node->right == NULL)
{
cout << node->ch << "'s code is :";
for (auto i : s)
cout << i;
cout << endl;
}
s.pop_back();
if (node->right != NULL)
s += '1';
Inorder(node->right, s);
}
}
//将开辟的空间清空,不然会导致内存泄露
void Delete(Node*node)
{
if (node == NULL)
{
return;
}
Delete(node->left);
Delete(node->right);
delete node;
}
int main()
{
string s;
Node*n[6];
n[0] = new Node(5, 'f');
n[1] = new Node(9, 'e');
n[2] = new Node(16, 'd');
n[3] = new Node(12, 'c');
n[4] = new Node(13, 'b');
n[5] = new Node(45, 'a');
priority_queue<Node*, vector<Node*>, Comapre>qu;
int i;
for (i = 0; i<6; i++)
{
qu.push(n[i]);
}
Node* R = Huffman(qu);
Inorder(R, s);
Delete(R);
return 0;
}