哈夫曼树的实现c++
时间: 2023-08-21 19:05:24 浏览: 129
哈夫曼树 哈夫曼树C++实现
### 回答1:
以下是哈夫曼树的c++实现,包括创建哈夫曼树和哈夫曼编码的实现:
```cpp
#include <iostream>
#include <queue>
#include <vector>
#include <unordered_map>
using namespace std;
// 定义哈夫曼树的节点结构体
struct Node {
char ch; // 字符
int freq; // 字符出现的频率
Node *left, *right; // 左右子节点
Node(char c, int f) : ch(c), freq(f), left(nullptr), right(nullptr) {}
};
// 定义大根堆的比较函数,用于priority_queue
struct cmp {
bool operator()(Node* a, Node* b) {
return a->freq < b->freq;
}
};
// 创建哈夫曼树
Node* huffman_tree(const string& s) {
unordered_map<char, int> freq; // 统计每个字符出现的频率
for (char c : s) {
freq[c]++;
}
priority_queue<Node*, vector<Node*>, cmp> pq; // 定义大根堆,用于构建哈夫曼树
for (auto& p : freq) {
pq.push(new Node(p.first, p.second));
}
while (pq.size() > 1) {
Node* left = pq.top(); pq.pop();
Node* right = pq.top(); pq.pop();
Node* parent = new Node('\0', left->freq + right->freq); // 创建新的父节点
parent->left = left;
parent->right = right;
pq.push(parent);
}
return pq.top();
}
// 递归获取哈夫曼编码
void get_code(Node* root, string code, unordered_map<char, string>& huffman_code) {
if (!root) return;
if (root->ch != '\0') {
huffman_code[root->ch] = code;
}
get_code(root->left, code + "0", huffman_code);
get_code(root->right, code + "1", huffman_code);
}
// 哈夫曼编码
unordered_map<char, string> huffman_encode(const string& s) {
Node* root = huffman_tree(s);
unordered_map<char, string> huffman_code;
get_code(root, "", huffman_code);
return huffman_code;
}
int main() {
string s = "hello world";
unordered_map<char, string> huffman_code = huffman_encode(s);
cout << "哈夫曼编码表:" << endl;
for (auto& p : huffman_code) {
cout << p.first << ": " << p.second << endl;
}
return 0;
}
```
上述代码中,首先使用 `unordered_map` 统计字符串中每个字符出现的频率,然后将每个字符和其频率封装成一个节点,加入大根堆中。接着依次弹出两个权值最小的节点,将它们作为左右子节点,创建一个新的父节点,将父节点再次加入大根堆中。重复上述步骤,直到堆中只剩下一个节点,这个节点即为哈夫曼树的根节点。
创建哈夫曼树后,使用递归的方式获取每个字符的哈夫曼编码。如果是左子节点,则在编码的末尾添加 0;如果是右子节点,则在编码的末尾添加 1。如果到达了叶子节点,则将该字符和它的哈夫曼编码加入哈夫曼编码表中。
最终输出哈夫曼编码表,其中键为字符,值为对应的哈夫曼编码。
### 回答2:
哈夫曼树是一种用于数据压缩和编码的树形数据结构,其特点是根据数据出现的频率构建出最优的编码方式。下面是哈夫曼树的一个简单实现示例。
首先,我们需要定义一个结构体来表示哈夫曼树的节点,包含节点的权重和指向左右子节点的指针。
```
struct HuffmanNode {
int weight;
struct HuffmanNode *left, *right;
};
```
接下来,我们需要定义几个辅助函数来构建哈夫曼树。
首先是一个比较函数,用于对节点按照权重进行排序。
```
int compare(const void *a, const void *b) {
struct HuffmanNode **pa = (struct HuffmanNode **)a;
struct HuffmanNode **pb = (struct HuffmanNode **)b;
return (*pa)->weight - (*pb)->weight;
}
```
然后是一个用于构建哈夫曼树的函数,传入待编码的字符及其对应的权重数组。
```
struct HuffmanNode *buildHuffmanTree(char *data, int *weights, int n) {
// 创建节点数组
struct HuffmanNode **nodes = (struct HuffmanNode **)malloc(sizeof(struct HuffmanNode *) * n);
for (int i = 0; i < n; i++) {
nodes[i] = (struct HuffmanNode *)malloc(sizeof(struct HuffmanNode));
nodes[i]->weight = weights[i];
nodes[i]->left = nodes[i]->right = NULL;
}
// 按照权重排序节点
qsort(nodes, n, sizeof(struct HuffmanNode *), compare);
// 通过循环构建哈夫曼树
while (n > 1) {
// 取出权重最小的两个节点作为新节点的左右子节点
struct HuffmanNode *left = nodes[0];
struct HuffmanNode *right = nodes[1];
// 创建新节点
struct HuffmanNode *newNode = (struct HuffmanNode *)malloc(sizeof(struct HuffmanNode));
newNode->weight = left->weight + right->weight;
newNode->left = left;
newNode->right = right;
// 更新节点数组
nodes[0] = newNode;
memmove(nodes + 1, nodes + 2, sizeof(struct HuffmanNode *) * (n - 2));
// 数组长度减少1
n--;
// 重新排序
qsort(nodes, n, sizeof(struct HuffmanNode *), compare);
}
// 返回树的根节点
return nodes[0];
}
```
最后,我们可以编写一个函数来测试上述代码,输入一组字符及其权重,输出构建的哈夫曼树的结果。
```
void test() {
char data[] = {'a', 'b', 'c', 'd', 'e'};
int weights[] = {5, 3, 2, 1, 1};
int n = sizeof(data) / sizeof(char);
struct HuffmanNode *root = buildHuffmanTree(data, weights, n);
// 输出树的结果
printTree(root);
}
```
这是一个简单的哈夫曼树的实现示例,实际应用中可能需要考虑更多的边界情况和优化,但以上代码可以用作初步理解哈夫曼树的实现原理。
### 回答3:
哈夫曼树是一种经典的数据结构,可以用来构建最优的哈夫曼编码。在C语言中,我们可以通过构造二叉树的方式来实现哈夫曼树。
首先,我们需要定义一个结构体来表示二叉树的节点,包含节点的权值和指向左右子节点的指针。
```c
typedef struct Node {
int weight; // 节点的权值
struct Node *left; // 左子节点指针
struct Node *right; // 右子节点指针
} Node;
```
接下来,我们可以定义一些用于操作哈夫曼树的函数。
1. 创建单个节点的函数 `createNode`:
```c
Node * createNode(int weight) {
Node *node = (Node *)malloc(sizeof(Node));
node->weight = weight;
node->left = NULL;
node->right = NULL;
return node;
}
```
2. 构造哈夫曼树的函数 `buildHuffmanTree`:
```c
Node * buildHuffmanTree(int weights[], int n) {
Node *nodes[2*n-1]; // 初始化一个足够大的节点数组
for (int i = 0; i < n; i++) {
nodes[i] = createNode(weights[i]); // 将权值数组中的每个值创建为独立节点
}
for (int i = n; i < 2*n-1; i++) {
// 每次选择两个最小权值的节点生成新的根节点,直到只剩下一个节点
int minIndex1 = -1, minIndex2 = -1; // 记录最小权值的两个节点下标
for (int j = 0; j < i; j++) {
if (nodes[j] != NULL && (minIndex1 == -1 || nodes[j]->weight < nodes[minIndex1]->weight)) {
minIndex2 = minIndex1;
minIndex1 = j;
} else if (nodes[j] != NULL && (minIndex2 == -1 || nodes[j]->weight < nodes[minIndex2]->weight)) {
minIndex2 = j;
}
}
// 生成新节点,以两个最小权值的节点为其左右子节点
nodes[i] = createNode(nodes[minIndex1]->weight + nodes[minIndex2]->weight);
nodes[i]->left = nodes[minIndex1];
nodes[i]->right = nodes[minIndex2];
// 将已选用的两个权值最小的节点置为NULL,表示已合并
nodes[minIndex1] = NULL;
nodes[minIndex2] = NULL;
}
return nodes[2*n-2]; // 返回根节点
}
```
通过这两个函数,我们就能够实现哈夫曼树的构建。构建好的哈夫曼树可以用于编码和解码等操作,它能够根据字符出现的频率构造最优编码,使得编码后的数据长度更短,节省存储空间和传输带宽。
阅读全文