哈弗曼编码算法(简单链表法)
2011-12-26 23:24 java线程例子 阅读(219) 评论(0) 收藏 举报算法代码如下:
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),符合插入排序算法的时间复杂度.