哈夫曼编码(Huffman)Java实现代码简化版
生活随笔
收集整理的這篇文章主要介紹了
哈夫曼编码(Huffman)Java实现代码简化版
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
這個網上發現的Huffuman編碼Java實現在組織上相對簡化,便于理解文件壓縮過程:提取文件統計字符頻度-根據字符頻度創建huffman樹-根據huffman樹生成huffman可變字長無前綴編碼-根據huffman編碼對文件中的字符轉化成二進制串-將huffman編碼的二進制串(非固定8位,可變字長)轉化成8位固定字節的字符并輸出文件。
代碼中對于Java數據類型的使用也值得參考。
package cn.hm;import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.InputStream; import java.io.OutputStream; import java.util.ArrayList; import java.util.Comparator; import java.util.HashMap; import java.util.Iterator; import java.util.PriorityQueue; import java.util.Set; public class HFMCondense { public class HFMNode { byte data; //存儲字節的數據域 int value; //字節出現的頻率 String code;//葉子結點的哈弗曼編碼 HFMNode lchild,rchild;//左右孩子的引用 //只指定數據的構造體 public HFMNode(byte data,int rate){ this(data,rate,null,null); } //同時指定左右孩子的構造體 public HFMNode(byte data,int value,HFMNode lchild,HFMNode rchild){ this.data=data; this.value=value; this.lchild=lchild; this.rchild=rchild; } } public static void main(String args[]){ String file="D://tmp//ori.txt"; HFMCondense condense=new HFMCondense(); HFMNode hfmTree=condense.HashMapToHFMTree(condense.readFiletoMap(file)); condense.HuffmanCoding(hfmTree, ""); System.out.println("開始壓縮..."); long start=System.currentTimeMillis(); condense.CompressFile(condense.createByteArray(condense.FileToString(file)),"D://tmp//des"); System.out.println("壓縮結束...用時:"+(System.currentTimeMillis()-start)); } /** * 讀取將要被壓縮的文件,統計每一個字符出現的頻率,并將得到的內容存入HashMap中 * @param fileName 將要被壓縮的文件 * @return 每一個字節數出現的頻率所對應的HashMap */ public HashMap<Byte,Integer> readFiletoMap(String fileName){ HashMap<Byte,Integer> hashMap=new HashMap<Byte,Integer>(); File file=new File(fileName); if(file.exists()){ try{ InputStream in=new FileInputStream(file); //創建與文件大小相同的字節數組 byte[] content=new byte[in.available()]; //讀取文件 in.read(content); //存入HashMap中 for(int i=0;i<content.length;i++){ //如果表中存在某一個鍵 if(hashMap.containsKey(content[i])){ //獲取該字節當前的鍵值 int rate=hashMap.get(content[i]); //鍵值增大 rate++; hashMap.put(content[i], rate); } //如果不存在某一個字節對象,則將它存入HashMap當中 else{ hashMap.put(content[i],1); } } in.close(); }catch(Exception e){ e.printStackTrace(); } } else{ System.out.println("文件不存在"); } return hashMap; } /** * 將HashMap中的元素取出來封裝到哈弗曼樹中,樹中葉子結點保存的是HashMap中的每一個鍵值與頻率 * @param map 讀取的Map * @return 哈夫曼樹的根結點 */ public HFMNode HashMapToHFMTree(HashMap<Byte,Integer> map){ //得到存儲鍵值的系 Set<Byte> keys=map.keySet(); //得到迭代器對象 Iterator<Byte> iter=keys.iterator(); //如果還有值 while(iter.hasNext()){ byte key=iter.next();//獲取系中的鍵 int value=map.get(key);//得到該鍵出現的頻率 //創建結點并將結點對象加入到隊列當中 HFMNode node=new HFMNode(key,value); nodeQueue.add(node); nodeList.add(node); } //當所剩的結點數還大于兩個 while(nodeQueue.size()>=2){ //得到鍵值頻率最小的兩個結點 HFMNode left=nodeQueue.poll(); HFMNode right=nodeQueue.poll(); //將這兩個結點組合起來生成新的結點 HFMNode node=new HFMNode(left.data,left.value+right.value,left,right); nodeQueue.add(node); } //獲取隊列中的最后一個結點作為根結點 HFMNode hfm=nodeQueue.poll(); return hfm; } /** * 為生成的哈弗曼樹進行編碼,產生對應的哈弗曼編碼表 * @param hfm 對應的哈弗曼樹 * @param code 對應生成的哈弗曼編碼 * @return 哈弗曼編碼表 */ //創建一個新的哈弗曼編碼表 HashMap<Byte,String> codeMap=new HashMap<Byte,String>(); public HashMap<Byte,String> HuffmanCoding(HFMNode hfm,String code){ //如果左子樹不為空,則左子樹編碼加1 if(hfm.lchild!=null){ HuffmanCoding(hfm.lchild,code+"1"); } //如果右子樹不為空,則右子樹編碼加0 if(hfm.rchild!=null){ HuffmanCoding(hfm.rchild,code+"0"); } //如果到達葉子結點,則將元素放入HashMap中生成哈弗曼編碼表 if(hfm.lchild==null&&hfm.rchild==null){ codeMap.put(hfm.data,code); hfm.code=code; } return codeMap; } /** * 將哈弗曼編碼轉換成字符串 * @param fileName 讀取的文件名 * @return 編碼之后的哈弗曼字符串 */ public String CodeToString(String fileName){ File file=new File(fileName); String codeString=""; //如果文件存在 if(file.exists()){ try{ InputStream in=new FileInputStream(file); byte content[]=new byte[in.available()]; in.read(content); int i=0; int len=content.length;//得到文件的字節長度 int size=nodeList.size();//得到隊列的長度 while(i<len){ for(int j=0;j<size;j++){ if(content[i]==nodeList.get(j).data){ codeString+=nodeList.get(j).code; break; } } i++; } in.close(); }catch(Exception e){ e.printStackTrace(); } }else { System.out.println("文件不存在"); } return codeString; } /** * 將文件按照對應的哈弗曼編碼表轉成01字符串 * @param fileName 讀入的文件名 * @return 轉譯后的字符串 */ public String FileToString(String fileName){ File file=new File(fileName); String StringContent=""; //如果文件存在 if(file.exists()){ try{ InputStream in=new FileInputStream(file); byte content[]=new byte[in.available()]; in.read(content); //循環轉譯 int len=content.length; for(int i=0;i<len;i++){ StringContent+=codeMap.get(content[i]); } in.close(); }catch(Exception e){ e.printStackTrace(); } }else{ System.out.println("文件不存在"); } return StringContent; } /** * 將轉譯后的01字符串重新轉換后放入新的字節數組當中 * @param code 轉譯后的01字符串 * @return 新的字節數組,里面包含了壓縮后的字節內容 */ public byte[] createByteArray(String code) { //將每8位字符分隔開來得到字節數組的長度 int size=code.length()/8; //截取得到字符串8整數后的最后幾個字符串 String destString=code.substring(size*8); byte dest[]=destString.getBytes(); //s用來記錄字節數組的單字節內容 int s = 0; int i=0; int temp = 0; // 將字符數組轉換成字節數組,得到字符的字節內容,方便將二進制轉為十進制 byte content[] = code.getBytes(); for (int k = 0; k < content.length; k++) { content[k] = (byte) (content[k] - 48); } //轉譯后的字節內容數組 byte byteContent[]; if (content.length % 8 == 0) {// 如果該字符串正好是8的倍數 byteContent = new byte[content.length / 8 + 1]; byteContent[byteContent.length - 1] = 0;// 那么返回的字節內容數組的最后一個數就補0 } else { //否則該數組的最后一個數就是補0的個數 byteContent = new byte[content.length / 8 + 2]; byteContent[byteContent.length - 1] = (byte) (8 - content.length % 8); } int bytelen=byteContent.length; int contentlen=content.length; // byteContent數組中最后一個是補0的個數,實際操作到次后個元素 //Math.pow返回第一個參數的第二個參數次冪的值 while (i < bytelen - 2) { for (int j = 0; j < contentlen; j++) { if (content[j] == 1) {// 如果數組content的值為1 s =(int)(s + Math.pow(2, (7 - (j - 8 * i))));// 累積求和 }// if if ((j+1)%8==0) {// 當有8個元素時 byteContent[i] = (byte) s;// 就將求出的和放入到byteContent數組中去 i++; s = 0;// 并重新使s的值賦為0 }// if }// for }// while int destlen=dest.length; for(int n=0;n<destlen;n++){ temp+=(dest[n]-48)*Math.pow(2, 7-n);//求倒數第2個字節的大小 } byteContent[byteContent.length - 2] = (byte) temp; return byteContent; } /** * 壓縮并輸出新文件 * @param content 壓縮后產生的新的字節數組 * @param fileName 輸出文件名 */ public void CompressFile(byte[] content,String fileName){ File file=null; //統一后綴名 if(!fileName.endsWith("hfm")){ file=new File(fileName+".hfm"); }else if(fileName.endsWith("hfm")){ file=new File(fileName); } int len=content.length; if(len>0){ try{ OutputStream out=new FileOutputStream(file); //將字節內容寫入文件 out.write(content); out.close(); }catch(Exception e){ e.printStackTrace(); } }else{ System.out.println("壓縮出錯"); } } /** * 測試一下哈弗曼樹建立是否正確 * @param hfm */ public void PreOrderTraverse(HFMNode hfm){ if(hfm!=null){ System.out.print(hfm.value+" "); PreOrderTraverse(hfm.lchild); PreOrderTraverse(hfm.rchild); } } /** * 存儲哈弗曼樹結點的優先隊列 */ ArrayList<HFMNode> nodeList=new ArrayList<HFMNode>(); PriorityQueue<HFMNode> nodeQueue=new PriorityQueue<HFMNode>(11,new MyComparator()); /** * 實例化的一個比較器類 */ class MyComparator implements Comparator<HFMNode>{ public int compare(HFMNode o1, HFMNode o2) { return o1.value-o2.value; } } }總結
以上是生活随笔為你收集整理的哈夫曼编码(Huffman)Java实现代码简化版的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 哈夫曼编码(Huffman)Java实现
- 下一篇: java美元兑换,(Java实现) 美元