哈夫曼编码

package cn.zhf.test;


import java.util.Comparator;
import java.util.NoSuchElementException;

public class HuffmanTree {
    final int SIZE = 256;

    public static void main(String[] args) {
        new HuffmanTree().encode();
    }

    // 编码
    public void encode() {
        String str = "hello";
        char[] ch = str.toCharArray();
        int[] freq = new int[SIZE];
        // 字符频率统计
        for (int i = 0; i < ch.length; i++)
            freq[ch[i]]++;
        Node1 root = buildTrie(freq);
        Node1.printTree(root);
        printBinaryTree(root, 0);
    }

    // 打印树形二叉树
    public static void printBinaryTree(Node1 root, int level) {
        if (root == null)
            return;
        printBinaryTree(root.right, level + 1);
        if (level != 0) {
            for (int i = 0; i < level - 1; i++)
                System.out.print("|\t");
            System.out.println("|-------" + root.ch + ":" + root.freq);
        } else
            System.out.println(root.ch + ":" + root.freq);
        printBinaryTree(root.left, level + 1);
    }

    /**
     * 创建哈夫曼树 1.根据频率表,将所有字符按照频率从小到大的顺序插入优先级队列中
     * 2.从优先级队列的第一个节点开始,把优先级最低的2个节点左右接到一个新的节点下,两者频率之和作为新节点的频率, 然后把这个新节点插入到优先级队列中
     * 3.循环上述过程直到优先级队列只剩下一个根节点,此时哈夫曼树构造完成。
     */
    public Node1 buildTrie(int[] freq) {
        PQueue pq = new PQueue(freq.length);
        for (int i = 0; i < freq.length; i++)
            if (freq[i] > 0)
                pq.insert(new Node1((char) i, freq[i], null, null));
        while (pq.size() > 1) {
            Node1 left = pq.delMin();
            Node1 right = pq.delMin();
            Node1 parent = new Node1('\0', left.freq + right.freq, left, right);
            pq.insert(parent);
        }
        return pq.delMin();
    }

}

// 节点类
class Node1 {
    char ch;
    int freq;
    Node1 left, right;

    public Node1(char ch, int freq, Node1 left, Node1 right) {
        this.ch = ch;
        this.freq = freq;
        this.left = left;
        this.right = right;
    }

    // 判断是否是叶节点
    public boolean isLeaf() {
        return left == null && right == null;
    }

    // 节点频率比较
    public int compareTo(Node1 that) {
        return this.freq - that.freq;
    }

    public String toString() {
        return "ch:" + this.ch + "; freq:" + this.freq;
    }

    /**
     * 编码: 从根节点开始,向左的方向上标记为0,向右的方向上标记为1
     */
    private void printNode(String path) {
        if ((left == null) && (right == null))
            System.out.println(ch + " " + path);

        if (left != null)
            left.printNode(path + '0');
        if (right != null)
            right.printNode(path + '1');
    }

    public static void printTree(Node1 tree) {
        tree.printNode("");
    }
}

// 优先级队列
class PQueue {
    Node1[] node1;
    int N;
    Comparator comparator;

    public PQueue(int size) {
        node1 = new Node1[size];
        N = 0;
    }

    public PQueue() {
    }

    public boolean isEmpty() {
        return N == 0;
    }

    public int size() {
        return N;
    }

    // 插入队列中,新插入的节点先放在队尾
    public boolean insert(Node1 node) {
        if (node1.length == size())
            return false;
        node1[++N] = node;
        swim(N);
        return true;
    }

    // 新插入的数与其他数比较
    private void swim(int k) {
        while (k > 1 && greater(k / 2, k)) {
            swap(k, k / 2);
            k = k / 2;
        }
    }

    // 比较大小
    private boolean greater(int i, int j) {
        if (comparator == null) {
            return ((Comparable) node1[i].freq).compareTo(node1[j].freq) < 0;
        } else {
            return comparator.compare(node1[i].freq, node1[j].freq) < 0;
        }
    }

    // 交换位置
    private void swap(int i, int j) {
        Node1 temp = node1[i];
        node1[i] = node1[j];
        node1[j] = temp;
    }

    // 返回并移除最小值
    public Node1 delMin() {
        if (isEmpty())
            throw new NoSuchElementException("underflow!");
        else
            return node1[N--];
    }

}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值