huffman编码详解与java代码实现

参考:
https://download.csdn.net/download/qq_31567335/10356263

huffman编码

字符编码

编码分为定长编码和不定长编码。定长编码实现简单,效率高。不定长编码是为了压缩数据而提出的编码方式:给使用频率高的字符短的编码。那么到底如何给字符编码,而使平均长度最短呢?huffman就是解决这个问题的。

不定长编码

先介绍一下前缀编码

在一个编码系统中,任何一个编码都不是其他编码的前缀,则称该编码系统的编码是前缀码。例如: 01, 10, 110, 111, 101 就不是前缀编码,因为 10 是 101 的前缀,如果去掉 10或101就是前缀编码。当在一个编码系统中采用定长编码时,可以不需要分隔符;如果采用不定长编码时,必须使用前缀编码或分隔符,否则在解码时会产生歧义。所谓解码就是由二进制位串还原字符数据的过程。而使用分隔符会加大编码长度,因此一般采用前缀编码。

前缀编码可以通过二叉树来实现:
使用二叉树对字符集中的字符进行编码的方法是,将字符集中的所有字符作为二叉树的叶子结点;在二叉树中,每一个“父亲—左孩子”关系对应一位二进制位 0,每一个“父亲—右孩子”关系对应一位二进制位 1;于是从根结点通往每个叶子结点的路径,就对应于相应字符的二进制编码。每个字符编码的长度 L 等于对应路径的长度,也等于该叶子结点的层次数。
这里写图片描述

huffman编码

而如何使得二叉树得到的编码是最优的,也就是平均编码长度,也可以说树的叶子结点的平均深度最小?huffman编码解决了这一问题。其编码步骤如下:
1. 根据给定的 n 个权值,构造 n 棵只有一个根结点的二叉树, n 个权值分别是这些二叉树根结点的权, F 是由这 n 棵二叉树构成的集合;
2. 在 F 中选取两棵根结点树值最小的树作为左、右子树,构造一颗新的二叉树,置新二叉树根的权值=左子树根结点权值+右子树根结点权值;
3. 从 F 中删除这两颗树,并将新树加入 F;
4. 重复以上步骤,直到只剩下最后一颗树。
如下图所示(图截自java数据结构与算法 作者:周鹏):
这里写图片描述

huffman编码正确性证明

个人理解:
通过huffman编码构造的树,每一步都满足这样一个性质:权值最小的节点层数最大。由这个性质可以推断,无论如何,都无法构造出一颗总权值更小的树。所以huffman编码是最优的。

java代码实现

二叉树节点:

package dataStructureAndAlgorithms;

public class HuffmanTreeNode implements Comparable<HuffmanTreeNode>{
    public int getWeight() {
        return weight;
    }

    public void setWeight(int weight) {
        this.weight = weight;
    }

    public String getCode() {
        return code;
    }

    public void setCode(String code) {
        this.code = code;
    }

    public HuffmanTreeNode getLeftChild() {
        return leftChild;
    }

    public void setLeftChild(HuffmanTreeNode leftChild) {
        this.leftChild = leftChild;
    }

    public HuffmanTreeNode getRightChild() {
        return rightChild;
    }

    public void setRightChild(HuffmanTreeNode rightChild) {
        this.rightChild = rightChild;
    }

    public String getContent() {
        return content;
    }

    public void setContent(String content) {
        this.content = content;
    }

    private String content = null;
    private int weight;
    private String code = "";
    private HuffmanTreeNode leftChild = null;
    private HuffmanTreeNode rightChild = null;


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

    //Returns:a negative integer, zero, or a positive integer as this object is
    //less than, equal to, or greater than the specified object.
    public int compareTo(HuffmanTreeNode o) {
        if(weight<o.getWeight()){
            return -1;
        }else if(weight > o.getWeight()){
            return 1;
        }else{
            return 0;
        }
    }
}

哈夫曼编码:

package dataStructureAndAlgorithms;

import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;


public class HuffmanCode {
    public static HuffmanTreeNode buildHuffmanTree(List<HuffmanTreeNode> nodes){
        int n = nodes.size();
        //n-1次
        for(int i=1;i<n;i++){
            Collections.sort(nodes);

            HuffmanTreeNode min1 = nodes.remove(0);
            HuffmanTreeNode min2 = nodes.remove(0);
            HuffmanTreeNode newNode = new HuffmanTreeNode(min1.getWeight()+min2.getWeight());
            newNode.setLeftChild(min1);
            newNode.setRightChild(min2);
            nodes.add(newNode);
        }
        return nodes.get(0);
    }

    public static void generateHuffmanCode(HuffmanTreeNode root){
        if(root.getLeftChild() != null){
            root.getLeftChild().setCode(root.getCode() + "0");
            generateHuffmanCode(root.getLeftChild());
        }

        if(root.getRightChild() != null){
            root.getRightChild().setCode(root.getCode() + "1");
            generateHuffmanCode(root.getRightChild());
        }
    }

    public static void main(String[] args) {
        HuffmanTreeNode node1 = new HuffmanTreeNode(3);
        node1.setContent("A");
        HuffmanTreeNode node2 = new HuffmanTreeNode(1);
        node2.setContent("B");
        HuffmanTreeNode node3 = new HuffmanTreeNode(2);
        node3.setContent("C");
        HuffmanTreeNode node4 = new HuffmanTreeNode(1);
        node4.setContent("D");

        List<HuffmanTreeNode>nodes = new LinkedList<HuffmanTreeNode>();
        nodes.add(node1);
        nodes.add(node2);
        nodes.add(node3);
        nodes.add(node4);

        List<HuffmanTreeNode>nodeCopy = new ArrayList<HuffmanTreeNode>();
        nodeCopy.addAll(nodes);


        HuffmanTreeNode root = buildHuffmanTree(nodes);
        generateHuffmanCode(root);


        for(HuffmanTreeNode node:nodeCopy){
            System.out.println(node.getContent() + "->" + node.getCode());
        }
    }
}

结果:

A->0
B->110
C->10
D->111

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值