/// <summary> /// Builds the prefix code tree. /// </summary> /// <returns>An optimal prefix code tree for given characters and their frequencies.</returns> private PrefixCodeTree BuildPrefixCodeTree() { // A MinPriorityQueue is used for selecting two nodes with minimal weights at a time MinPriorityQueue <PrefixCodeTree> pq = new MinPriorityQueue <PrefixCodeTree>(this.symbols.Length); // Add all leaf nodes to the priority queue separately for (int i = 0; i < this.symbols.Length; ++i) { PrefixCodeTree node = new PrefixCodeTree(); node.Symbol = this.symbols[i]; node.Weight = this.frequencies[i]; pq.Enqueue(node); } // Select two nodes with minimal weights and join them under a new node until a root tree is built while (pq.Size > 1) { PrefixCodeTree first = pq.Dequeue(); PrefixCodeTree second = pq.Dequeue(); PrefixCodeTree newNode = new PrefixCodeTree(); newNode.Symbol = null; newNode.Weight = first.Weight + second.Weight; newNode.Left = first; newNode.Right = second; pq.Enqueue(newNode); } // The last node in the queue is the root of the prefix code tree return(pq.Dequeue()); }
/// <summary> /// Traverses the code tree recursively and construct prefix codes at leaf nodes. /// </summary> /// <param name="tree">Prefix code tree.</param> /// <param name="path">Path to the current node from the tree root.</param> private void BuildCodes(PrefixCodeTree tree, string path) { if (tree.Symbol != null) { // This is a leaf node, a path has been found this.codes[tree.Symbol.Value] = path; } else { // Traverse left and right children with updated paths this.BuildCodes(tree.Left, path + "0"); this.BuildCodes(tree.Right, path + "1"); } }