霍夫曼树,霍夫曼编码

关于霍夫曼树和霍夫曼编码的背景知识,这里不讲述。本文只记录代码。

package org.lyk.entities;

import org.lyk.entities.List.Node;
import org.omg.CORBA.Current;

public class HuffmanTree<T extends Comparable<T>>
{
    class PriorityNode implements Comparable<PriorityNode>
    {
        T data;
        int count = 0;

        public PriorityNode(T data, int count)
        {
            super();
            this.data = data;
            this.count = count;
        }

        @Override
        public int hashCode()
        {
            final int prime = 31;
            int result = 1;
            result = prime * result + getOuterType().hashCode();
            result = prime * result + count;
            result = prime * result + ((data == null) ? 0 : data.hashCode());
            return result;
        }

        @Override
        public boolean equals(Object obj)
        {
            if (this == obj)
                return true;
            if (obj == null)
                return false;
            if (getClass() != obj.getClass())
                return false;
            PriorityNode other = (PriorityNode) obj;
            if (!getOuterType().equals(other.getOuterType()))
                return false;

            if (data == null)
            {
                if (other.data != null)
                    return false;
            } else if (!data.equals(other.data))
                return false;
            return true;
        }

        private HuffmanTree getOuterType()
        {
            return HuffmanTree.this;
        }

        @Override
        public int compareTo(HuffmanTree<T>.PriorityNode o)
        {
            if (this.count < o.count)
                return -1;
            else if (this.count > o.count)
                return 1;
            else
                return 0;
        }
    }

    class HuffmanNode
    {
        PriorityNode data;
        HuffmanNode left;
        HuffmanNode right;
        String code = "?";

        public HuffmanNode(PriorityNode data)
        {
            this.data = data;
        }
    }

    private java.util.List<PriorityNode> pnList = null;
    private java.util.List<HuffmanNode> hfList = null;
    private StringBuffer codes = new StringBuffer();

    public void setPriorityList(T[] source)
    {
        java.util.List<PriorityNode> pnList = new java.util.ArrayList<>();
        for (T item : source)
        {
            PriorityNode temp = new PriorityNode(item, 1);
            if (!pnList.contains(temp))
            {
                pnList.add(temp);
            } else
            {
                int index = pnList.indexOf(temp);
                PriorityNode pn = pnList.get(index);
                pn.count++;
            }
        }
        pnList.sort((pn1, pn2) ->
        {
            return pn1.compareTo(pn2);
        });
        this.pnList = pnList;
    }

    public void setHuffmanList()
    {
        java.util.List<HuffmanNode> hfList = new java.util.ArrayList<>();
        for (PriorityNode item : this.pnList)
        {
            HuffmanNode temp = new HuffmanNode(item);
            hfList.add(temp);
        }
        this.hfList = hfList;
    }

    public void setHuffmanTree()
    {
        while (this.hfList.size() > 1)
        {
            HuffmanNode node0 = this.hfList.get(0);
            HuffmanNode node1 = this.hfList.get(1);
            PriorityNode pn = new PriorityNode(null, node0.data.count + node1.data.count);
            HuffmanNode newHFNode = new HuffmanNode(pn);
            newHFNode.code = "?";

            if (node0.data.count < node1.data.count)
            {
                node0.code = "0";
                newHFNode.left = node0;
                node1.code = "1";
                newHFNode.right = node1;
            } else
            {
                node1.code = "0";
                newHFNode.left = node1;
                node0.code = "1";
                newHFNode.right = node0;
            }

            this.hfList.remove(0);
            this.hfList.remove(0);
            this.hfList.add(newHFNode);
            this.hfList.sort((hfNode1, hfNode2) ->
            {
                if (hfNode1.data.count < hfNode2.data.count)
                    return -1;
                else if (hfNode1.data.count > hfNode2.data.count)
                    return 1;
                else
                    return 0;
            });
        }
    }

    public void encodeHuffmanTree()
    {
        this.encodeInternal(this.hfList.get(0), "?");
        this.getAllCodes(this.hfList.get(0));
        //System.out.println(this.codes.toString());
    }

    private void encodeInternal(HuffmanNode hfNode, String preCode)
    {
        if ("?".equals(hfNode.code))
        {
            if (null != hfNode.left)
                encodeInternal(hfNode.left, "");
            if (null != hfNode.right)
                encodeInternal(hfNode.right, "");
        } else
        {
            // 非根元素
            hfNode.code = preCode + hfNode.code;
            if (null != hfNode.left)
                encodeInternal(hfNode.left, hfNode.code);
            if (null != hfNode.right)
                encodeInternal(hfNode.right, hfNode.code);
        }
    }

    private void getAllCodes(HuffmanNode node)
    {
        if (null == node.left && null == node.right)
        { 
            this.codes.append(node.code);
        }
        if (null != node.left)
            getAllCodes(node.left);
        if (null != node.right)
            getAllCodes(node.right);
    }

    public String decode(String codes)
    {
        char[] charArray = codes.toCharArray();
        HuffmanNode current = this.hfList.get(0);
        for (char c : charArray)
        {
            if ('0' == c)
                current = current.left;
            else if ('1' == c)
                current = current.right;

            if (null == current.left && null == current.right)
            {
                System.out.print(current.data.data);
                current = this.hfList.get(0);
            }
        }
        return null;
    }

    public void find(T item)
    {
        this.findInternal(this.hfList.get(0), item);
    }

    private void findInternal(HuffmanNode node, T item)
    {
        if (null == node.left && null == node.right)
        {
            if (node.data.data.equals(item))
                this.codes.append(node.code);
        }

        if (null != node.left)
            findInternal(node.left, item);
        if (null != node.right)
            findInternal(node.right, item);

    }

    public String encodeContent(T[] charArray)
    {
        for (T c : charArray)
        {
            this.find(c);
        }

        return this.codes.toString();
    }
}

测试代码:

    public static void main(String[] args) throws Exception
    {
        StringBuffer info = new StringBuffer();
        File inputFile = new File("C:\D\code\Docs\Linux.txt");
        Scanner scanner = new Scanner(new FileInputStream(inputFile));
        scanner.useDelimiter("
");
        while(scanner.hasNext())
        {
            info.append(scanner.next());
        } 
        int countSource = info.length();
        HuffmanTree<Character> ht = new HuffmanTree<>();
        char[] _charArray = info.toString().toCharArray();
        Character[] charArray = new Character[_charArray.length];
        for(int i = 0; i < _charArray.length; i++)
        {
            charArray[i] = _charArray[i];
        }
        ht.setPriorityList(charArray);
        ht.setHuffmanList();
        ht.setHuffmanTree();
        ht.encodeHuffmanTree();
        String codes = ht.encodeContent(charArray);
        int countNew = codes.length();
        System.out.println(codes);;
        ht.decode("0000000000000100000100000");
        System.out.println("原长度:" + (countSource*3*8));
        System.out.println("压缩后长度:" + countNew);
        System.out.println("压缩率:" + (new BigDecimal(countNew/(countSource*3*8*1.0)).divide(new BigDecimal("1"),2, RoundingMode.HALF_EVEN)));
        System.out.println("///~ Main done");
        
    }    
原文地址:https://www.cnblogs.com/kuillldan/p/6045003.html