/// <summary> insert node into sorted forest while preserving ordering </summary> private static void SortInsert(List <HuffmannTree> forest, HuffmannTree node) { if (forest.Count == 0) { forest.Add(node); return; } int i = 0; while (NodeCompare(forest[i], node)) { i++; if (i == forest.Count) { // node is bigger or equal to the whole forest, it is supposed to be last forest.Add(node); return; } } // forest[i] > node, we want to insert node before i-th forest's node forest.Insert(i, node); }
/// <summary> returns bool, whether node1 <= node2 </summary> private static bool NodeCompare(HuffmannTree node1, HuffmannTree node2) { if (node1.Weight != node2.Weight) { return(node1.Weight < node2.Weight); } else { if (node1.IsLeaf() && node2.IsLeaf()) { return(node1.Symbol <= node2.Symbol); } else if (node1.IsLeaf() && !node2.IsLeaf()) { // leaves are lighter then inner nodes return(true); } else if (!node1.IsLeaf() && node2.IsLeaf()) { return(false); } else { // two inner nodes with the same Weight return(true); } } }
static void Main(string[] args) { // check cmd args if (args.Length != 1 || args[0] == "") { Console.WriteLine("Argument Error"); return; } try { FileStream fs = new FileStream(args[0], FileMode.Open); HuffmannTree huffmannTree = HuffmannTree.BuildTree(fs); FileStream outputFile = new FileStream(args[0] + ".huff", FileMode.Create); outputFile.Write(new byte[] { 0x7B, 0x68, 0x75, 0x7C, 0x6D, 0x7D, 0x66, 0x66 }); // write header huffmannTree.PrintTree(outputFile, true); } catch (Exception ex) { if (ex is IOException || ex is UnauthorizedAccessException) { Console.WriteLine("File Error"); return; } throw; } }
public static void Encode(Stream inputStream, Stream outputStream) { HuffmannTree huffmannTree = HuffmannTree.BuildTree(inputStream); outputStream.Write(new byte[] { 0x7B, 0x68, 0x75, 0x7C, 0x6D, 0x7D, 0x66, 0x66 }, 0, 8); // write header huffmannTree.PrintTree(outputStream, true); outputStream.Write(new byte[] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, 0, 8); // huffmann tree representation is ended with 8 bytes of zeros inputStream.Position = 0; EncodeData(inputStream, outputStream, huffmannTree); }
void BuildPathsDictionary(HuffmannTree node, List <byte> path) { if (node.IsLeaf()) { paths.Add((char)node.Symbol, path.ToArray()); } else { path.Add(0); BuildPathsDictionary(node.Left, path); path.RemoveAt(path.Count - 1); path.Add(1); BuildPathsDictionary(node.Right, path); path.RemoveAt(path.Count - 1); } }
/// <summary>Build huffmann tree from byte frequency array</summary> public static HuffmannTree BuildTree(UInt64[] freq) { List <HuffmannTree> forest = new List <HuffmannTree>(); for (int i = 0; i < 256; i++) { if (freq[i] > 0) { forest.Add(new HuffmannTree { Left = null, Right = null, Symbol = (byte)i, Weight = freq[i] }); } } if (forest.Count == 0) { return(null); } // initial leaf ordering forest = forest.OrderBy(node => node.Weight).ThenBy(node => node.Symbol).ToList(); while (forest.Count > 1) { HuffmannTree parent = new HuffmannTree(); parent.Left = forest[0]; parent.Right = forest[1]; parent.Weight = parent.Left.Weight + parent.Right.Weight; forest.RemoveRange(0, 2); SortInsert(forest, parent); } HuffmannTree huffmannTree = forest[0]; huffmannTree.paths = new Dictionary <char, byte[]>(); huffmannTree.BuildPathsDictionary(); return(huffmannTree); }
public static void EncodeData(Stream inputStream, Stream outputStream, HuffmannTree huffmannTree) { int b; BitWriter writer = new BitWriter(outputStream); while ((b = inputStream.ReadByte()) != -1) { byte[] path = huffmannTree.paths[(char)b]; /* * foreach (var bit in path) * { * Console.Write(bit); * } * Console.WriteLine(); */ writer.WriteBits(path); } writer.Flush(); }