Java實現啥夫曼編碼

來源:互聯網
上載者:User

在開發手機程式時,總是希望壓縮網路傳輸的資訊,以減少流量。本文僅以哈夫曼編碼為引導,拋磚引玉,實現壓縮功能。

大家可能會想,程式和第三方提供了很多壓縮方式,何必自己寫壓縮代碼呢?不錯,如GZIP這樣的壓縮公用程式很多,可是在某些情況下(如常值內容小且字元不重複),GZIP壓縮後會比原始文本還要大。所以在某些特殊情況下用自己的壓縮方式可以更優。

大家可能早已忘記了在學校學習的哈夫曼知識,可以先在百度百科瞭解一下哈夫曼知識

http://baike.baidu.com/view/127820.htm

哈夫曼思想:統計文本字元重複率,求出各字元權值,再構造出一顆最優二叉樹(又稱哈夫曼樹),然後給每個葉子結點產生一個以位(bit)為單位的碼值,每個碼值不能做為其他碼值的首碼,再將碼值合并以每8個產生一個位元組。

package com.huffman;/** * 結點 * @author Davee */public class Node implements Comparable<Node> {    int weight;//權值    Node leftChild;//左孩子結點    Node rightChild;//右孩子結點    String huffCode;    private boolean isLeaf;//是否是葉子    Character value;        public Node(Character value, int weight) {        this.value = value;        this.weight = weight;        this.isLeaf = true;    }        public Node(int weight, Node leftChild, Node rightChild) {        this.weight = weight;        this.leftChild = leftChild;        this.rightChild = rightChild;    }        public void increaseWeight(int i) {        weight += i;    }        public boolean isLeaf() {        return isLeaf;    }    @Override    public int compareTo(Node o) {        return this.weight - o.weight;    }}

package com.huffman;import java.math.BigInteger;import java.util.ArrayList;import java.util.Collections;import java.util.HashMap;import java.util.Map;import java.util.TreeMap;public class HuffmanTree {    private boolean debug = false;        private HashMap<Character, Node> nodeMap;    private ArrayList<Node> nodeList;        public HuffmanTree() {        nodeMap = new HashMap<Character, Node>();        nodeList = new ArrayList<Node>();    }    public void setDebug(boolean debug) {        this.debug = debug;    }        public String decode(Map<String, Character> codeTable, String binary) {        int begin = 0, end = 1, count = binary.length();        StringBuffer sb = new StringBuffer();        while (end <= count) {            String key = binary.substring(begin, end);            if (codeTable.containsKey(key)) {                sb.append(codeTable.get(key));                begin = end;            } else {            }            end++;        }        return sb.toString();    }    public String encode(String originText) {        if (originText == null) return null;                calculateWeight(originText);        //        if (debug) printNodes(nodeList);        Node root = generateHuffmanTree(nodeList);                generateHuffmanCode(root, "");                if (debug) printNodes(root);                StringBuffer sb = new StringBuffer();        for (Character key : originText.toCharArray()) {            sb.append(nodeMap.get(key).huffCode);        }        if (debug) System.out.println("二進位:"+sb.toString());                return sb.toString();    }        /**     * 計算葉子權值     * @param text     */    private void calculateWeight(String text) {        for (Character c : text.toCharArray()) {            if (nodeMap.containsKey(c)) {                nodeMap.get(c).increaseWeight(1);//權值加1            } else {                Node leafNode = new Node(c, 1);                nodeList.add(leafNode);                nodeMap.put(c, leafNode);            }        }    }        /**     * 產生哈夫曼樹     * @param nodes     */    private Node generateHuffmanTree(ArrayList<Node> nodes) {        Collections.sort(nodes);        while(nodes.size() > 1) {            Node ln = nodes.remove(0);            Node rn = nodes.remove(0);            insertSort(nodes, new Node(ln.weight + rn.weight, ln, rn));        }        Node root = nodes.remove(0);        nodes = null;        return root;    }        /**     * 插入排序     * @param sortedNodes     * @param node     */    private void insertSort(ArrayList<Node> sortedNodes, Node node) {        if (sortedNodes == null) return;        int weight = node.weight;        int min = 0, max = sortedNodes.size();        int index;        if (sortedNodes.size() == 0) {            index = 0;        } else if (weight < sortedNodes.get(min).weight) {            index = min;//插入到第一個        } else if (weight >= sortedNodes.get(max-1).weight) {            index = max;//插入到最後        } else {            index = max/2;            for (int i=0, count=max/2; i<=count; i++) {                if (weight >= sortedNodes.get(index-1).weight && weight < sortedNodes.get(index).weight) {                    break;                } else if (weight < sortedNodes.get(index).weight) {                    max = index;                } else {                    min = index;                }                index = (max + min)/2;            }        }        sortedNodes.add(index, node);    }        private void generateHuffmanCode(Node node, String code) {        if (node.isLeaf()) node.huffCode = code;        else {            generateHuffmanCode(node.leftChild, code + "0");            generateHuffmanCode(node.rightChild, code + "1");        }    }        /**     * 產生碼錶     * @return     */    public Map<String, Character> getCodeTable() {        Map<String, Character> map = new HashMap<String, Character>();        for (Node node : nodeMap.values()) {            map.put(node.huffCode, node.value);        }        return map;    }        /**     * 列印節點資訊     * @param root     */    private void printNodes(Node root) {        System.out.println("字元  權值  哈夫碼");        printTree(root);    }        private void printTree(Node root) {        if (root.isLeaf()) System.out.println((root.value == null ? "   " : root.value)+"    "+root.weight+"    "+(root.huffCode == null ? "" : root.huffCode));        if (root.leftChild != null) printTree(root.leftChild);        if (root.rightChild != null) printTree(root.rightChild);    }    /**     * 列印節點資訊     * @param nodes     */    private void printNodes(ArrayList<Node> nodes) {        System.out.println("字元  權值  哈夫碼");        for (Node node : nodes) {            System.out.println(node.value+"    "+node.weight+"    "+node.huffCode);        }    }}

package com.test;import java.util.Map;import com.huffman.HuffUtils;import com.huffman.HuffmanTree;public class Test {    public static void main(String[] args) {        String originText = "abcdacaha";        HuffmanTree huffmanTree = new HuffmanTree();        huffmanTree.setDebug(true);//測試        String binary = huffmanTree.encode(originText);        byte[] bytes = HuffUtils.binary2Bytes(binary);        Map<String, Character> codeTable = huffmanTree.getCodeTable();        int lastByteNum = binary.length() % 8;        System.out.println(bytes.length);        //將bytes、codeTable、 lastByteNum傳遞到伺服器端        //省略。。。。。。                /*                         伺服器端解析                         接收到參數,並轉換成bytes、relationMap、 lastByteNum        */        String fullBinary = HuffUtils.bytes2Binary(bytes, lastByteNum);        System.out.println("伺服器二進位:"+fullBinary);        String retrieveText = huffmanTree.decode(codeTable, fullBinary);        System.out.println("恢複文本:"+retrieveText);    }}

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.