• 哈夫曼(Huffman)编码


      在学习二叉树时看到关于哈夫曼编码的一些描述,兴趣来潮,自己写一个算法。哈夫曼算法使用二叉树

    以令人惊讶的方式来压缩数据,以提高数据传输的效率和时间。只有知道哈夫曼编码而不会写代码的童鞋们

    才会在网上搜代码,故在这里对哈夫曼编码不做过多介绍。

      实现哈弗曼(Huffman)算法的编码(Encode)与解码(Encode).

      分为以下四步来完成这项编码

      1.Create a Huffman tree for this message.
        2.Create a code table.
        3.Encode the message into binary.
        4.Decode the message from binary back to
          text.

      以下这段代码逻辑正确,测试结果也正确,但仍有一些缺陷还没解决。比如编码时出现频率最多的字符编码位数要最少,

    这样得到的编码位数少效率高,这段代码并没做到。其次还有对优先级队列运用不是很准确,不能精准的控制它.remove出的

    元素有时不符合我的预期。若有有心人的话,可在这个基础上二次开发,并将更完善的代码发我一份,共同学习。

      本程序是用Java编写的。 

      一.Node.java

     1 package main;
     2 
     3 class Node 
     4 {
     5     char cData;
     6     int iNumber;
     7     Node leftChild;
     8     Node rightChild;
     9     
    10     public void displayNode()
    11     {
    12         System.out.print("Node:");
    13         System.out.print("{");
    14         System.out.print(cData);
    15         System.out.print(",");
    16         System.out.print(iNumber);
    17         System.out.print("}");
    18     }
    19 }

       二.HuffmanTree.java

     1 package main;
     2 
     3 class HuffmanTree 
     4 {
     5     private Node root;
     6     
     7     public HuffmanTree(Node root)
     8     {
     9         this.root = root;
    10     }
    11     
    12     //获取root的引用,以便用来组装新树
    13     public Node getRoot()
    14     {
    15         return this.root;
    16     }
    17     
    18     //获取iNumber的值,代表频率数
    19     public int getNumber()
    20     {
    21         if(root != null)
    22             return root.iNumber;
    23         else
    24             return 0;
    25     }
    26 }

      三.Main.java

      1 /******************************************************
      2 Copyright:bupt
      3 Author:zhai bao hua
      4 Begin:2013-10-12
      5 End:2013-10-17
      6 E-mail:carman_loneliness@163.com
      7 Description:实现哈弗曼(Huffman)算法的编码(Encode)与
      8             解码(Encode).哈弗曼编码是一种数据压缩算
      9             法,以节省数据传输的时间,提高效率。
     10             分为以下四步来完成这项编码
     11             1.Create a Huffman tree for this message.
     12             2.Create a code table.
     13             3.Encode the message into binary.
     14             4.Decode the message from binary back to
     15               text.
     16 Description2:这段代码逻辑正确,测试结果也正确,但仍有一些
     17                缺陷还没解决。比如编码时出现频率最多的字符编码
     18                位数要最少,这样得到的编码位数少效率高,这段代码
     19                并没做到。其次还有对优先级队列运用不是很准确,
     20                不能精准的控制它.remove出的元素有时不符合我的
     21                预期。若有有心人的话,可在这个基础上二次开发,
     22                并将更完善的代码发我一份,共同学习。
     23 *******************************************************/
     24 package main;
     25 
     26 import java.util.Comparator;
     27 import java.util.HashMap;
     28 import java.util.PriorityQueue;
     29 import java.util.Set;
     30 
     31 public class Main
     32 {
     33     static HashMap<String,Integer> hmNumberTable;    //频率表
     34     static PriorityQueue<HuffmanTree> pqList;    //所有树的队列
     35     static HuffmanTree hTree;    //表示哈夫曼树
     36     static HashMap<String, String> hmCodeTable;    //代码表
     37     static String sHuffman = "";    //Encode的字符串
     38     static String sDecode = "";    //Decode的字符串
     39     
     40     public static void main(String[] args) 
     41     {
     42         //test word
     43         String sSample = "TODAY IS A GOOD DAY";
     44         
     45         /*一.Create a Huffman tree for this message
     46          */
     47         
     48         //得到每个字符出现几率频率表
     49         hmNumberTable = gethmNumberTable(sSample);
     50         
     51         //定义优先级队列,key值小的排在先
     52         Comparator<HuffmanTree> OrderIsdn =  new Comparator<HuffmanTree>() 
     53         {
     54             @Override
     55             public int compare(HuffmanTree o1, HuffmanTree o2) 
     56             {
     57                 int numbera = o1.getNumber();  
     58                 int numberb = o2.getNumber();  
     59                 if(numberb > numbera)  
     60                 {
     61                     return -1;  
     62                 }  
     63                 else if(numberb < numbera)  
     64                 {
     65                     return 1;  
     66                 }  
     67                 else  
     68                 {
     69                     return 0;  
     70                 } 
     71             }
     72         };
     73         pqList = new PriorityQueue<HuffmanTree>(hmNumberTable.size(),OrderIsdn);
     74         
     75         /*操作步骤
     76          *1.为消息中的每个字符创建一个Node对象,每个节点有两个数据项:
     77          *字符和字符在消息中出现的频率。
     78          *2.为这些节点创建tree对象
     79          *3.把这些树都插入到优先级队列pqList当中去,它们按频率排序,
     80          *频率小的有最高优先级。
     81          */
     82         Set<String> sTemp = hmNumberTable.keySet();
     83         for(String string:sTemp)
     84         {
     85             Node node = new Node();
     86             node.cData = string.charAt(0);
     87             node.iNumber = hmNumberTable.get(string);
     88             HuffmanTree hTempTree = new HuffmanTree(node);
     89             pqList.add(hTempTree);
     90         }
     91         
     92         /*操作步骤
     93          *1.从pqList中删除两棵树,并把它们作为一个新节点的子节点。
     94          *新节点的频率是子节点频率的和,它的字符字段可以是空的。
     95          *2.把这个新的三节点树插回优先级队列里。
     96          *3.反复重复第一步和第二步。树会越变越大,队列中的数据项会
     97          *越来越少。当队中只有一颗树时,它就是所建的哈夫曼树了。
     98          */
     99         while(pqList.size() > 1)
    100         {
    101             HuffmanTree hTempA = pqList.peek();
    102             pqList.remove();
    103             HuffmanTree hTempB = pqList.peek();
    104             pqList.remove();
    105             Node node = new Node();
    106             node.cData = '$';    //$作为一个特别的char,用作识别。
    107             node.iNumber = hTempA.getNumber() + hTempB.getNumber();
    108             node.leftChild = hTempA.getRoot();
    109             node.rightChild = hTempB.getRoot();
    110             HuffmanTree hTempC = new HuffmanTree(node);
    111             pqList.add(hTempC);
    112             //测试单元,遍历队列
    113 //            traveQueue(pqList);
    114         }
    115         hTree = pqList.peek();
    116         
    117         /*二.Create a code table.
    118          *得到hmCodeTable
    119          */
    120         
    121         hmCodeTable = new HashMap<String, String>();
    122         getPaths(hTree.getRoot(),"");
    123         
    124         /*三.Encode the message into binary.
    125          */
    126         for(char cTemp:sSample.toCharArray())
    127         {
    128             String string = hmCodeTable.get(String.valueOf(cTemp));
    129             sHuffman = sHuffman + string;
    130         }
    131         System.out.println("Huffman Code:");
    132         System.out.println(sHuffman);
    133         
    134         /*四.Decode the message from binary back to
    135          *     text.
    136          */
    137         int index = 0;
    138         char cIndex;
    139         Node nIndexNode = hTree.getRoot();
    140         while(index < sHuffman.length())
    141         {
    142             cIndex = sHuffman.charAt(index);
    143             if(cIndex == '1')
    144             {
    145                 nIndexNode = nIndexNode.rightChild;
    146             }
    147             else if(cIndex == '0')
    148             {
    149                 nIndexNode = nIndexNode.leftChild;
    150             }
    151             if(nIndexNode.leftChild == null && nIndexNode.rightChild == null)
    152             {
    153                 sDecode = sDecode + nIndexNode.cData;
    154                 nIndexNode = hTree.getRoot();
    155             }
    156             index ++;
    157         }
    158         System.out.println("Decode:");
    159         System.out.println(sDecode);
    160     }
    161     
    162     //得到频率的Hash表
    163     private static HashMap<String,Integer> gethmNumberTable(String sSample) 
    164     {
    165         HashMap<String,Integer> hmList = new HashMap<String,Integer>();
    166         for(int i = 0;i < sSample.length();i++)
    167         {
    168             char temp = sSample.charAt(i);
    169             String sTemp = String.valueOf(temp);
    170             if(hmList.containsKey(sTemp))
    171             {
    172                 int value = hmList.get(sTemp) + 1;
    173                 hmList.remove(sTemp);
    174                 hmList.put(sTemp, value);
    175             }
    176             else
    177             {
    178                 hmList.put(sTemp,1);
    179             }
    180         }
    181         return hmList;
    182     }
    183     
    184     /*递归遍历所有节点,并保存所有叶子节点的路径
    185      *node:父节点
    186      *myPath:父节点本身的路径
    187      *向左走一步为0,向右走一步为1.
    188      *终止条件:遍历到叶子节点为止.因此可遍历完所有叶子节点
    189      *递归代码很简单,但理清思路确花了我好久的时间。
    190      */
    191     private static void getPaths(Node node,String myPath)
    192     {
    193         String[] sPaths = new String[2];
    194         if(node.leftChild == null && node.rightChild == null)
    195         {
    196             System.out.println("{" + node.cData + ":" + myPath + "}");
    197             hmCodeTable.put(String.valueOf(node.cData), myPath);
    198             return;
    199         }
    200         if(node.leftChild != null)
    201         {
    202             sPaths[0] = myPath + "0";
    203             getPaths(node.leftChild,sPaths[0]);
    204         }
    205         if(node.rightChild != null)
    206         {
    207             sPaths[1] = myPath + "1";
    208             getPaths(node.rightChild,sPaths[1]);
    209         }
    210         return;
    211     }
    212     
    213     /*UNIT*UNIT
    214      *测试代码 
    215      *遍历队列但不删除元素
    216      */
    217     private static void traveQueue(PriorityQueue<HuffmanTree> list)
    218     {
    219         HuffmanTree[] trees = new HuffmanTree[list.size()];
    220         int i = 0;
    221         while(list.size() > 0)
    222         {
    223             HuffmanTree tree = list.peek();
    224             System.out.print(tree.getRoot().cData + ":" + tree.getNumber() + " ");
    225             list.remove();
    226             trees[i] = tree;
    227             i++;
    228         }
    229         System.out.println();
    230         for(HuffmanTree theTree:trees)
    231         {
    232             list.add(theTree);
    233         }
    234     }
    235 }

      邮箱:carman_loneliness@163.com

      希望和大家多多交流!

  • 相关阅读:
    java内存管理之内存模型
    HTTP协议
    12 数值的整数次方
    11 二进制中1的个数+二进制补充知识点
    10 矩形覆盖
    9 变态跳台阶
    8 跳台阶
    7斐波那契数列
    6旋转数组的最小数字
    5用两个栈实现队列
  • 原文地址:https://www.cnblogs.com/carmanloneliness/p/3374149.html
Copyright © 2020-2023  润新知