演算法代碼如下:
public class HuffmanNode { public char Char { get; set; } public int Frequency { get; set; } //用於構造哈弗曼樹 internal HuffmanNode LeftChild { get; set; } internal HuffmanNode RightChild { get; set; } //用於構造鏈表 internal HuffmanNode NextSibling { get; set; } public string HuffmanCode {get;set;} public HuffmanNode(char Char,int Freq) { this.Char = Char; this.Frequency = Freq; } } public class HuffmanAlgorithms { /// <summary> /// 進行哈弗曼編碼,編碼過程中不改變Nodes節點,僅改變一些域。 /// </summary> /// <param name="Nodes"></param> public static void HuffmanCode(HuffmanNode[] Nodes) { if (Nodes == null || Nodes.Length == 0) { return; } #region 這個處理可以不要 if (Nodes.Length == 1) { Nodes[0].HuffmanCode = "0"; return; } if (Nodes.Length == 2) { Nodes[0].HuffmanCode = "0"; Nodes[1].HuffmanCode = "1"; return; } #endregion HuffmanNode theHead = null; //用插入排序演算法,建立升序節點鏈表O(n^2) for (int i = 0; i < Nodes.Length;i++ ) { InsertNode(ref theHead, Nodes[i]); } //建立Huffman樹,採用貪婪法,每次取鏈表中最小的兩個(前兩個). HuffmanNode theTmp1 = null; HuffmanNode theTmp2 = null; theTmp1 = theHead; if (theHead != null) { theTmp2 = theHead.NextSibling; } //鏈表裡有兩個則操作,則繼續建樹,否則樹建立完成,退出迴圈.O(n*lgn) while (theTmp1 != null && theTmp2 != null) { //建立一個內節點包含當前鏈表中兩個最小元素,這個節點的頻率是這兩個元素的頻率之和. HuffmanNode theParent = new HuffmanNode('\0', theTmp1.Frequency + theTmp2.Frequency); theParent.LeftChild = theTmp1; theParent.RightChild = theTmp2; //除掉當前兩個最小元素,並插入建立節點. theHead = theTmp2.NextSibling; //將建立立的內節點插入當前鏈表. InsertNode(ref theHead, theParent); theTmp1 = theHead; if (theHead != null) { theTmp2 = theHead.NextSibling; } } //採用樹的先序遍曆進行編碼.結果存放在節點的編碼域中.o(n) HuffmanCode(theHead, ""); //清理臨時域,保證記憶體釋放.o(n) foreach (var node in Nodes) { node.LeftChild = null; node.NextSibling = null; node.RightChild = null; } } /// <summary> /// 利用樹的先序遍曆進行編碼,實際上有效都是葉子節點,葉子節點都在Nodes數組中。 /// </summary> /// <param name="ANode"></param> /// <param name="StrCode"></param> private static void HuffmanCode(HuffmanNode ANode, string StrCode) { if (ANode != null) { ANode.HuffmanCode = StrCode; if (ANode.LeftChild != null) { HuffmanCode(ANode.LeftChild, StrCode + "0"); } if (ANode.RightChild != null) { HuffmanCode(ANode.RightChild, StrCode + "1"); } } } /// <summary> /// 將節點Node插入到鏈表AHead中去,並升序排列. /// </summary> /// <param name="AHead"></param> /// <param name="Node"></param> private static void InsertNode(ref HuffmanNode AHead,HuffmanNode Node) { HuffmanNode theTmp1 = AHead; HuffmanNode theTmp2 = null; while (theTmp1 != null && theTmp1.Frequency < Node.Frequency) { theTmp2 = theTmp1; theTmp1 = theTmp1.NextSibling; } if (theTmp2 == null) { AHead = Node; } else { theTmp2.NextSibling = Node; } Node.NextSibling = theTmp1; } }
PS:這個演算法利用最小堆效率要高些,在O(nlgn),這裡的演算法還是O(n^2),符合插入排序演算法的時間複雜度.