华为OD笔试机试 - 生成哈夫曼树 (python 2024年C卷D卷)

华为OD机试(C卷+D卷)2024真题目录(Java & c++ & python)

题目描述

给定长度为 n 的无序的数字数组,每个数字代表二叉树的叶子节点的权值,数字数组的值均大于等于1。

请完成一个函数,根据输入的数字数组,生成哈夫曼树,并将哈夫曼树按照中序遍历输出。

为了保证输出的二叉树中序遍历结果统一,增加以下限制:

二叉树节点中,左节点权值小于右节点权值,根节点权值为左右节点权值之和。当左右节点权值相同时,左子树高度小于等于右子树高度。

注意:

所有用例保证有效,并能生成哈夫曼树。

提醒:

哈夫曼树又称为最优二叉树,是一种带权路径长度最短的二叉树。

所谓树的带权路径长度,就是树中所有的叶节点的权值乘上其到根节点的路径长度(若根节点为 0 层,叶节点到根节点的路径长度为叶节点的层数)

输入描述

例如:由叶子节点:5 15 40 30 10,生成的最优二叉树如下图所示,该树的最短带权路径长度为:40 * 1 + 30 * 2 + 15 * 3 + 5 * 4 + 10 * 4 = 205。
在这里插入图片描述

输出描述

输出一个哈夫曼的中序遍历数组,数值间以空格分隔

示例1

输入

5
5 15 40 30 10

输出

40 100 30 60 15 30 5 15 10

说明:根据输入,生成哈夫曼树,按照中序遍历返回。所有节点中,左节点权值小于等于右节点权值之和。当左右节点权值相同时,左子树高度小于右子树。结果如上图所示。

解题思路

构建哈夫曼树。

哈夫曼树定义:

给定N个权值作为N个叶子结点,构造一棵二叉树,若该树的带权路径长度达到最小,称这样的二叉树为最优二叉树,也称为哈夫曼树(Huffman Tree)。

构建方法:

  • 取出两个最小的权值
  • 放回两个最小权值的合并和
  • 直至剩一个元素

可以发现涉及最小值的存取,那么用优先队列来提速。

题目的特定限制:
二叉树节点中,左节点权值小于右节点权值,根节点权值为左右节点权值之和。当左右节点权值相同时,左子树高度小于等于右子树高度。

这是为了保证输出的二叉树中序遍历结果统一

参考代码

import heapq

class Node:
    def __init__(self, lc, rc, weight, height):
        self.lc = lc  # 左孩子节点
        self.rc = rc  # 右孩子节点
        self.weight = weight  # 当前节点的权重
        self.height = height  # 当前节点代表子树的高度

    def __lt__(self, other):
        # 优先级比较时,权重小的优先级更高,权重相同时,高度小的优先级更高
        if self.weight != other.weight:
            return self.weight < other.weight
        else:
            return self.height < other.height

# 输入获取
n = int(input())
weights = list(map(int, input().split()))

# 二叉树中序遍历
def inOrder(root, seq):
    if root.lc is not None:
        inOrder(root.lc, seq)
    seq.append(root.weight)
    if root.rc is not None:
        inOrder(root.rc, seq)

pq = []

# 创建n个哈夫曼树节点,并加入优先队列
for w in weights:
    heapq.heappush(pq, Node(None, None, w, 0))

# 初始n个节点经过多轮合并,只剩一个节点时,那么该节点就是哈夫曼树的根节点,因此当优先队列中只剩一个节点时即可停止合并
while len(pq) > 1:
    lc = heapq.heappop(pq)
    rc = heapq.heappop(pq)

    # 将lc和rc合并,合并后新节点fa的权重,是两个子节点权重之和,fa子树高度为最大高度+1
    fa_weight = lc.weight + rc.weight
    fa_height = max(lc.height, rc.height) + 1

    # 将合并后的新节点加入优先队列
    heapq.heappush(pq, Node(lc, rc, fa_weight, fa_height))

# 最后优先队列中必然只剩一个节点,即哈夫曼树的根节点,此时对此根节点(哈夫曼树)进行中序遍历
root = heapq.heappop(pq)
seq = []
inOrder(root, seq)

print(" ".join(map(str, seq)))

  • 5
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值