根据给定的 n个结点的权值建立一棵哈夫曼树,并构造哈夫曼编码。首先建立哈夫曼树。根据哈夫曼树的构造过程,要构造一棵有n个叶子结点的哈夫曼树由二叉树性质可知,度为2的结点有n一1个,整个哈夫曼树共有2n一1个结点,故可用大小为 2n-1的向量 ht来存储,其中向量 ht的前n个分量表示叶子结点。树中每个结点包含个域:结点的值域、权值域、双亲域和左、右孩子域,其中双亲域和左、右孩子域用于存龙结点在向量中的下标。由于在构造哈夫曼树时,必须在森林的所有结点中先选取两个权值小的根结点合并为一棵二叉树,因此,先要判断选取的结点是否为根结点。通过判断结点的双亲域是否为0,可以区分该结点是否为根结点。该算法的基本思想如下:
① 将哈夫曼树向量 ht 中的 2n-1 个结点进行初始化。
② 将n个结点的权值存入向量 ht 的前n个分量中。③ 对n个结点进行 n-1次合并,将生成的 n-1个新结点依次存入向量 ht 的第t(n+1≤t≤2n-1)个分量中,每次合并的方法是:在哈夫曼树向量ht中的前t-1个结点中选取具有最小权值和次小权值的两个根结点,将这两个结点的下标分别存入1eft和right 中;将根为 ht[left]和 ht[right]的两个棵树合并,使其成为新结点 ht[i]的左、右孩子,得到一棵以新结点 ht[i]为根的二叉树;同时修改 ht[left]和 ht[right]的双亲域,使其指向新结点 ht[i],将 ht[left]和 ht[right]的权值相加后作为新结点 ht[i]的权值。
构造哈夫曼编码的方法是:对于每个叶子结点,反复查找该结点的双亲结点,每进行一步都要判断该结点是双亲结点的左孩子(记为“0”)还是右孩子(记为“1”),从而得到这一步的编码,直至双亲为根结点,编码结束。将这些编码逆序输出,即为该叶子结点对应的哈夫曼编码。
代码如下
#include <stdio.h>
#define MAX 50 // 定义最大节点数
// 定义哈夫曼树节点结构
typedef struct {
char data; // 节点数据
int weight; // 节点权值
int parent; // 父节点索引
int lch; // 左孩子索引
int rch; // 右孩子索引
} HuffNode;
// 定义哈夫曼编码结构
typedef struct {
char bit[MAX]; // 编码字符串
int start; // 编码起始