/// <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); }
protected override IEnumerable <KeyValuePair <T, BitPath> > ListValues(BitPath prefix) { yield return(new KeyValuePair <T, BitPath>(value, prefix)); }
/// <summary> /// Recursively searches through all child nodes, and returns all values mapped to their respective bit sequences. /// </summary> /// <param name="prefix">Sequence of bits used to get to the current node. Every level of recursion on <see cref="Path"/> nodes appends a 0/1 bit, <see cref="Leaf"/> nodes return the final value.</param> protected abstract IEnumerable <KeyValuePair <T, BitPath> > ListValues(BitPath prefix);