请给出用C语言写出的哈夫曼树的建立的代码并对它进行注释以及原理分析
时间: 2024-05-05 20:21:19 浏览: 108
以下是用C语言实现哈夫曼树的代码及注释:
```c
#include <stdio.h>
#include <stdlib.h>
// 定义哈夫曼树结点类型
typedef struct Node {
int weight; // 权值
int parent; // 父结点下标
int left; // 左子结点下标
int right; // 右子结点下标
} Node, *HuffmanTree;
// 选择权值最小的两个结点
void select(HuffmanTree HT, int n, int *s1, int *s2) {
int i, min;
for (i = 1; i <= n; i++) {
if (HT[i].parent == 0) {
min = i;
break;
}
}
for (i = 1; i <= n; i++) {
if (HT[i].parent == 0 && HT[i].weight < HT[min].weight) {
min = i;
}
}
*s1 = min;
for (i = 1; i <= n; i++) {
if (HT[i].parent == 0 && i != *s1) {
min = i;
break;
}
}
for (i = 1; i <= n; i++) {
if (HT[i].parent == 0 && i != *s1 && HT[i].weight < HT[min].weight) {
min = i;
}
}
*s2 = min;
}
// 建立哈夫曼树
void createHuffmanTree(HuffmanTree *HT, int n) {
if (n <= 1) {
return;
}
int m = 2 * n - 1; // 哈夫曼树的结点数
*HT = (HuffmanTree) malloc((m + 1) * sizeof(Node)); // 分配空间
int i;
for (i = 1; i <= m; i++) { // 初始化
(*HT)[i].parent = 0;
(*HT)[i].left = 0;
(*HT)[i].right = 0;
}
for (i = 1; i <= n; i++) { // 输入权值
scanf("%d", &(*HT)[i].weight);
}
int s1, s2;
for (i = n + 1; i <= m; i++) { // 构造哈夫曼树
select(*HT, i - 1, &s1, &s2);
(*HT)[s1].parent = i;
(*HT)[s2].parent = i;
(*HT)[i].left = s1;
(*HT)[i].right = s2;
(*HT)[i].weight = (*HT)[s1].weight + (*HT)[s2].weight;
}
}
int main() {
HuffmanTree HT;
int n;
printf("请输入哈夫曼树的叶子结点数:");
scanf("%d", &n);
createHuffmanTree(&HT, n);
return 0;
}
```
哈夫曼树的原理分析:
哈夫曼树是一种带权路径长度最短的二叉树,它的构造基于贪心算法。先将每个权值看作一个结点,然后选择两个权值最小的结点,将它们作为左右子结点创建一个新的父结点,并将父结点的权值设为左右子结点权值之和。这个过程会不断重复,直到所有结点都被合并成一个根结点,即构造出了一棵哈夫曼树。
在构造哈夫曼树的过程中,每次需要选择权值最小的两个结点,这个过程称为选择。选择可以通过线性扫描所有未被合并的结点,找到其中权值最小的两个结点。时间复杂度为 O(n^2)。也可以使用最小堆来实现选择,时间复杂度为 O(nlogn)。选择结束后,需要创建一个新的父结点,并将它的左右子结点设为被选中的两个结点,然后计算新的父结点的权值。这个过程称为合并。合并可以通过一个新的结点来实现,它的权值为被选中的两个结点的权值之和。这个新的结点成为了它的两个子结点的父结点。合并后,需要将被选中的两个结点的 parent、left、right 分别指向新的父结点,然后再进行下一轮选择和合并,直到构造出一棵哈夫曼树。
阅读全文