哈夫曼树的基本概念是什么?
时间: 2023-12-24 13:25:24 浏览: 29
哈夫曼树是一种带权路径长度最短的树,也称为最优二叉树。在哈夫曼树中,每个叶子节点都有一个权值,而非叶子节点的权值则是其左右子树权值之和。哈夫曼树的主要应用是创建哈夫曼编码,通过哈夫曼编码可以实现数据的高效压缩和解压缩。
下面是一个创建哈夫曼树的例子:
假设有以下字符及其出现频率:
| 字符 | 频率 |
|------|------|
| A | 5 |
| B | 1 |
| C | 2 |
| D | 4 |
首先将这些字符及其频率按照频率从小到大排序,得到:
| 字符 | 频率 |
|------|------|
| B | 1 |
| C | 2 |
| D | 4 |
| A | 5 |
然后将频率最小的两个字符(B和C)合并成一个节点,其权值为3,得到:
| 字符 | 频率 |
|------|------|
| BC | 3 |
| D | 4 |
| A | 5 |
再将频率最小的两个字符(BC和D)合并成一个节点,其权值为7,得到:
| 字符 | 频率 |
|------|------|
| BC | 3 |
| DA | 9 |
最后将频率最小的两个字符(BCDA)合并成一个节点,其权值为12,得到哈夫曼树:
```
12
/ \
3 9
/ \ / \
B C D A
```
相关问题
c语言哈夫曼树基本操作,请用代码展示
以下是C语言实现哈夫曼树的基本操作代码:
//定义哈夫曼树结点
typedef struct HuffmanNode {
int weight; //权值
int parent; //父结点下标
int leftChild; //左孩子下标
int rightChild; //右孩子下标
} HuffmanNode, *HuffmanTree;
//构建哈夫曼树
void createHuffmanTree(HuffmanTree *tree, int n, int *weight) {
if (n <= 1) return; //结点数小于等于1,无法构建哈夫曼树
int m = 2 * n - 1; //哈夫曼树总结点数
*tree = (HuffmanTree) malloc((m + 1) * sizeof(HuffmanNode)); //动态分配数组空间
HuffmanTree p = *tree;
for (int i = 1; i <= n; i++, p++, weight++) {
p->weight = *weight;
p->parent = 0;
p->leftChild = 0;
p->rightChild = 0;
}
for (int i = n + 1; i <= m; i++, p++) {
p->weight = 0;
p->parent = 0;
p->leftChild = 0;
p->rightChild = 0;
}
for (int i = n + 1; i <= m; i++) {
int s1 = 0, s2 = 0;
select(tree, i - 1, &s1, &s2); //选择权值最小的两个结点
(*tree)[s1].parent = i;
(*tree)[s2].parent = i;
(*tree)[i].leftChild = s1;
(*tree)[i].rightChild = s2;
(*tree)[i].weight = (*tree)[s1].weight + (*tree)[s2].weight; //合并结点
}
}
//选择权值最小的两个结点
void select(HuffmanTree tree, int n, int *s1, int *s2) {
int min1 = INT_MAX, min2 = INT_MAX;
for (int i = 1; i <= n; i++) {
if (tree[i].parent == 0) {
if (tree[i].weight < min1) {
min2 = min1;
*s2 = *s1;
min1 = tree[i].weight;
*s1 = i;
} else if (tree[i].weight < min2) {
min2 = tree[i].weight;
*s2 = i;
}
}
}
}
//销毁哈夫曼树
void destroyHuffmanTree(HuffmanTree *tree) {
free(*tree);
*tree = NULL;
}
//编码
void encode(HuffmanTree tree, int n, char *str, char *code) {
for (int i = 0; i < n; i++, str++, code++) {
int j = 1;
HuffmanTree p = tree + 1;
while (p->leftChild != 0 && p->rightChild != 0) {
if (*str == '0') {
p = tree + p->leftChild;
*code++ = '0';
} else {
p = tree + p->rightChild;
*code++ = '1';
}
j++;
}
*code = '\0';
}
}
//解码
void decode(HuffmanTree tree, int n, char *code, char *str) {
for (int i = 0; i < n; i++, code++, str++) {
HuffmanTree p = tree + 1;
while (p->leftChild != 0 && p->rightChild != 0) {
if (*code == '0') {
p = tree + p->leftChild;
} else {
p = tree + p->rightChild;
}
code++;
}
*str = (char) p->weight;
}
}
掌握哈夫曼树、哈夫曼编码的概念和基本理论,设计实现哈夫曼编码
哈夫曼树是一种小根堆,它的每个节点都有一个权值,哈夫曼树的根节点距离其它叶子节点最远,因此可以用于构建最优二进制编码。
构建哈夫曼编码的过程如下:
1. 统计字符的出现频率,并按照从小到大的顺序构建哈夫曼树。
2. 对于哈夫曼树中的每个叶子节点,将其对应的字符编码为0,向上遍历到根节点,左儿子对应的编码为0,右儿子对应的编码为1。
3. 遍历待编码的字符串,根据哈夫曼树的编码规则将每个字符编码成二进制数。
4. 将所有编码后的二进制数拼接起来即为哈夫曼编码。
下面是Python实现哈夫曼编码的示例代码:
```python
import heapq
from collections import defaultdict
def huffman_encoding(data):
freq = defaultdict(int)
for c in data:
freq[c] += 1
heap = [[wt, [sym, '']] for sym, wt in freq.items()]
heapq.heapify(heap)
while len(heap) > 1:
lo = heapq.heappop(heap)
hi = heapq.heappop(heap)
for pair in lo[1:]:
pair[1] = '0' + pair[1]
for pair in hi[1:]:
pair[1] = '1' + pair[1]
heapq.heappush(heap, [lo[0] + hi[0]] + lo[1:] + hi[1:])
huff_code = dict(heapq.heappop(heap)[1:])
encoded_data = ''.join([huff_code[c] for c in data])
return encoded_data, huff_code
def huffman_decoding(encoded_data, huff_code):
inv_huff_code = {v: k for k, v in huff_code.items()}
decoded_data = ''
i = 0
while i < len(encoded_data):
j = i + 1
while encoded_data[i:j] not in inv_huff_code:
j += 1
decoded_data += inv_huff_code[encoded_data[i:j]]
i = j
return decoded_data
if __name__ == '__main__':
data = 'hello world'
encoded_data, huff_code = huffman_encoding(data)
decoded_data = huffman_decoding(encoded_data, huff_code)
print(encoded_data) # 100011011001110110101001011010000
print(decoded_data) # hello world
```
在上面的代码中,我们首先使用`defaultdict`统计字符出现频率,并将其存储在堆中。然后我们使用循环从堆中弹出两个最小的元素,合并它们并将它们放回堆中的过程,直到堆中只有一个元素。在这个过程中,我们将左儿子赋值为0,右儿子赋值为1,并将哈夫曼编码存储在一个字典中。最后,我们将编码后的二进制数拼接起来并返回哈夫曼编码。
对于解码过程,我们只需要将哈夫曼编码反转并存储在另一个字典中,然后遍历编码后的二进制数并查找对应的字符即可。