哈夫曼树的实现

1、基本概念

哈夫曼树又称最优树(二叉树),是一类带权值路径最短的树。构造这种树的算法是最早由哈夫曼(Huffman)于1952年提出的,这种树在信息检索中很有用。

①节点之间的路径长度:从一个节点到另一个节点之间的分支数目;

②树的路径长度:从树的根节点中每一个节点的路径长度之和。

2、哈夫曼树编码规则:

从哈夫曼树根节点开始,对左子树分配代码“0”,右子树分配代码“1”,一直到达叶节点为止,然后将树根每条路径到达叶子节点的代码排列起来,便得到了哈夫曼编码。

例:对于字符串EMCAD编码。若采用等长编码,则:

E        M      C       A       D

000   001   010   011   100

EMCAD=>000001010011100,一共十五位

设各字母出现的频率为{E,M,C,A,D} = {1,2,3,3,4}.以频率为权值生成哈夫曼树,并在叶子上标注对应的字母,树枝分配代码“0”或者“1”:

由此哈夫曼编码树获得每个字母编码:

  E        M       C      A       D

000     001     01    10     11

这样大大地减少了编码的位数

3、哈夫曼树的完整代码实现:

首先定义节点:

public class Node {
    public Node left;//左子节点
    public Node right;//右子节点
    String str;//字符
    String code;//哈夫曼编码
    int weight;//权值
}

然后根据权值建树,返回根节点,我们将其写在createHFM这个函数中:

public Node createHFM(String[] strs, int[] weights) {
        Node[] nodes = new Node[strs.length];
        for (int i = 0; i < nodes.length; i++) {
            nodes[i] = new Node();
            nodes[i].weight = weights[i];
            nodes[i].str = strs[i];
        }
        while (nodes.length > 1) {
            sort(nodes);
            Node n1 = nodes[0];
            Node n2 = nodes[1];
            Node node = new Node();
            node.left = n1;
            node.right = n2;
            node.weight = n1.weight + n2.weight;
            Node[] nodes2 = new Node[nodes.length - 1];
            for (int i = 2; i < nodes.length; i++) {
                nodes2[i - 2] = nodes[i];
            }
            nodes2[nodes2.length - 1] = node;
            nodes = nodes2;
        }
        return nodes[0];
    }

​

①先将字符数组和其对应的权值转换为Node数组;(2-7行)

②在while循环中建树,直到只剩下一个节点;(8行)

③先将节点以权值递增的顺序排序;(9行)

④建立一个新节点,将第一个节点(权值最小的节点)设为该节点的左子节点,将第二个节点(权值第二小的节点)设为该节点的右子节点,该节点的权值等于两个节点的权值之和;(10-15行)

⑤将两个权值最小的节点删除,把新生成的节点加入数组中,重复上述步骤,直到队列中只剩下一个节点。(16-21行)

排序算法:这里我使用了冒泡排序:

​public void sort(Node[] nodes) {
        for (int i = 0; i < nodes.length; i++) {
            for (int j = i + 1; j < nodes.length; j++) {
                if (nodes[j].weight < nodes[i].weight) {
                    Node n = new Node();
                    n = nodes[j];
                    nodes[j] = nodes[i];
                    nodes[i] = n;
                }
            }
        }
    }

print函数打印哈夫曼树编码:

public void print(Node node, String code) {
        //递归的方法
        if (node == null) {
            return;
        }
        else{
            if (node.left == null && node.right == null) {//该节点是叶子节点
                String msg = node.str + "权值:" + node.weight + " HFM编码:" + code;
                System.out.println(msg);//打印相关信息
            }
            print(node.left, code + "0");//左子节点的编码后加0
            print(node.right, code + "1");//右子节点的编码后加1
        }
    }

测试代码运行结果:

public static void main(String[] args) {
        try {
            //String = "fasdfasfqkejhkqwnfs,zjalfuoiurjq,a..fasdfa.123efafzcvs";
            HFM hfm = new HFM();
            String[] strs = new String[]{"A", "B", "C", "D", "E", "F"};
            int[] weights = new int[]{4, 6, 1, 9, 8, 2};
            Node root = hfm.createHFM(strs, weights);
            hfm.print(root, "");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

完整代码:

Node类:

package p1;

public class Node {
    public Node left;//左子节点
    public Node right;//右子节点
    String str;//字符
    String code;//哈夫曼编码
    int weight;//权值
}

HFM类:

package p1;

import javax.swing.*;
import javax.xml.crypto.NodeSetData;

public class HFM {
    public Node createHFM(String[] strs, int[] weights) {
        Node[] nodes = new Node[strs.length];
        for (int i = 0; i < nodes.length; i++) {
            nodes[i] = new Node();
            nodes[i].weight = weights[i];
            nodes[i].str = strs[i];
        }
        while (nodes.length > 1) {
            sort(nodes);
            Node n1 = nodes[0];
            Node n2 = nodes[1];
            Node node = new Node();
            node.left = n1;
            node.right = n2;
            node.weight = n1.weight + n2.weight;
            Node[] nodes2 = new Node[nodes.length - 1];
            for (int i = 2; i < nodes.length; i++) {
                nodes2[i - 2] = nodes[i];
            }
            nodes2[nodes2.length - 1] = node;
            nodes = nodes2;
        }
        return nodes[0];
    }

    public void sort(Node[] nodes) {
        for (int i = 0; i < nodes.length; i++) {
            for (int j = i + 1; j < nodes.length; j++) {
                if (nodes[j].weight < nodes[i].weight) {
                    Node n = new Node();
                    n = nodes[j];
                    nodes[j] = nodes[i];
                    nodes[i] = n;
                }
            }
        }
    }

    public void print(Node node, String code) {
        //递归的方法
        if (node == null) {
            return;
        }
        else{
            if (node.left == null && node.right == null) {//该节点是叶子节点
                String msg = node.str + "权值:" + node.weight + " HFM编码:" + code;
                System.out.println(msg);//打印相关信息
            }
            print(node.left, code + "0");//左子节点的编码后加0
            print(node.right, code + "1");//右子节点的编码后加1
        }
    }

    public static void main(String[] args) {
        try {
            //String = "fasdfasfqkejhkqwnfs,zjalfuoiurjq,a..fasdfa.123efafzcvs";
            HFM hfm = new HFM();
            String[] strs = new String[]{"A", "B", "C", "D", "E", "F"};
            int[] weights = new int[]{4, 6, 1, 9, 8, 2};
            Node root = hfm.createHFM(strs, weights);
            hfm.print(root, "");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值