/// <summary> /// Converts a <see cref="Dictionary{TKey, TValue}"/>, which maps <see cref="BitPath"/> instances to their assigned symbols, into a <see cref="HuffmanNode{T}"/>. /// </summary> /// <param name="paths">Mapping of bit paths to the symbols. All possible paths must terminate in a symbol.</param> /// <exception cref="ArgumentException">Thrown when the <paramref name="paths"/> dictionary is missing a possible path, or a path is unreachable.</exception> public static HuffmanNode <T> FromSymbolPaths(Dictionary <BitPath, T> paths) { int longestBranch = paths.Select(path => (int)path.Key.Length).DefaultIfEmpty(0).Max(); int totalLeaves = 0; HuffmanNode <T> GenerateNodeBranch(in BitPath prefix, bool nextBit) { BitPath branch = prefix.Add(nextBit); if (paths.TryGetValue(branch, out T symbol)) { ++totalLeaves; return(new HuffmanNode <T> .Leaf(symbol)); } else if (branch.Length >= longestBranch) { return(new HuffmanNode <T> .Dummy()); // TODO hack to "support" Huffman trees with missing branches } else { return(GenerateNode(branch)); } } HuffmanNode <T> GenerateNode(in BitPath stream) { return(new HuffmanNode <T> .Path(GenerateNodeBranch(stream, false), GenerateNodeBranch(stream, true))); } HuffmanNode <T> root = GenerateNode(new BitPath()); if (totalLeaves != paths.Count) { throw new ArgumentException("Impossible symbol paths, " + (paths.Count - totalLeaves) + " symbol(s) could not be reached.", nameof(paths)); } return(root); }
public Path(HuffmanNode <T> left, HuffmanNode <T> right) { this.left = left; this.right = right; }
public void Deconstruct(out HuffmanNode <T> node, out int frequency) { node = Node; frequency = Frequency; }
public Freq(HuffmanNode <T> node, int frequency) { this.Node = node; this.Frequency = frequency; }