Huffman 壓縮解壓縮java實現

附上完整代碼

http://download.csdn.net/download/u010485034/7847447

Huffman編碼的原理這裏就不說了,網上隨處都是。這裏來講講利用Huffman編碼來進行壓縮和解壓縮的具體實現吧。本工程使用java實現。


編碼

1. 流程圖


2. 數據結構

CharacterWeight:記錄字符值,以及其在待壓縮文件中的權重。

Class{
char c; //字符值
int weight;  //在文件中權重
String code;  //其對應huffman編碼
}

HuffmanNode:huffman樹中的節點信息。

Class{
Int parent;  //父節點
Int lChild; //左兒子
Int rChild;  //右兒子
Int weight; //權重
}

3. 程序關鍵點

3.1 Huffman樹的構建

Huffman樹的變量:ArrayList<HuffmanNode> list;

創建流程圖:

for(int i=0;i<list.size()-1;i++){
			//w1 : the first min weight w2: the second min weight 
			//i1 : the first min weight index, i2: the second min weight index
			int w1 = MAX_VALUE, w2=MAX_VALUE; 
			int i1 = 0, i2 = 0;
			// find the two node with the minimum weight
			for(int j=0;j<tree.size();j++){
				HuffmanNode node = tree.get(j);
				if(node.getWeight()< w1 && node.getParent()==-1){
					w2 = w1;
					w1 = node.getWeight();
					i2 = i1;
					i1 = j;
				}
				else if(node.getWeight()<w2 && node.getParent()==-1){
					w2 = node.getWeight();
					i2 = j;
				}
			}
			//set the two node to be the children of a new node, and add the new node to the tree
			HuffmanNode pNode = new HuffmanNode(w1+w2);
			pNode.setlChild(i1);
			pNode.setrChild(i2);
			tree.add(pNode);
			tree.get(i1).setParent(tree.indexOf(pNode));
			tree.get(i2).setParent(tree.indexOf(pNode));}

3.2   根據Huffman 樹獲得Huffman編碼

從葉子節點開始網上遍歷Huffman樹,直到到達根節點,根據當前節點爲其父節點的左兒子還是右兒子確定這一位值是0還是1。最後將依次獲得的0,1字符串反轉獲得Huffman編碼。

代碼:

for(int i=0;i<list.size();i++){
			HuffmanNode node = tree.get(i);
			HuffmanNode pNode = tree.get(node.getParent());
			String code ="";
			while(true){
				if(pNode.getlChild()==tree.indexOf(node)){
					code = "0"+code;
				}
				else if(pNode.getrChild() == tree.indexOf(node)){
					code = "1"+code;
				}
				else {
					System.out.println("Tree Node Error!!!");
					return null;
				}
				node=pNode;
				if(node.getParent()!=-1)
					pNode=tree.get(node.getParent());
				else 
					break;
			}
			list.get(i).setCode(new String(code));
		}
3.3  文件頭設計

字符總數

Int 四個字節

字符種類數

Short 兩個字節

葉子節點

char字符  short 父節點 3個字節

非葉子節點

Short 左兒子 short 右兒子 short父節點 6字節

 

文件頭長度(單位: byte)

l= 9n

其中n 爲字符種類數。

3.4文件內容的編碼和寫入

	while((temp=reader.read())!=-1){ //!= EOF	
				// get the code from the code table
				String code = codeTable.get((char)temp);
				c++;
				if(c>=count/96){
					System.out.print("=");
					c=0;
				}
				try{
					StringBuilder codeString = new StringBuilder(code);
					outputStringBuffer.append(codeString);
					while(outputStringBuffer.length()>8){
						out.write(Short.parseShort(outputStringBuffer.substring(0, 8),2));
						outputStringBuffer.delete(0, 8);
					}
				} catch(Exception e){
					e.printStackTrace();
				}

			}

解碼

1. 流程圖


2.   數據結構

HuffmanNode:huffman樹中的節點信息。

Class{

Int parent;  //父節點

Int lChild; //左兒子

Int rChild;  //右兒子

Int weight; //權重

Char c; //對應的字符值


3.    程序關鍵點

3.1   重建Huffman樹。在文件頭中存放的原本就是Huffman樹的節點信息,所以重建Huffman樹是比較簡單的。

代碼:

	in = new DataInputStream(new FileInputStream(file));
			count = in.readInt();
			charNum = in.readShort();
			nodeNum = 2*charNum -1;
			//rebuild the huffman tree
			for(int i=0;i<charNum;i++){
				HuffmanNode node = new HuffmanNode((char)in.readByte());
				int parent = in.readShort();
				node.setParent(parent);
				tree.add(node);
			}
			
			for(int i=charNum;i<nodeNum;i++){
				HuffmanNode node = new HuffmanNode(' ');
				int l = in.readShort();
				int r = in.readShort();
				int p = in.readShort();
				node.setlChild(l);
				node.setrChild(r);
				node.setParent(p);
				tree.add(node);
			}

3.2 解碼

解碼流程圖

	while(true){
				while(buff.length()<32){
					temp = in.readInt();
					String codeString = Integer.toBinaryString(temp);
					while(codeString.length()<32){
						codeString='0'+codeString;
					}
					buff.append(codeString);
				}
				node = tree.get(tree.size()-1);
				dep = 0;
				while(!(node.getlChild()==-1&&node.getrChild()==-1)){
					if(dep>=buff.length()){
						System.out.println( "Buff overflow");
					}
					if(buff.charAt(dep)=='0'){
						node = tree.get(node.getlChild());
					}
					else if(buff.charAt(dep)=='1'){
						node = tree.get(node.getrChild());
					}
					else{
						System.out.println("Coding error");
					}
					dep++;
				}
				
				char c = node.getCH();
				num++;
				if(num>=n/99){
					System.out.print("=");
					num=0;
				}
				count++;
				if(count>=n){
					break;
				}
				charBuff+=c;
				if(charBuff.length()>256){
					writer.write(charBuff);
					charBuff="";
				}
				buff.delete(0, dep);
				
			}
			
		} catch(EOFException e){
			//just do nothing
		}
		catch(Exception e){
			e.printStackTrace();
		} finally{
			//there may be data released in the buff and charbuff, so we need to process them
			while(buff.length()>0){
				node = tree.get(tree.size()-1);
				dep = 0;
				while(!(node.getlChild()==-1&&node.getrChild()==-1)){
					if(dep>=buff.length()){
						break;
					}
					if(buff.charAt(dep)=='0'){
						node = tree.get(node.getlChild());
					}
					else if(buff.charAt(dep)=='1'){
						node = tree.get(node.getrChild());
					}
					else{
						System.out.println("Coding error");
						//return;
					}
					dep++;
				}
				char c = node.getCH();
				num++;
				if(num>=n/99){
					System.out.print("=");
					num=0;
				}
				count++;
				if(count>=n){
					break;
				}
				charBuff+=c;
				if(charBuff.length()>256){
					try {
						writer.write(charBuff);
					} catch (IOException e1) {
						// TODO Auto-generated catch block
						e1.printStackTrace();
					}
					charBuff="";
				}
				buff.delete(0, dep);
			}
			
			try {
				writer.write(charBuff);
				writer.close();
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} 
		}
		try{
			writer.close();
		} catch(IOException e){
			throw e;
		}

    完整工程就不放出了,以後再更新吧。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章