Java实现哈夫曼二叉树

1、统计学生学分
学生考试结果 A B C D
学分增加 5 4 3 0
人数 10 50 30 10

代码1:
if A : +5
else if B : +4
else if C : +3
else D :0
这份代码执行的效率为:10 + 50*2 +30*3 +10*3
代码2:
if B :+4
else if C:+3
else if A: +5
else D : 0
这份代码执行的效率为: 50 + 30 *2 +(10+10)*3
显然代码二比代码一的效率要高

在计算机数据处理中,霍夫曼编码使用变长编码表对源符号(如文件中的一个字母)进行编码,其中变长编码表是通过一种评估来源符号出现机率的方法得到的,出现机率高的字母使用较短的编码,反之出现机率低的则使用较长的编码,这便使编码之后的字符串的平均长度、期望值降低,从而达到无损压缩数据的目的。
2.哈夫曼二叉树
* 权值:出现次数
* 路径:当前节点到根节点的层数
* 加权路径:权值*路径
*
* 哈夫曼二叉树:所有节点加权路径和最小的二叉树
*
根据字符串构建哈夫曼二叉树
*
* 第一步:统计字符串中各个字母出现次数,并且生成节点
* 第二步:根据节点的权值排序
* 第三步:取出权限最小的两个节点,构建一个新节点
* 第四步:重复2 3,直到只剩一个节点,该节点就是根节点。
这里写图片描述

代码部分:
1.节点类

public class Node {
    private Object data;//数据
    private Node left;//左节点
    private Node right;//右节点
    private int weight;//权值
    public Node(){

    }
    public Node(Object data,int weight){
        super();
        this.data = data;
        this.weight = weight;
    }
    public int getWeight() {
        return weight;
    }
    public void setWeight(int weight) {
        this.weight = weight;
    }
    public Object getData() {
        return data;
    }
    public void setData(Object data) {
        this.data = data;
    }
    public Node getLeft() {
        return left;
    }
    public void setLeft(Node left) {
        this.left = left;
    }
    public Node getRight() {
        return right;
    }
    public void setRight(Node right) {
        this.right = right;
    }

}

2.哈夫曼二叉树类

public class HalfmenTree<E> {
    private Node root;
    private int[] num = new int[128];// 权值数组
    // 声明一个队列存字符的Ascll码对象
    ArrayList<Object> numlist = new ArrayList<Object>();
    // 声明一个队列存贮节点
    ArrayList<Node> list = new ArrayList<Node>();
    // 根据字母的权值排序从小到大(冒泡排序)
    public void paixu(){
        for (int i = 0; i < list.size(); i++) {
            for (int j = i + 1; j < list.size(); j++) {
                if (list.get(i).getWeight() > list.get(j).getWeight()) {
                    Node node = list.get(i);
                    list.set(i, list.get(j));
                    list.set(j, node);
                }
            }
        }
    }
    public void add(String str) {
        // 将str拆成单个字符,并根据其对应的Ascll码存放在num权值数组中
        for (int i = 0; i < str.length(); i++) {
            char ch = str.charAt(i);
            int n = (int) ch;
            num[n]++;
            if (num[n] == 1) {// 当每个字母第一次出现时,将这个字母的Ascll码存进numlist
                numlist.add(n);
            }
        }
        // 生成节点
        for (int i = 0; i < numlist.size(); i++) {
            int n = (int) numlist.get(i);
            int m = num[n];
            char ch = (char) n;
            Node node = new Node(ch, m);
            list.add(node);
        }
        // 根据字母的权值排序从小到大(冒泡排序)
        paixu();

        // 排序后输出节点的字母和权值
        for (int i = 0; i < list.size(); i++) {
            System.out.println(list.get(i).getData() + "  " + list.get(i).getWeight());
        }
        System.out.println("=======================");

        // 取出权值最小的两个节点,构建一个新节点
        while (list.size() > 1) {
            Node left = list.remove(0);
            Node right = list.remove(0);
            String st = left.getData().toString() + right.getData().toString();//st为左右子节点的字母并在一起
            Node father = new Node(st, left.getWeight() + right.getWeight());
            father.setLeft(left);
            father.setRight(right);
            list.add(0, father);
            paixu();//排序
        }
        // 让根节点等于最后一个节点
        root = list.get(0);
    }
    /**
     * 递归遍历
     */
    public void output() {
        output(root);
    }

    public void output(Node node) {
        //后序遍历 
        if (node.getLeft() != null) {
            output(node.getLeft());
            if (node.getRight() != null) {
                output(node.getRight());
            }
        }
        System.out.println(node.getData() + "   " + node.getWeight());

    }
}

3.测试类

public class Manage2 {

    public static void main(String[] args) {
        HalfmenTree ht = new HalfmenTree();
        ht.add("sadadsadaaqweqeadad");
        ht.output();
    }

}

运行结果为:
这里写图片描述

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值