#小编发现大多数教材都没有实现哈夫曼树,故突发奇想构建哈夫曼树#
哈夫曼树的实现方法
注:频率也称权值
构建哈夫曼树的过程可以分为以下几个步骤:
1. 创建叶子节点:根据给定的数据集,为每个值创建一个叶子节点,并将节点的频率设置为对应值在数据集中的出现频率(或概率)。
2. 构建优先队列:将所有的叶子节点放入一个优先队列(优先级队列),以节点的频率作为比较的依据。频率较低的节点具有较高的优先级。
3. 构建哈夫曼树:重复以下步骤,直到优先队列中只剩下一个节点:
- 从优先队列中选择频率最低的两个节点作为当前节点的左子节点和右子节点。
- 创建一个新节点作为它们的父节点,将新节点的频率设置为左右子节点频率之和。
- 将新节点插入到优先队列中。
4. 哈夫曼树构建完成:最终,优先队列中只剩下一个节点,即为哈夫曼树的根节点。
通过以上步骤,我们根据给定的数据集构建了哈夫曼树,其中频率较低的值对应的节点位于树的较高层级,频率较高的值对应的节点位于树的较低层级。这种树结构使得频率较高的值具有较短的编码,而频率较低的值具有较长的编码,从而实现了数据的有效压缩。 需要注意的是,构建哈夫曼树的过程中需要使用优先队列来选择频率最低的节点。这样可以保证每次选择的节点都是当前频率最低的节点,以确保构建出正确的哈夫曼树。
优先队列介绍和实现
优先队列介绍
优先队列(Priority Queue)是一种特殊的队列数据结构,它根据元素的优先级进行排序和访问。与普通队列不同,优先队列中的元素并不按照它们进入队列的顺序进行处理,而是根据各自的优先级进行排序。
优先队列的主要特点是:
- 每个元素都有一个关联的优先级,优先级高的元素排在队列的前面。
- 当访问或删除元素时,优先队列会返回具有最高(或最低)优先级的元素。
- 元素的插入操作会按照优先级的顺序进行调整,以确保队列的顺序是正确的。
优先队列实现
priority_queue<HuffmanNode*,vector<HuffmanNode*>, Compare> pq;
struct Compare { //比较权值方便构建哈夫曼树
bool operator()(HuffmanNode* a, HuffmanNode* b) {
return a->frequency > b->frequency;
}
};
- `<HuffmanNode*, std::vector<HuffmanNode*>, Compare>`: 这是 `priority_queue` 类型的具体化,指定了优先队列中元素的类型、底层容器类型以及比较器类型。
- `HuffmanNode*` 是优先队列中元素的类型,表示指向 `HuffmanNode` 对象的指针。
-`vector<HuffmanNode*>` 是底层容器类型,表示使用 `vector` 作为优先队列的底层容器来存储元素。
- `Compare` 是比较器类型,用于比较两个元素的优先级。在你的代码中,使用了自定义的 `Compare` 结构体来实现比较器。
如果还是不理解,可以把Compare看作是队列中元素的排列要求(即权值小的优先),HuffmanNode*是队列元素数据类型,借助vector<HuffmanNode*>来存储。
哈夫曼树的代码实现
typedef struct HuffmanNode{
int value; //节点数值
unsigned int frequency; //权值
struct HuffmanNode* lchild; //左孩子
struct HuffmanNode* rchild; //右孩子
HuffmanNode(int v, unsigned freq) //构造函数
: value(v), frequency(freq), lchild(nullptr), rchild(nullptr) {}
}HuffmanNode,*HuffmanTree;struct Compare { //比较权值方便构建哈夫曼树
bool operator()(HuffmanNode* a, HuffmanNode* b) {
return a->frequency > b->frequency;
}
};
#include "HuffmanTree.h"
void DestroyHuffmanTree(HuffmanNode* root) { // 递归销毁哈夫曼树
if (root == nullptr)
return;
DestroyHuffmanTree(root->lchild);
DestroyHuffmanTree(root->rchild);
delete root;
}// 构建哈夫曼树
HuffmanNode* BuildHuffmanTree(const vector<int>& values, const vector<unsigned>& frequencies) {
priority_queue<HuffmanNode*,vector<HuffmanNode*>, Compare> pq; // 建立优先队列将权值递增排序
for (size_t i = 0; i < values.size(); ++i) { // 创建叶子节点并加入优先队列
pq.push(new HuffmanNode(values[i], frequencies[i]));
}
while (pq.size() > 1) { // 构建哈夫曼树
HuffmanNode* left = pq.top(); // 选择频率最小的两个节点
pq.pop();
HuffmanNode* right = pq.top();
pq.pop();
HuffmanNode* parent = new HuffmanNode(-1, left->frequency + right->frequency); // 创建一个新节点作为它们的父节点
parent->lchild = left;
parent->rchild = right;
pq.push(parent); // 将新节点加入优先队列
}
return pq.top(); // 返回根节点
}
void PrintHuffmanCodes(HuffmanNode* root,string code) { // 打印哈夫曼树的编码
if (root == nullptr)
return;
if (root->lchild == nullptr && root->rchild == nullptr) { // 叶子节点表示一个值,打印该值和对应的编码
cout << root->value << ": " << code <<endl;
}// 递归打印左子树和右子树的编码
PrintHuffmanCodes(root->lchild, code + "0");
PrintHuffmanCodes(root->rchild, code + "1");
}