Huffman編碼演算法之Java實現__JSON

來源:互聯網
上載者:User

目錄(?)[+] Huffman編碼介紹

Huffman編碼處理的是字元以及字元對應的二進位的編碼配對問題,分為編碼和解碼,目的是壓縮字元對應的位元據長度。我們知道字元存貯和傳輸的時候都是二進位的(電腦只認識0/1),那麼就有字元與二進位之間的mapping關係。字元屬於字元集(Charset), 字元需要通過編碼(encode)為二進位進行存貯和傳輸,顯示的時候需要解碼(decode)回字元,字元集與編碼方法是一對多關聯性(Unicode可以用UTF-8,UTF-16等編碼)。理解了字元集,編碼以及解碼,滿天飛的亂碼問題也就遊刃而解了。以英文字母小寫a為例, ASCII編碼中,十進位為97,二進位為01100001。ASCII的每一個字元都用8個Bit(1Byte)編碼,假如有1000個字元要傳輸,那麼就要傳輸8000個Bit。問題來了,英文中字母e的使用頻率為12.702%,而z為0.074%,前者是後者的100多倍,但是確使用相同位元的二進位。可以做得更好,方法就是可變長度編碼,指導原則就是頻率高的用較短的位元編碼,頻率低的用較長位元編碼。Huffman編碼演算法就是處理這樣的問題。 Huffman編碼Java實現

Huffman編碼演算法主要用到的資料結構是完全二叉樹(full binary tree)和優先順序隊列。後者用的是java.util.PriorityQueue,前者自己實現(都為內部類),代碼如下: [java] view plain copy static class Tree {           private Node root;              public Node getRoot() {               return root;           }              public void setRoot(Node root) {               this.root = root;           }       }          static class Node implements Comparable<Node> {           private String chars = "";           private int frequence = 0;           private Node parent;           private Node leftNode;           private Node rightNode;              @Override           public int compareTo(Node n) {               return frequence - n.frequence;           }              public boolean isLeaf() {               return chars.length() == 1;           }              public boolean isRoot() {               return parent == null;           }              public boolean isLeftChild() {               return parent != null && this == parent.leftNode;           }              public int getFrequence() {               return frequence;           }              public void setFrequence(int frequence) {               this.frequence = frequence;           }              public String getChars() {               return chars;           }              public void setChars(String chars) {               this.chars = chars;           }              public Node getParent() {               return parent;           }              public void setParent(Node parent) {               this.parent = parent;           }              public Node getLeftNode() {               return leftNode;           }              public void setLeftNode(Node leftNode) {               this.leftNode = leftNode;           }              public Node getRightNode() {               return rightNode;           }              public void setRightNode(Node rightNode) {               this.rightNode = rightNode;           }       }   統計資料

既然要按頻率來安排編碼錶,那麼首先當然得獲得頻率的統計資訊。我實現了一個方法處理這樣的問題。如果已經有統計資訊,那麼轉為Map<Character,Integer>即可。如果你得到的資訊是百分比,乘以100或1000,或10000。總是可以轉為整數。比如12.702%乘以1000為12702,Huffman編碼只關心大小問題。統計方法實現如下: [java] view plain copy public static Map<Character, Integer> statistics(char[] charArray) {           Map<Character, Integer> map = new HashMap<Character, Integer>();           for (char c : charArray) {               Character character = new Character(c);               if (map.containsKey(character)) {                   map.put(character, map.get(character) + 1);               } else {                   map.put(character, 1);               }           }              return map;       }   構建樹

構建樹是Huffman編碼演算法的核心步驟。思想是把所有的字元掛到一顆完全二叉樹的葉子節點,任何一個非頁子節點的左節點出現頻率不大於右節點。演算法為把統計資訊轉為Node存放到一個優先順序隊列裡面,每一次從隊列裡面彈出兩個最小頻率的節點,構建一個新的父Node(非葉子節點), 字元內容剛彈出來的兩個節點字元內容之和,頻率也是它們的和,最開始的彈出來的作為左子節點,後面一個作為右子節點,並且把剛構建的父節點放到隊列裡面。重複以上的動作N-1次,N為不同字元的個數(每一次隊列裡面個數減1)。結束以上步驟,隊列裡面剩一個節點,彈出作為樹的根節點。代碼如下: [java] view plain copy private static Tree buildTree(Map<Character, Integer> statistics,               List<Node> leafs) {           Character[] keys = statistics.keySet().toArray(new Character[0]);              PriorityQueue<Node> priorityQueue = new PriorityQueue<Node>();           for (Character character : keys) {               Node node = new Node();               node.chars = character.toString();               node.frequence = statistics.get(character);               priorityQueue.add(node);               leafs.add(node);           }              int size = priorityQueue.size();           for (int i = 1; i <= size - 1; i++) {               Node node1 = priorityQueue.poll();               Node node2 = priorityQueue.poll();                  Node sumNode = new Node();               sumNode.chars = node1.chars + node2.chars;               sumNode.frequence = node1.frequence + node2.frequence;                  sumNode.leftNode = node1;               sumNode.rightNode = node2;                  node1.parent = sumNode;               node2.parent = sumNode;                  priorityQueue.add(sumNode);           }              Tree tree = new Tree();           tree.root = priorityQueue.poll();           return tree;       }   編碼

某個字元對應的編碼為,從該字元所在的葉子節點向上搜尋,如果該字元節點是父節點的左節點,編碼字元之前加0,反之如果是右節點,加1,直到根節點。只要擷取了字元和二進位碼之間的mapping關係,編碼就非常簡單。代碼如下: [java] view plain copy public static String encode(String originalStr,               Map<Character, Integer> statistics) {           if (originalStr == null || originalStr.equals("")) {               return "";           }              char[] charArray = originalStr.toCharArray();           List<Node> leafNodes = new ArrayList<Node>();           buildTree(statistics, leafNodes);           Map<Character, String> encodInfo = buildEncodingInfo(leafNodes);              StringBuffer buffer = new StringBuffer();           for (char c : charArray) {               Character character = new Character(c);               buffer.append(encodInfo.get(character));           }              return buffer.toString();       }   [java] view plain copy private static Map<Character, String> buildEncodingInfo(List<Node> leafNodes) {           Map<Character, String> codewords = new HashMap<Character, String>();           for (Node leafNode : leafNodes) {               Character character = new Character(leafNode.getChars().charAt(0));               String codeword = "";               Node currentNode = leafNode;                  do {                   if (currentNode.isLeftChild()) {                       codeword = "0" + codeword;                   } else {                       codeword = "1" + codeword;                   }                      currentNode = currentNode.parent;               } while (currentNode.parent != 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.