樹論之哈夫曼樹

樹論之哈夫曼樹

給定N個權值作爲N個葉子結點,構造一棵二叉樹,若該樹的帶權路徑長度達到最小,稱這樣的二叉樹爲最優二叉樹,也稱爲哈夫曼樹(Huffman Tree)。哈夫曼樹是帶權路徑長度最短的樹,權值較大的結點離根較近。

哈夫曼樹構建

  • 哈夫曼樹的節點都是葉子節點
  • 根據哈夫曼樹的特點,構建樹最好的選擇當然是從底層開始。
  • 從底層開始構建時應該選擇權重最小的2個值開始構建

哈夫曼樹的用途

  • 哈夫曼編碼是最優前綴碼 因此可用於加密解密
  • 文件壓縮解壓

代碼再現

public class HuffmanTree {

	List<TreeNode> leafs;
	
	Map<Character,Integer> weights;
	
	TreeNode rootNode;
	
	Map<Character,String> codeMap;
	Map<String,Character> decodeMap;
	
	private HuffmanTree(Map<Character,Integer> weights) {
		this.weights = weights;
		leafs = new ArrayList<>();
		codeMap = new HashMap<>();
		decodeMap = new HashMap<>();
		initTree();
	}
	
	public void initTree(){
		PriorityQueue<TreeNode> queue = new PriorityQueue();
		Character[] keys =weights.keySet().toArray(new Character[0]);
		weights.keySet().toArray(keys);
		for(Character chr:keys){
			TreeNode treeNode = new TreeNode(chr.toString(),weights.get(chr).intValue());
			queue.add(treeNode);
			leafs.add(treeNode);
		}
		
		for(int n=1;n <= keys.length-1;n++) {
			TreeNode left = queue.poll();
			TreeNode right = queue.poll();
			
			TreeNode newNode = new TreeNode(left.chars+right.chars,left.freq+right.freq);
			newNode.left = left ; 
			newNode.right = right;
			left.parent = newNode;
			right.parent = newNode;
			queue.add(newNode);
		}
		rootNode = queue.poll();
	}
	
	public String encode(String str) {
		StringBuilder sbr = new StringBuilder();
		for(Character c : str.toCharArray()) {
			sbr.append(codeMap.get(c));
		}
		System.out.println(str+"=="+sbr.toString());
		return sbr.toString();
	}
	public void decode(String str) {
		StringBuilder sbr = new StringBuilder();
		StringBuilder temp = new StringBuilder();
		for(Character c : str.toCharArray()) {
			temp.append(c);
			if(decodeMap.containsKey(temp.toString())) {
				sbr.append(decodeMap.get(temp.toString()));
				temp = new StringBuilder();
			}
		}
		System.out.println(str+"=="+sbr.toString());
	}
	
	public void codes(){
		for(int i=0;i<leafs.size();i++) {
			TreeNode current = leafs.get(i);
			Character c = current.chars.charAt(0);
			String codes = "";
		     while(current.parent!=null) {
		    	 if(current == current.parent.left) {
		    		 codes="0"+codes;
		    	 }else {
		    		 codes="1"+codes;
		    	 }
		    	 current = current.parent;
		     }
		     System.out.println(c+"::"+codes);
		     codeMap.put(c, codes);
		     decodeMap.put(codes, c);
		}
	}
	
	public static void main(String[] args) {
		Map<Character,Integer> weights =new HashMap<Character,Integer>();
		weights.put('a', 3);
		weights.put('b', 24);
		weights.put('c', 6);
		weights.put('d', 20);
		weights.put('e', 34);
		weights.put('f', 4);
		weights.put('g', 12);
		HuffmanTree huffman = new HuffmanTree(weights);
		huffman.codes();
		huffman.decode(huffman.encode("afeddacbad"));
	}
	
	static class TreeNode implements Comparable<TreeNode>{
		private String chars;//節點字符
		private int freq;//權重
		private TreeNode left;//左節點
		private TreeNode right;//右節點
		private TreeNode parent;//父節點
		
		private TreeNode(String chars,int freq) {
			this.chars = chars;
			this.freq = freq;
		}

		@Override
		public int compareTo(TreeNode o) {
			return this.freq-o.freq;
		}
	}
}
發佈了42 篇原創文章 · 獲贊 6 · 訪問量 6398
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章