考研题分析总结-哈夫曼树

1,001 阅读7分钟

前言:最近在给我的小程序(数据结构算法演示)增加题库时,做了很多考研真题,所以在这里给大家总结下做题的思路和考点

题型1:哈夫曼树性质

  • 结点度数为0或者2
    • 一定是二叉树
    • n0=n2+1
    • n1=0
    • n=n0+n1+n2
    • n2有可能为0,即一个结点的特殊情况
  • 父结点权值等于两个子结点权值之和
    • 权值非负
    • 结点N的子树任意结点的权值都小于N的权值
  • 其他
    • 深度高的结点的权值一定不大于深度低的结点的权值:即N1(h1)和N2(h2),若h1>h2,那么N1<=N2(这个可通过反证法+构造哈夫曼树过程推断出)

(简单)考察结点数、度数相关

n个具有权值的叶子结点构造的霍夫曼树包含的结点总数是()
A. n-1
B. n+1
C. 2n-1
D. 2n+1

答案:C. 直接记住上面性质可得答案
2019408单选题
对n个互不相同的符号进行哈夫曼编码。若生成的哈夫曼树共有115个结点,则n的值是()
A. 56
B. 57
C. 58
D. 69

答案:C. 直接记住n0=n2+1,n1=0,这里n就是n0,可得答案
华东师范大学单选题
下列哪个数不可能是某棵哈夫曼树的结点个数?
A. 803
B. 308
C. 83
D. 以上选项都不对

答案:B n=n0+n2=2n2+1

关于结点数和度数的解题思路

  1. 需要把问题抽象成n0、n1、n2
  2. 直接套用性质即可:n0=n2+n1,n1=0

(简单)考察树形态的知识点

2010408单选题
对n(n≥2)个权值均不相同的字符构成哈夫曼树,关于该树的叙述中,错误的是()
A. 该树一定是一颗完全二叉树
B. 树中一定没有度为1的结点
C. 树中两个权值最小的结点一定是兄弟结点
D. 树中任一非叶结点的权值一定不小于下一层任一结点的权值

答案:A. A显然错误,BCD也可以通过上面总结的性质得到正确与否
下列有关霍夫曼树(huffman)的说法,其中正确的是()
A. 霍夫曼树一定是一颗完全二叉树
B. 霍夫曼树与二叉排序树是同义词
C. 霍夫曼树结点的度数只可能是0或者2
D. 霍夫曼树结点的度数有可能为012

答案:C. 显而易见

题型2:计算WPL

知识点参考这个juejin.cn/post/709831… 推荐选择方案3和方案2

(简单)给出哈夫曼树直接计算WPL

计算下图哈夫曼树的带权路径长度长度()
答案:37+52+16+21+22+30+10+12=200 已经给出了哈夫曼树,直接用方法二计算即可

graph4.png

(中等)给出叶结点权值直接计算WPL

2021408单选题
若某二叉树有5个叶子结点,其权值分别为1012162130。则其最小的带权路径长度(WPL)是()
A. 89
B. 200
C. 208
D. 209

答案:B. 使用方案2或者方案3即可计算WPL

(中等)给出编码的权重,计算编码平均长度

重庆大学单选题
Huffman编码树中所有结点(含叶结点)的权重分别为:
0.05,0.15,0.18,0.2,0.260.36,0.38,0.62,1.0。则该Huffman编码平均编码长度是()
A. 2.2
B. 2.8
C. 3.4
D. 3.6

答案:A. 因为每个叶结点哈夫曼编码的长度=路径长度,所以这里的平均编码长度就相当于WPL。
因此采用方法二或者方法三计算WPL即可

(困难)求WPL值的算法题

2014408算法题
二叉树的带权路径长度(WPL)是二叉树中所有叶结点的带权路径长度之和。给定一棵二叉树T,
采用二叉链表存储,结点结构为:(left,weight,right)。
其中叶结点的weight域保存该结点的非负权值。
设root为指向T的根结点的指针,请设计求T的WPL的算法

答案思路:遍历哈夫曼树(用自己最熟悉的遍历方法),计算所有非根结点的权值之和即可

下面我也给出方法1的计算WPL的代码,可以发现写起来很复杂,且必须要按层遍历来做

/**
 *
 * @param root
 * @param maxSize 队列最大值
 * @return 按层遍历计算WPL
 */
int getTreeWpl(struct TreeNode *root, int maxSize) {
    if (root == NULL) {
        return 0;
    }
    // 动态数组做队列
    struct TreeNode **queue = (struct TreeNode **) malloc(sizeof(struct TreeNode *) * maxSize);
    int rear = 0, front = 0;
    // 根结点入队
    queue[rear++] = root;
    // 当前层的size
    int currentSize = 1;
    // 下一层的size
    int nextSize = 0;
    int level = 0;
    struct TreeNode *temp;
    int wpl = 0;
    while (rear > front) {
        // 出队
        temp = queue[front++];
        currentSize--;
        if (temp->left == NULL && temp->right == NULL) {
            wpl += (temp->data * level);
        }
        if (temp->left) {
            queue[rear++] = temp->left;
            nextSize++;
        }
        if (temp->right) {
            queue[rear++] = temp->right;
            nextSize++;
        }
        if (currentSize == 0) {
            // 说明这一层已经遍历完
            currentSize = nextSize;
            nextSize = 0;
            level++;
        }
    }
    return wpl;
}
困难算法题:给定叶结点权值数组,求WPL值
方案1:用递归的方式计算WPL
方案2:先构造一个哈夫曼树,然后遍历哈夫曼树计算WPL(太麻烦、不推荐)

参考juejin.cn/post/709831…

题型3:哈夫曼树构造

  • 每次都选最小权值的两个结点向上合成一个新结点
    • 贪心
    • n个叶结点的哈夫曼树:要进行n-1次合并操作
  • 每次最小权值的两个结点只需要是兄弟就行,没有要求顺序
    • 哈夫曼树不唯一
    • n个叶结点的哈夫曼树:有2^(n-1)种形态的哈夫曼树

(简单)构造过程的概念题

只要记住怎么构造哈夫曼树、基本就没问题

构造霍夫曼树依据的基本思路是
A. 回溯算法
B. 贪心算法
C. 分治算法
D. 递归算法

答案:B
我自己编的题
以1,2,3对应叶结点的权值构造的哈夫曼树有多少种形态?

答案:一共4种:2^2=4

(简单)给叶结点权值,手画哈夫曼树

分别以 6,3,8,12,5,7 对应叶结点的权值构造的哈夫曼树的深度为()
A. 6
B. 5
C. 4
D. 3

答案:C 
这题有没有什么简单办法:是不是可以通过结点数推断深度呢?
很显然是不行,因为权值不一样树的形态不确定,所以直接画树即可

(困难)考察构造过程中关键点:每次都是选择最小的两个结点合成父结点

需要灵活应变,记住每次都选两个最小权值结点构造二叉树这条原则

2012408应用题
设有 6 个有序表 AB、C、D、E、F,分别含有1035405060200个数据元素,各表中元素按升序排列。
要求通过5次两两合并,将6个表最终合并成1个升序表,并在最坏情况下比较的总次数达到最小
1. 给出完整的合并过程,并求出最坏情况下比较的总次数。
2. 根据你的合并过程,描述 N(N≥2)个不等长升序表的合并策略,并说明理由。

答案:总比较次数为:44+84+109+194+394=825
这题看起来和哈夫曼树无关,但是简单思考下每次两两合并的最坏情况的次数是两个个数相加,
这就和哈夫曼树构造很类似,而且一个数越早参与到合并,对最后的总次数影响就越大;因此这就是哈夫曼树构造过程
2015408选择题
下列选项给出的是从根分别到达两个叶结点路径上的权值序列,能属于同一棵哈夫曼树的是()
A. 24,10,524,10,7
B. 24,10,524,12,7
C. 24,10,1024,14,11
D. 24,10,524,14,6

答案:D 排除法来做,记住每次都是最小的权值的连个结点合成新结点

第一眼看上去什么24,10,5这都是啥跟啥啊,看题意这是路径上结点的权值,所以需要手画以下才能明白,
比如A:第一个结点24肯定只能是根结点,
第二个结点是10,所以24的子结点只能是1014,所以10的子结点是57
5+7!=10,所以不对

题型4:哈夫曼编码

  • 哈夫曼编码是前缀码
    • 任何一个字符的编码都不能是其他字符编码的前缀
    • 解决二义性
  • 哈夫曼编码是平均长度最短的编码方式
    • 存储空间代价最小的编码方式
    • 定理:在变长编码中,如果码字长度严格按照对应符号出现的概率大小逆序排列,则其平均码字长度为最小
    • 叶结点编码长度=叶结点路径长度
  • 哈夫曼编码过程
    • 构造哈夫曼树
    • 左0右1

(简单)直接考察编码应用

2017408选择题
已知字符集{a,b,c,d,e,f,g,h},若各字符的哈夫曼编码依次是 
010010, 0000, 0101001, 011110001,
则编码序列 0101001001001011110101 的译码结果是()
A. a c g a b f h
B. a d b a g b b
C. a f b e a g d
D. a f e e f g d

答案:D 哈弗曼编码唯一性,所以直接匹配就行
2018408选择题
已知字符集{a,b,c,d,e,f,g,h},若个字符出现的次数分别为6382104,
则对应字符集中各字符的哈弗曼编码可能是()
A. 00101101101011100
B. 00100110000001001
C. 10101111001100010
D. 00111011001001000

答案:A. 
我们要把问题抽象下,既然是哈夫曼编码,肯定要代价小,也就是说次数越少长度越短,也就是次数等于权重,所以画出哈夫曼树我们便知道字符集的编码是哪些了
所以解题步骤还是:画哈夫曼树+编码

4047.png

(简单)考察前缀码

2014408单选题
5个字符有如下4种编码方案,不是前缀编码的是()
A. 01,0000,0001,001,1
B. 011,000,001,010,1,
C. 000,001,010,011,100
D. 0,100,110,1110,1100

答案:D 理解前缀码概念的送分题

(中等)哈夫曼编码和哈夫曼树性质、构造结合的应用

关于编码只需要记住左0右1、前缀码,加上其他哈夫曼知识万物皆可解决哈

南京航空航天大学单选题
根据使用频率为5个字符设计的哈夫曼编码不可能是()
A. 000,001,010,011,1
B. 0000,0001,001,01,1
C. 000,001,01,10,11
D. 00,100,101,110,111

答案:D  
1. 如果不是前缀码肯定不是哈夫曼
2. 左01画出对应哈夫曼树,判断是否满足哈夫曼树性质
D对应的哈夫曼树,有度数为1的结点,所以肯定不是哈夫曼编码
对于一个字符集中具有不同权值的字符进行Huffman编码时,
如果已知某个字符的Huffman编码为 0101,对于其他字符的Huffman编码;请分析说明
1. 具有哪些特征的编码是不可能的
2. 具有哪些特征的编码是一定会有的

答案:
1. 0,01,010和以0101为前缀的编码
2. 以1,00,011,0100为前缀的编码

这题比较巧妙,只给了一个字符的编码,所以还是按照左0右1的原则画哈夫曼树,同时根据哈夫曼树构造过程的要求补齐其他确定的结点,如下图,然后记住一点编码一定是叶结点就行

4161.png