using System; using System.Collections.Generic; namespace Huffman_Encoding { public class PriorityQueue where T : IComparable { protected List LstHeap = new List(); public virtual int Count { get { return LstHeap.Count; } } public virtual void Add(T val) { LstHeap.Add(val); SetAt(LstHeap.Count - 1, val); UpHeap(LstHeap.Count - 1); } public virtual T Peek() { if (LstHeap.Count == 0) { throw new IndexOutOfRangeException("Peeking at an empty priority queue"); } return LstHeap[0]; } public virtual T Pop() { if (LstHeap.Count == 0) { throw new IndexOutOfRangeException("Popping an empty priority queue"); } T valRet = LstHeap[0]; SetAt(0, LstHeap[LstHeap.Count - 1]); LstHeap.RemoveAt(LstHeap.Count - 1); DownHeap(0); return valRet; } protected virtual void SetAt(int i, T val) { LstHeap[i] = val; } protected bool RightSonExists(int i) { return RightChildIndex(i) < LstHeap.Count; } protected bool LeftSonExists(int i) { return LeftChildIndex(i) < LstHeap.Count; } protected int ParentIndex(int i) { return (i - 1) / 2; } protected int LeftChildIndex(int i) { return 2 * i + 1; } protected int RightChildIndex(int i) { return 2 * (i + 1); } protected T ArrayVal(int i) { return LstHeap[i]; } protected T Parent(int i) { return LstHeap[ParentIndex(i)]; } protected T Left(int i) { return LstHeap[LeftChildIndex(i)]; } protected T Right(int i) { return LstHeap[RightChildIndex(i)]; } protected void Swap(int i, int j) { T valHold = ArrayVal(i); SetAt(i, LstHeap[j]); SetAt(j, valHold); } protected void UpHeap(int i) { while (i > 0 && ArrayVal(i).CompareTo(Parent(i)) > 0) { Swap(i, ParentIndex(i)); i = ParentIndex(i); } } protected void DownHeap(int i) { while (i >= 0) { int iContinue = -1; if (RightSonExists(i) && Right(i).CompareTo(ArrayVal(i)) > 0) { iContinue = Left(i).CompareTo(Right(i)) < 0 ? RightChildIndex(i) : LeftChildIndex(i); } else if (LeftSonExists(i) && Left(i).CompareTo(ArrayVal(i)) > 0) { iContinue = LeftChildIndex(i); } if (iContinue >= 0 && iContinue < LstHeap.Count) { Swap(i, iContinue); } i = iContinue; } } } internal class HuffmanNode : IComparable { internal HuffmanNode(double probability, T value) { Probability = probability; LeftSon = RightSon = Parent = null; Value = value; IsLeaf = true; } internal HuffmanNode(HuffmanNode leftSon, HuffmanNode rightSon) { LeftSon = leftSon; RightSon = rightSon; Probability = leftSon.Probability + rightSon.Probability; leftSon.IsZero = true; rightSon.IsZero = false; leftSon.Parent = rightSon.Parent = this; IsLeaf = false; } internal HuffmanNode LeftSon { get; set; } internal HuffmanNode RightSon { get; set; } internal HuffmanNode Parent { get; set; } internal T Value { get; set; } internal bool IsLeaf { get; set; } internal bool IsZero { get; set; } internal int Bit { get { return IsZero ? 0 : 1; } } internal bool IsRoot { get { return Parent == null; } } internal double Probability { get; set; } public int CompareTo(object obj) { return -Probability.CompareTo(((HuffmanNode) obj).Probability); } } public class Huffman where T : IComparable { private readonly Dictionary> _leafDictionary = new Dictionary>(); private readonly HuffmanNode _root; public Huffman(IEnumerable values) { var counts = new Dictionary(); var priorityQueue = new PriorityQueue>(); int valueCount = 0; foreach (T value in values) { if (!counts.ContainsKey(value)) { counts[value] = 0; } counts[value]++; valueCount++; } foreach (T value in counts.Keys) { var node = new HuffmanNode((double) counts[value] / valueCount, value); priorityQueue.Add(node); _leafDictionary[value] = node; } while (priorityQueue.Count > 1) { HuffmanNode leftSon = priorityQueue.Pop(); HuffmanNode rightSon = priorityQueue.Pop(); var parent = new HuffmanNode(leftSon, rightSon); priorityQueue.Add(parent); } _root = priorityQueue.Pop(); _root.IsZero = false; } public List Encode(T value) { var returnValue = new List(); Encode(value, returnValue); return returnValue; } public void Encode(T value, List encoding) { if (!_leafDictionary.ContainsKey(value)) { throw new ArgumentException("Invalid value in Encode"); } HuffmanNode nodeCur = _leafDictionary[value]; var reverseEncoding = new List(); while (!nodeCur.IsRoot) { reverseEncoding.Add(nodeCur.Bit); nodeCur = nodeCur.Parent; } reverseEncoding.Reverse(); encoding.AddRange(reverseEncoding); } public List Encode(IEnumerable values) { var returnValue = new List(); foreach (T value in values) { Encode(value, returnValue); } return returnValue; } public T Decode(List bitString, ref int position) { HuffmanNode nodeCur = _root; while (!nodeCur.IsLeaf) { if (position > bitString.Count) { throw new ArgumentException("Invalid bitstring in Decode"); } nodeCur = bitString[position++] == 0 ? nodeCur.LeftSon : nodeCur.RightSon; } return nodeCur.Value; } public List Decode(List bitString) { int position = 0; var returnValue = new List(); while (position != bitString.Count) { returnValue.Add(Decode(bitString, ref position)); } return returnValue; } } internal class Program { private const string Example = "this is an example for huffman encoding"; private static void Main() { var huffman = new Huffman(Example); List encoding = huffman.Encode(Example); List decoding = huffman.Decode(encoding); var outString = new string(decoding.ToArray()); Console.WriteLine(outString == Example ? "Encoding/decoding worked" : "Encoding/Decoding failed"); var chars = new HashSet(Example); foreach (char c in chars) { encoding = huffman.Encode(c); Console.Write("{0}: ", c); foreach (int bit in encoding) { Console.Write("{0}", bit); } Console.WriteLine(); } Console.ReadKey(); } } }