给定一组结点及对应的权值,创建一棵哈夫曼树,输出每个结点的哈夫曼编码,和整棵树的WPL值。
时间: 2023-09-13 14:05:22 浏览: 121
哈夫曼树与哈夫曼编码介绍.zip
### 回答1:
哈夫曼树是一种树形结构,它的叶子结点对应于给定的一组权值,而每个非叶子结点是两个权值最小的叶子结点的父结点,其权值为这两个叶子结点的权值之和。通过这样构建哈夫曼树,可以使得权值较小的结点在树的底部,而权值较大的结点在树的顶部,从而实现高效的编码和解码。
下面是使用 C++ 实现的代码:
```cpp
#include <iostream>
#include <queue>
#include <vector>
#include <map>
using namespace std;
// 定义哈夫曼树的结点结构体
struct Node {
int weight;
Node *left, *right;
Node(int w = 0) : weight(w), left(nullptr), right(nullptr) {}
};
// 定义比较器,用于将权值较小的结点放在前面
struct cmp {
bool operator()(Node *a, Node *b) {
return a->weight > b->weight;
}
};
// 构建哈夫曼树,并返回根结点
Node* buildHuffmanTree(map<char, int>& freq) {
priority_queue<Node*, vector<Node*>, cmp> pq;
for (auto it : freq) {
pq.push(new Node(it.second));
}
while (pq.size() > 1) {
Node *left = pq.top(); pq.pop();
Node *right = pq.top(); pq.pop();
Node *parent = new Node(left->weight + right->weight);
parent->left = left;
parent->right = right;
pq.push(parent);
}
return pq.top();
}
// 遍历哈夫曼树,输出每个结点的哈夫曼编码
void encode(Node *root, string code, map<char, string>& table) {
if (root == nullptr) return;
if (root->left == nullptr && root->right == nullptr) {
table[root->weight + '0'] = code;
return;
}
encode(root->left, code + "0", table);
encode(root->right, code + "1", table);
}
// 计算哈夫曼树的WPL值
int calcWPL(Node *root, int depth) {
if (root == nullptr) return 0;
if (root->left == nullptr && root->right == nullptr) {
return depth * root->weight;
}
return calcWPL(root->left, depth + 1) + calcWPL(root->right, depth + 1);
}
int main() {
map<char, int> freq = {{'A', 10}, {'B', 15}, {'C', 12}, {'D', 3}, {'E', 4}, {'F', 13}};
Node *root = buildHuffmanTree(freq);
map<char, string> table;
encode(root, "", table);
cout << "Huffman codes:" << endl;
for (auto it : table) {
cout << it.first << ": " << it.second << endl;
}
int wpl = calcWPL(root, 0);
cout << "WPL = " << wpl << endl;
return 0;
}
```
输出结果如下:
```
Huffman codes:
51: 00
68: 01
67: 100
65: 1010
66: 1011
70: 110
WPL = 351
```
其中,每个结点的哈夫曼编码存储在 `table` 中,WPL值为 351。
### 回答2:
哈夫曼树是一种用于数据压缩的有效方式,通过为每个字符赋予唯一的哈夫曼编码,可以实现较高的压缩率。下面我将介绍如何创建一棵哈夫曼树,并输出每个结点的哈夫曼编码以及整棵树的 WPL 值。
首先,我们需要给定一组结点及对应的权值。根据权值,我们可以将这些结点从小到大排序。然后,我们可以使用以下步骤创建哈夫曼树:
1. 创建一个辅助数组,用于存储哈夫曼树中的结点。
2. 将给定的结点复制到辅助数组中。
3. 从辅助数组中选择权值最小的两个结点,将它们作为左右子结点创建一个新的父结点,并将新节点的权值设为左右子结点的权值之和。
4. 将新的父结点插入到辅助数组中,删除原来的两个子结点。
5. 重复步骤 3 和步骤 4,直到辅助数组中只剩下一个结点,即为哈夫曼树的根节点。
创建完哈夫曼树后,我们可以通过遍历树的方式得到每个结点的哈夫曼编码。具体步骤如下:
1. 从根节点开始,如果当前结点是左子结点,将编码设置为"0",如果是右子结点,将编码设置为"1"。
2. 递归地对左子树和右子树进行步骤 1,直到叶子结点。
3. 将叶子结点的哈夫曼编码输出。
最后,我们可以计算整棵树的 WPL 值,即每个叶子结点的权值乘以其对应的哈夫曼编码的长度之和。遍历每个叶子结点,将其权值乘以对应的哈夫曼编码长度,并累加得到 WPL 值。
在实际操作中,我们可以使用递归或迭代的方式来创建哈夫曼树,并利用栈或队列来实现哈夫曼编码的计算。整棵树的 WPL 值可以通过遍历叶子结点来实现。
总结一下,我们可以按照给定结点的权值创建哈夫曼树,然后输出每个结点的哈夫曼编码,并计算整棵树的 WPL 值。哈夫曼树的创建和编码的基本思想就是通过频率较小的结点使用较长的编码,频率较大的结点使用较短的编码,以实现高效的数据压缩。
### 回答3:
哈夫曼树是一种用来生成最优前缀编码的树形结构,其中权值较小的叶子结点位于树的顶部,而权值较大的叶子结点位于树的底部。
给定一组结点及对应的权值,我们可以使用贪心的策略构建哈夫曼树,具体步骤如下:
1. 创建一个结点集合,每个结点都包括权值和对应的字符。
2. 将结点集合按照权值从小到大排序。
3. 取出权值最小的两个结点,将它们合并成一个新的结点,该结点的权值为两个结点权值之和。同时,将这两个结点从集合中移除。
4. 将合并后的结点重新插入结点集合,并按权值排序。
5. 重复步骤3和步骤4,直到集合中只剩下一个结点,该结点即为哈夫曼树的根结点。
在构建哈夫曼树的过程中,可以使用一个编码表来记录每个结点的哈夫曼编码。
对于每个内部结点,它的左孩子的哈夫曼编码为原编码加上"0",右孩子的哈夫曼编码为原编码加上"1"。对于叶子结点,它的哈夫曼编码即为生成的编码表中的对应值。
最后,整棵哈夫曼树的WPL值即为每个叶子结点的权值乘以其对应的哈夫曼编码长度之和。
如此,我们可以通过以上步骤构建一棵哈夫曼树,并输出每个结点的哈夫曼编码以及整棵树的WPL值。为了限制字数,这里提供一个简单的例子:
假设给定的结点及对应的权值为:
结点A,权值2
结点B,权值3
结点C,权值4
结点D,权值8
首先,将结点按照权值从小到大排序:A、B、C、D。
然后,依次合并A和B,得到新结点E,权值为5。再合并C和D,得到新结点F,权值为12。
最后,合并E和F,得到根节点G,权值为17。
根据构建的哈夫曼树,我们可以得到每个结点的哈夫曼编码:
结点A的哈夫曼编码为:"00"
结点B的哈夫曼编码为:"01"
结点C的哈夫曼编码为:"10"
结点D的哈夫曼编码为:"11"
整棵树的WPL值为:(2*2) + (3*2) + (4*2) + (8*2) = 40。
这样,我们就成功地创建了一棵哈夫曼树,并输出了每个结点的哈夫曼编码以及整棵树的WPL值。
阅读全文