【Java】构建哈夫曼树和输出哈夫曼编码

2023-12-13 07:19:08

问题背景

一个单位有12个部门,每个部门都有一部电话,但是整个单位只有一根外线,当有电话打过来的时候,由转接员转到内线电话,已知各部门使用外线电话的频率为(次/天):5 20 10 12 8 43 5 6 9 15 19 32。

利用哈夫曼树算法思想设计内线电话号码,使得接线员拨号次数尽可能少。要求:

(1)依据使用外线电话的频率构造二叉树;

(2)输出设计出的各部门内线电话号码。

思路描述

  • 构建哈夫曼树:将所有节点按权重值从小到大排序,从中取出最小的两个节点node1、node2,然后创建一个新的节点,新节点的左右子节点分别是node1、node2(左节点node1的权重值一定要比右节点node2小),新节点的权重值是node1和node2权重值之和,然后将新节点代替node1和node2加入节点队列中,重复该过程,直到节点队列中只剩下一个节点。
  • 输入哈夫曼编码:在前面的构建好的二叉树中,左分支上标记0,右分支上标注1,从根节点到叶子节点所走过的路径就是该叶子节点的哈夫曼编码

?代码实现

/**
 * 用二叉链表存储二叉树
 */
public class HTNode implements Comparable<HTNode>{
    int weight;//权重
    HTNode left,right;//左右子节点

    public HTNode(int weight) {
        this.weight = weight;
    }

    @Override
    public int compareTo(HTNode o) {
        return this.weight-o.weight;//从小到大排序
    }
    @Override
    public String toString() {
        return super.toString();
    }
}
public class HuffmanTree {
    //构建哈夫曼树
    public static HTNode CreatHuffmanTree(int[] arr){
        //初始化
        if(arr.length<1)
            return null;
        List<HTNode> nodes=new ArrayList<>();
        for(int weight:arr){
            nodes.add(new HTNode(weight));
        }
        Collections.sort(nodes);//HTNodes实现了Comparable接口,基于weight排序
        while (nodes.size()>1){//nodes中只剩下一个时,该节点就是根节点
            //取权值最小的两个结点
            HTNode htNode1 = nodes.get(0);
            HTNode htNode2 = nodes.get(1);

            HTNode parent=new HTNode(htNode1.weight+htNode2.weight);
            parent.left=htNode1;
            parent.right=htNode2;
            nodes.remove(0);
            nodes.remove(0);
            nodes.add(parent);
            Collections.sort(nodes);
        }

        return nodes.get(0);
    }

    public static void creatHuffmanCode(HTNode root,String append,StringBuilder code){
        StringBuilder stringBuilder = new StringBuilder(code);
        stringBuilder.append(append);
        if(root.left==null&&root.right==null){
            System.out.println("权值为"+root.weight+"的节点的哈夫曼编码为"+stringBuilder);
            return;
        }
        creatHuffmanCode(root.left,"0",stringBuilder);
        creatHuffmanCode(root.right,"1",stringBuilder);
    }
    //写个前序遍历验证一下构建的哈夫曼树是否正确
    public static void preOrder(HTNode node){
        if(node==null)
            return;
        System.out.print(node.weight+" ");
        preOrder(node.left);
        preOrder(node.right);
    }
}

?运行结果

public class Main {
    public static void main(String[] args) {
        Scanner sc=new Scanner(System.in);
        System.out.println("请输入节点个数:");
        int n=sc.nextInt();
        int[] arr = new int[n];
        System.out.println("请输入"+n+"个节点的权值:");
        for(int i=0;i<n;i++){
            arr[i]=sc.nextInt();
        }
        HTNode htNode = HuffmanTree.CreatHuffmanTree(arr);
        System.out.println("前序遍历该哈夫曼树:");
        HuffmanTree.preOrder(htNode);
        System.out.println();
        HuffmanTree.creatHuffmanCode(htNode,"",new StringBuilder());
    }
}

?

?另外

  1. 为什么哈夫曼编码能够保证是前缀编码?? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 要编码的字符都在叶子结点上,根结点到每一个叶子结点的路径一定是不同的
  2. ?为什么哈夫曼编码能够保证字符编码总长最短?? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?哈夫曼树的带权路径长度是最小的,权重越大出现频率越高的字符越接近根结点

文章来源:https://blog.csdn.net/m0_73520938/article/details/134897799
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。