哈夫曼树是一种带权路径最小的树,运用于压缩编码算法。
带权路径又称WPL,是所有非叶子节点的路径之和,路径=深度*权值
哈夫曼树的节点个数=2*带权节点个数-1
哈夫曼树的构造过程
在未组成哈夫曼树的节点中寻找权值最小和第二小的节点,作为左右孩子,构造一个新节点作为父节点,父节点的权值为左右孩子的权值之和
哈夫曼树的表示
哈夫曼树用顺序存储的数组表示。
存储结构如下
1 2 3 4 5 6 7 8 9 10 11 12 13
| typedef struct TreeNode { int weight; int parent; int lchild; int rchild; } TreeNode;
typedef struct HaffTree { struct TreeNode *node; int length; } HaffTree;
|
哈夫曼树的初始化操作
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| HaffTree *initTree(int *weight, int length) { HaffTree *T = (HaffTree *)malloc(sizeof(HaffTree)); T->node = (TreeNode *)malloc(sizeof(struct TreeNode) * (2 * length - 1));
T->length = length; for (int i = 0; i < length; i++) { T->node[i].weight = weight[i]; T->node[i].parent = -1; T->node[i].lchild = -1; T->node[i].rchild = -1; } return T; }
|
上面我们已经说明哈夫曼树的节点树为带权节点个数*2-1,所以代码中我们申请了个数为为2 * length-1的哈夫曼结点数组
构建哈夫曼树
寻找最小节点和第二小节点。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| int *findMinWeight(HaffTree *T) { int min = 10000; int secmin = 10000; int minidx = -1; int secidx = -1;
for (int i = 0; i < T->length; i++) { if (T->node[i].parent == -1) { if (T->node[i].weight < min) { secmin = min; secidx=minidx;
min = T->node[i].weight; minidx = i; } else if (T->node[i].weight < secmin) { secmin = T->node[i].weight; secidx = i; } } }
int *arr = (int *)malloc(sizeof(int) * 2); arr[0] = minidx; arr[1] = secidx; return arr; }
|
构建哈夫曼树的具体过程
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| void buildHaffTree(HaffTree *T) { int length = T->length * 2 -1;
for (int i = T->length; i < length; i++) { int *res = findMinWeight(T); int lchild = res[0], rchild = res[1]; T->node[i].weight = T->node[lchild].weight + T->node[rchild].weight; T->node[i].lchild = lchild; T->node[i].rchild = rchild; T->node[i].parent = -1;
T->node[lchild].parent = i; T->node[rchild].parent = i;
T->length++; }
}
|
完整代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133
| #include <stdio.h> #include <stdlib.h>
#define MAXNODE 1024; typedef struct TreeNode { int weight; int parent; int lchild; int rchild; } TreeNode;
typedef struct HaffTree { struct TreeNode *node; int length; } HaffTree;
HaffTree *initTree(int *weight, int length) { HaffTree *T = (HaffTree *)malloc(sizeof(HaffTree)); T->node = (TreeNode *)malloc(sizeof(struct TreeNode) * (2 * length - 1));
T->length = length; for (int i = 0; i < length; i++) { T->node[i].weight = weight[i]; T->node[i].parent = -1; T->node[i].lchild = -1; T->node[i].rchild = -1; } return T; }
int *findMinWeight(HaffTree *T) { int min = 10000; int secmin = 10000; int minidx = -1; int secidx = -1;
for (int i = 0; i < T->length; i++) { if (T->node[i].parent == -1) { if (T->node[i].weight < min) { secmin = min; secidx=minidx;
min = T->node[i].weight; minidx = i; } else if (T->node[i].weight < secmin) { secmin = T->node[i].weight; secidx = i; } } }
int *arr = (int *)malloc(sizeof(int) * 2); arr[0] = minidx; arr[1] = secidx; return arr; }
void buildHaffTree(HaffTree *T) { int length = T->length * 2 -1;
for (int i = T->length; i < length; i++) { int *res = findMinWeight(T); int lchild = res[0], rchild = res[1]; T->node[i].weight = T->node[lchild].weight + T->node[rchild].weight; T->node[i].lchild = lchild; T->node[i].rchild = rchild; T->node[i].parent = -1;
T->node[lchild].parent = i; T->node[rchild].parent = i;
T->length++; }
} void preOrder(HaffTree *T, int idx) { if (idx != -1){ printf("%d->", T->node[idx].weight); preOrder(T, T->node[idx].lchild); preOrder(T, T->node[idx].rchild); } }
int WPL(HaffTree *T){ int wpl=0; for(int i=0;i<T->length-1;i++){ if(T->node[i].lchild==-1&&T->node[i].rchild==-1){ int j=i; int depth=0; while(T->node[j].parent!=0){ j=T->node[j].parent; depth++; } wpl+=depth*T->node[i].weight; } } return wpl; } void secOrder(HaffTree *T, int idx) { if (idx <= -1) return; preOrder(T, T->node[idx].lchild); printf("%d->", T->node[idx].weight); preOrder(T, T->node[idx].rchild); } int main() { int weight[] = {5, 1, 3, 6, 11, 2, 4}; HaffTree *T = initTree(weight, 7); buildHaffTree(T); preOrder(T, T->length - 1); printf("wpl=%d\n",WPL(T)); return 0; }
|