哈夫曼二叉树的简单构建

什么是哈夫曼二叉树?

哈夫曼树又叫做最优树。什么是最优?路径(权值)最短。

/*
 * 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的时间明显优于代码1.这里的人数可以看作为权值,也就是说权值最大的放置在最上面,权值最小的放在树的最小面。于是可以得出类似的数

 *          B
 *      +4      C
 *          +3      A
 *              +5      +0

构建哈夫曼二叉树

从最优算法中可以类似得到的:
1.权值:出现的次数
2.路径长度:当前节点到根节点的层数
3.加权路径:该结点到根节点之间的路径(长度)和权值的乘积
4.二叉树的路径长度:由根结点到所有叶子结点的路径长度之和

哈夫曼二叉树就是所有节点的加权路径之和最小的树。这就是最优树。

了解这些以后就可以开始构建哈夫曼二叉树了。
**第一步:统计字符串中各个字母出现次数,并且生成节点
第二步:根据节点的权值排序
第三步:取出权限最小的两个节点,构建一个新节点
第四步:重复2 3,直到只剩一个节点,该节点就是根节点。**
哈夫曼二叉树的简单构建_第1张图片

代码部分:
1.结点类
这部分就是给结点声明几个属性,再设置get和set方法为了方便操作。

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;
    }
}

哈夫曼二叉树类
需要注意的是,每进行一次新节点的生成之后,都要进行一次排序比较每个结点的权值,有的时候生成的结点会大于其他节点,如下图,但这是错误的!生成ab之后应该再比较c和d。
哈夫曼二叉树的简单构建_第2张图片
每次重新排序后
哈夫曼二叉树的简单构建_第3张图片

public class HalfmenTree {
    private Node root;
    private int[] num = new int[128];// 权值数组
    // 声明一个队列存字符的Ascll码对象
    ArrayList numlist = new ArrayList();
    // 声明一个队列存贮节点
    ArrayList list = new ArrayList();
    // 根据字母的权值排序从小到大(冒泡排序)
    public void sort(){
        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);
        }
        // 根据字母的权值排序从小到大(冒泡排序)
        sort();

        // 排序后输出节点的字母和权值
        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);
            sort();//排序
        }
        // 让根节点等于最后一个节点
        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();
    }
}

哈夫曼二叉树的简单构建_第4张图片

你可能感兴趣的:(数据结构和算法)