哈夫曼树

哈夫曼树

基本概念

路径:在一棵树中,从任意一个结点到达另一个结点的通路
路径长度:该路径所需经过的边的个数
带权路径长度:从根结点到达该节点的路径长度再乘以该结点权值的结果
带权路径长度和:树所有的叶子结点的带权路径长度和
哈夫曼树:给定n个带权值结点,以它们为叶子结点构造的一棵带权路径和最小的二叉树

哈夫曼树的求法

  1. 将所有结点放入集合 K。
  2. 若集合 K 中剩余结点大于 2 个,则取出其中权值最小的两个结点,构造他们同时为某个新节点的左右儿子,该新节点是他们共同的双亲结点,设定它的权值为其两个儿子结点的权值和。并将该父亲结点放入集合 K。重复步骤 2 或 3。
  3. 若集合 K 中仅剩余一个结点,该结点即为构造出的哈夫曼树数的根结点,所有构造得到的 ()

给定结点的哈夫曼树可能不唯一,所以关于哈夫曼树的机试题往往需要求解的是其最小带权路径长度和。如下例题:

题目描述:

哈夫曼树,第一行输入一个数 n,表示叶结点的个数。需要用这些叶结点生成哈夫曼树,根据哈夫曼树的概念,这些结点有权值,即 weight,题目需要输出所有结点的值与权值的乘积之和。

输入:

输入有多组数据。
每组第一行输入一个数 n,接着输入 n 个叶节点(叶节点权值不超过 100,2<=n<=1000)。

输出:

输出权值。
样例输入:
5
1 2 2 5 9
样例输出:
37

来源:

2010 年北京邮电大学计算机研究生机试真题

解题思路:

由于会存在反复从集合中取出两个最小数,并向集合中存入之前取出两数的和的操作,容易想到使用小根堆可以完成此操作,而且时间复杂度为 log2n .此功能可以使用java的优先队列PriorityQueue完成。

解题步骤

  1. 将所有节点的权值存入优先队列集合queue中
  2. 从集合queue集合中取出两个最小数,并求和得到sum(中间节点的权值)
  3. 将sum存入集合queue 中,并求ans += sum;(ans保存中间节点的权值和)
  4. 重复1,2,直至集合queue中为空。
  5. 输出ans,此时ans为最小带权路径长度和,即为题目所求。

代码示例

import java.util.Scanner;
import java.util.PriorityQueue;
import java.util.Queue;
public class Main{
    public static void main(String [] args){
        Scanner cin = new Scanner(System.in);
        while(cin.hasNext()){
            int N = cin.nextInt();
            Queue<Integer> queue = new PriorityQueue<Integer>(N);
            // 输入所有节点的权值
            for(int i = 0; i < N; i++){
                queue.add(cin.nextInt());
            }
            int ans = 0;        // 保存中间节点的权值之和
            // 集合queue中两个最小的值
            int min1 = 0;
            int min2 = 0;
            int sum = 0;        // 保存min1和min2的和
            while(queue.size() >= 2){
                min1 = queue.poll();
                min2 = queue.poll();
                sum = min1 + min2;
                queue.add(sum);
                ans += sum;
            }
            System.out.println(ans);
        }

    }
}

附:Java PriorityQueue类的常用方法

方法类型描述
public PriorityQueue(int initialCapacity)构造指定容量初始化优先级队列
public boolean add(E e)普通向优先队列中插入指定元素
public void clear()普通清空优先队列
public E peek()普通取出对头元素,但是不删除
public E poll()普通对头元素出栈
public int size()普通取得优先级队列中元素的个数
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值