E-生成哈夫曼树(100p)

生成哈夫曼树

问题描述

LYA 是一名计算机专业的学生,最近她学习了哈夫曼编码。为了巩固知识,她决定写一个程序来生成哈夫曼树。

给定一个长度为 的正整数数组,每个数字代表二叉树叶子节点的权值。请你帮助 LYA 生成一棵哈夫曼树,并将其按中序遍历的顺序输出。

为了保证输出的哈夫曼树唯一,需要满足以下条件:

  1. 树中每个非叶子节点的权值等于其左右子节点权值之和。

  2. 对于权值相同的两个节点,左子树的高度应小于等于右子树的高度。

  3. 在满足上述条件的前提下,左子节点的权值应小于等于右子节点的权值。

输入格式

第一行包含一个正整数 ,表示叶子节点的个数。

第二行包含 个正整数,表示每个叶子节点的权值,数值之间用空格分隔。

输出格式

输出一行,包含若干个正整数,表示按中序遍历哈夫曼树得到的节点权值序列,数值之间用空格分隔。

样例输入

5
5 15 40 30 10

样例输出

40 100 30 60 15 30 5 15 10

数据范围

权值

题解

本题考查哈夫曼树的构建。哈夫曼树是一种带权最优二叉树,其特点是带权路径长度最短。

构建哈夫曼树的基本步骤如下:

  1. 将所有节点看成独立的树,并按照权值从小到大排序。

  2. 取出权值最小的两棵树,将它们作为一个新树的左右子树,新树的权值为两棵子树权值之和。

  3. 重复步骤 2,直到只剩下一棵树,即为所求的哈夫曼树。

在实现时,我们可以用优先队列来维护节点,每次取出权值最小的两个节点合并。为了保证输出的哈夫曼树唯一,在优先队列中比较两个节点时,先比较权值,权值相同再比较树高,树高也相同则比较左右子树的权值大小关系。

构建完哈夫曼树后,我们再进行一次中序遍历即可得到输出序列。

参考代码

  • Python
import heapq


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

    def __gt__(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 midOrder(root, seq):
    # 中序遍历,即先遍历二叉树的左子树,再遍历二叉树的根,最后遍历二叉树的右子树
    if root.lc is not None:
        midOrder(root.lc, seq)

    seq.append(root.weight)

    if root.rc is not None:
        midOrder(root.rc, seq)


# 算法入口
def getResult():
    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子树高度 = rc子树高度+1; PS:rc的高度>=lc的高度
        fa_weight = lc.weight + rc.weight
        fa_height = rc.height + 1

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

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

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


# 算法调用
print(getResult())
  • Java
import java.util.*;

class Node implements Comparable<Node> {
    Node lc; // 左孩子节点
    Node rc; // 右孩子节点
    long weight; // 当前节点的权重
    int height; // 当前节点代表子树的高度

    public Node(Node lc, Node rc, long weight, int height) {
        this.lc = lc;
        this.rc = rc;
        this.weight = weight;
        this.height = height;
    }

    @Override
    public int compareTo(Node other) {
        // 优先级比较时,权重小的优先级更高,权重相同时,高度小的优先级更高
        if (this.weight != other.weight) {
         

剩余60%内容,订阅专栏后可继续查看/也可单篇购买

算法刷题笔记 文章被收录于专栏

本专栏收集并整理了一些刷题笔记

全部评论

相关推荐

不愿透露姓名的神秘牛友
05-29 15:00
教授A:“你为什么要讲这么久,是要压缩我们对你的评议时间吗?你们别以为这样就能够让我们对你们少点意见。”&nbsp;“从你的发言和论文格式就能知道你的性格啊。”…….&nbsp;感觉被狠狠霸凌了。
码农索隆:“教授您好,首先我想回应您提出的两点疑问。” “关于我讲解时间较长的问题:这绝非为了压缩各位老师的评议时间。这份毕业设计是我过去几个月倾注了全部心血的作品,从构思、实验、调试到撰写,每一个环节都反复打磨。我深知时间宝贵,所以选择详细讲解,是希望能更完整、清晰地展示它的核心创新点、实现过程和验证结果,确保老师们能充分理解它的价值和我的努力。我完全理解并重视评审环节的意义,也做好了充分准备来听取各位老师的专业意见和批评。几个月的研究都坚持下来了,我怎么可能害怕老师们的点评呢?今天站在这里,正是抱着虚心学习、诚恳求教的态度而来。” “如果我的展示确实超时,影响了后续流程,烦请老师们随时示意,我会立刻调整。我非常期待并预留了充足的时间,希望能听到老师们宝贵的建议和深入的讨论。” “其次,关于您提到‘从发言和论文格式就能知道我的性格’。教授,我对此感到非常困惑和不安。学术研究和答辩的核心,难道不应该是作品本身的质量、逻辑的严谨性、数据的可靠性和结论的合理性吗?论文格式有明确的规范要求,我尽最大努力遵循了这些规范。如果格式上存在疏忽或不足,这属于技术性、规范性的问题,恳请老师们具体指出,我一定认真修改。但将格式问题或个人表达风格(如讲解时长)直接上升为对个人性格的评判,甚至以此作为质疑我学术态度和动机的依据,这让我感到非常不公平,也偏离了学术评议应有的客观和严谨原则。” “我尊重每一位评审老师的专业权威,也衷心希望能得到老师们对我的工作内容本身的专业指导和批评指正。任何基于研究本身的意见,无论多么尖锐,我都会认真聆听、反思并改进。但我恳请老师们,能将评议的焦点放在我的研究本身,而不是对我个人进行主观的推断或评价。谢谢各位老师。”
点赞 评论 收藏
分享
SadnessAlex:跟三十五岁原则一样,人太多给这些***惯坏了
点赞 评论 收藏
分享
评论
1
2
分享

创作者周榜

更多
牛客网
牛客企业服务