前言:最近項目上一直沒事干,感覺無聊到了極點,給自己找點事做,補一下大學沒有完成的事情,寫一個huffman算法Java版的,學校里面寫過c語言的。
因為很久沒搞數據結構和算法這方面了(現在搞Java web,真心感覺沒什么挑戰啊),代碼寫的一般,邊聽歌邊寫,3小時,不知道為什么現在效率這么低,寫習慣了
xml配置,感覺純寫算法代碼手生的緊,悲呼唉哉!
1、哈夫曼樹:
給定n個權值作為n個葉子結點,構造一棵二叉樹,若帶權路徑長度達到最小,稱這樣的二叉樹為最優二叉樹,也稱為哈夫曼樹(Huffman tree)
2、生成過程:
1. 在n個權值里面首先尋找最小的兩個權值作為子節點,開始生成第一棵子樹;
2.將新子樹的父節點作為一個新的權值與剩余的權值繼續做比較,選出最小的兩個權值繼續構造新子樹;
3.依次進行,直到最后一棵子樹生成;
4.這時候,最后一棵子樹的根節點就是整個哈夫曼樹的根節點,從此根節點開始遍歷,就能遍歷完整個哈夫曼樹。
3、圖形表示:
假設有6個權值:1、2、3、4、5、6,生成哈夫曼樹的過程如下:
依次下去...
這樣,最終得到的父節點21就是哈夫曼樹的根節點,遍歷樹的話,
c/c++就是:root->left root->right就可以通過遞歸的方式從root節點訪問到最后一個子節點。
Java就是: root.left root.right通過遞歸從root訪問到最后一個子節點。
當然,二叉樹的遍歷不止遞歸一種方法,遞歸是最有效率的一種,還可以通過數據結構里面堆/棧的方式進行遍歷。
下面是我寫的實現哈夫曼樹的Java代碼(為了完成功能,絕壁不是優秀的,但可以方便看懂)
注:儲存權值使用了List列表,隨時增或者刪方便一點。
1 import java.util.ArrayList; 2 import java.util.List; 3 4 class Node 5 { 6 int weight; 7 Node left,right,parent; 8 public Node(int weight) 9 { 10 this.weight=weight; 11 } 12 } 13 public class Huffman { 14 private static List<Node> list=new ArrayList<Node>(); 15 public static Node root; 16 public void insert(Node node) 17 { 18 //按照插入排序的方式將節點有序插入list 19 if(list.size()==0){ 20 list.add(node); 21 return; 22 } 23 int size=list.size(); 24 for(int i=0;i<size;) 25 { 26 if(list.get(i).weight<node.weight){ 27 i++; 28 if(i>=list.size()) 29 list.add(node); 30 } 31 else 32 { 33 //交換位置 34 list.add(list.get(list.size()-1)); 35 for(int j=list.size()-1;j>i;j--) 36 { 37 list.set(j, list.get(j-1)); 38 } 39 list.set(i, node);//插入新數據 40 return; 41 } 42 43 } 44 45 } 46 public Node createTree(Node n1,Node n2) 47 { 48 //返回新子樹的父節點 49 Node parentNode=new Node(0); 50 parentNode.weight=n1.weight+n2.weight; 51 parentNode.left=n1; 52 parentNode.right=n2; 53 n1.parent=parentNode; 54 n2.parent=parentNode; 55 return parentNode; 56 } 57 public void run(List<Node> list) 58 { 59 int length=list.size(); 60 while(length!=0) 61 { 62 if(length==1){ 63 root=list.get(0); 64 return; 65 } 66 if(length==2){ 67 root=createTree(list.get(0),list.get(1)); 68 return; 69 } 70 Node n1=list.get(0); 71 Node n2=list.get(1); 72 Node newNode=createTree(n1,n2); 73 for(int i=0;i<length-2;i++) 74 { 75 //轉移數據 76 list.set(i, list.get(i+2)); 77 } 78 list.remove(length-1); 79 list.remove(length-2); 80 insert(newNode); 81 length=list.size(); 82 } 83 84 } 85 public void display(Node node) 86 { 87 if(node!=null) 88 { 89 display(node.left); 90 System.out.print(node.weight+"\t"); 91 display(node.right); 92 } 93 } 94 public void drawTree(Node node) 95 { 96 if(node!=null) 97 { 98 //中序遍歷,打算打印樹形狀,有些麻煩,后面改進 99 // if(node.parent!=null&&node.parent.left==node) 100 // System.out.print("/"); 101 // if(node.parent!=null&&node.parent.right==node) 102 // System.out.print("\\"); 103 System.out.print(node.weight+"\t"); 104 drawTree(node.left); 105 drawTree(node.right); 106 } 107 } 108 public static void main(String[] args) 109 { 110 Huffman hf=new Huffman(); 111 hf.insert(new Node(1)); 112 hf.insert(new Node(2)); 113 hf.insert(new Node(3)); 114 hf.insert(new Node(4)); 115 hf.insert(new Node(5)); 116 hf.insert(new Node(6)); 117 hf.run(list); 118 System.out.println("前序遍歷"); 119 hf.display(root); 120 System.out.println("\n中序遍歷"); 121 hf.drawTree(root); 122 } 123 }
執行結果:
后面,將寫通過哈夫曼解析具體報文。