哈夫曼树及其应用

目录

一、相关概念

二、构建哈夫曼树

三、哈夫曼树的存储结构和类型定义

3.1 存储结构  

3.2 类型定义 

四、哈夫曼树的算法实现

4.1 初始化哈夫曼树

4.2 选出权重最小的两个结点

4.3 构建哈夫曼树


一、相关概念

(1) 路径、路径长度和树的路径长度

路径:从一个结点到另一个结点的分支序列。

路径长度: 从一个结点到另一个结点所经过的分支数目。

树的路径长度:从根结点到每个结点的路径长度之和。

(2)结点的权和带权路径长度 

结点的权:给树的每个结点赋予的一个具有实际意义的实数。

带权路径长度:从根结点到某一结点的路径长度与该结点的权的乘积。

(3)树的带权路径长度

树的带权路径长度:从根结点到每个叶结点的带权路径长度之和。

Q:给定n个权值,求一棵具有n个终端结点的二叉树,使其带权路径长度最短?

A:哈夫曼给出了构造这种树的规律,将给定结点构成一棵带权路径长度最短的二叉树,即哈夫曼树。

二、构建哈夫曼树

哈夫曼树是由n个带权叶结点构成的所有二叉树中带权路径长度最短的二叉树。因为这种树最早由哈夫曼研究,所以称为哈夫曼树,又称最优二叉树。

构建哈夫曼树的步骤:

示例:

三、哈夫曼树的存储结构和类型定义

3.1 存储结构  

由离散数学知识可知,一棵有n个叶结点的哈夫曼树共有2n-1个结点。因此,可以用一个大小为2n-1的一维数组来存放哈夫曼树的各个结点。

对于有n个叶结点的哈夫曼树,其结点总数为2n-1个。为实现方便,将叶结点集中存储在前面的1-n个位置,而后面的n-1个位置中存储其余的非叶结点。 

3.2 类型定义 

#define MAXN 20
#define MAXM 2 * MAXN - 1

typedef struct {
    int weight;
    int parent;
    int LChild;
    int RChild;
} HTNode, HuffmanTree[MAXM+1]; /* 弃用0号单元 */

四、哈夫曼树的算法实现

4.1 初始化哈夫曼树

w[ ]:存储结点权重的数组。

n:叶结点的数量。

for (i = 1; i <= m; ++i) {
    /* 对叶结点填入已知权重,对非叶结点暂时全部填入0 */
    ht[i].weight = i <= n ? w[i] : 0;

    ht[i].parent = ht[i].LChild = ht[i].RChild = 0;
}

4.2 选出权重最小的两个结点

结点未被处理过的标志:双亲结点为0。

/* 选出权重最小的两个结点 */
void Select(HuffmanTree ht, int n, int *s1, int *s2) {
    *s1 = 1;
    for (int i = 1; i <= n; ++i)
        if (ht[i].parent == 0 && ht[i].weight < ht[*s1].weight)
            *s1 = i;

    *s2 = *s1 == 1 ? 2 : 1; /* 避免结点重复 */
    for (int i = 1; i <= n; ++i)
        if (ht[i].parent == 0 && ht[i].weight < ht[*s2].weight && i != *s1)
            *s2 = i;
}

4.3 构建哈夫曼树

void CreateHuffmanTree(HuffmanTree ht, int *w, int n) {
    int i, s1, s2;
    int m = 2 * n - 1;

    /* 初始化哈夫曼树 */
    for (i = 1; i <= m; ++i) {
        ht[i].weight = i <= n ? w[i] : 0;
        ht[i].parent = ht[i].LChild = ht[i].RChild = 0;
    }

    /* 处理所有非叶结点 */
    for (i = n + 1; i <= m; ++i) {
        /* 查找范围扩大:纳入已处理非叶结点 */
        Select(ht, i - 1, &s1, &s2);

        /* 选出的两个结点的双亲结点为i */
        ht[s1].parent = ht[s2].parent = i;

        ht[i].LChild = s1;
        ht[i].RChild = s2;
        ht[i].weight = ht[s1].weight + ht[s2].weight;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值