Построение дерева "Код Хаффмана" - C#
Формулировка задачи:
Доброго времени суток, есть коллекция символов с числом их повторений, как реализовать этот шаг:
Если я правильно понимаю, коллекция состоит, например: h - 1, e - 1, o - 1, l - 2. Берутся первые два символа объединяются и в итоге получается след.: he - 2, o - 1, l - 2, и так до тех пор пока не останется одна ячейка: helo - 5. Дальше встает вопрос,что каждому символу необходима присвоить значение 1 или 0,когда это делать?
Выбираются два свободных узла дерева с наименьшими весами.
Создается их родитель с весом, равным их суммарному весу. <- Этот интересует
Кто-нибудь подскажет?
Решение задачи: «Построение дерева "Код Хаффмана"»
textual
Листинг программы
public class HuffmanTree
{
private List<Node> nodes = new List<Node>();
public Node Root { get; set; }
public Dictionary<char, int> Frequencies = new Dictionary<char, int>();
public void Build(string source)
{
for (int i = 0; i < source.Length; i++)
{
if (!Frequencies.ContainsKey(source[i]))
{
Frequencies.Add(source[i], 0);
}
Frequencies[source[i]]++;
}
foreach (KeyValuePair<char, int> symbol in Frequencies)
{
nodes.Add(new Node() { Symbol = symbol.Key, Frequency = symbol.Value });
}
while (nodes.Count > 1)
{
List<Node> orderedNodes = nodes.OrderBy(node => node.Frequency).ToList<Node>();
if (orderedNodes.Count >= 2)
{
// Take first two items
List<Node> taken = orderedNodes.Take(2).ToList<Node>();
// Create a parent node by combining the frequencies
Node parent = new Node()
{
Symbol = '*',
Frequency = taken[0].Frequency + taken[1].Frequency,
Left = taken[0],
Right = taken[1]
};
nodes.Remove(taken[0]);
nodes.Remove(taken[1]);
nodes.Add(parent);
}
this.Root = nodes.FirstOrDefault();
}
}
public BitArray Encode(string source)
{
List<bool> encodedSource = new List<bool>();
for (int i = 0; i < source.Length; i++)
{
List<bool> encodedSymbol = this.Root.Traverse(source[i], new List<bool>());
encodedSource.AddRange(encodedSymbol);
}
BitArray bits = new BitArray(encodedSource.ToArray());
return bits;
}
public string Decode(BitArray bits)
{
Node current = this.Root;
string decoded = "";
foreach(bool bit in bits){
if (bit)
{
if (current.Right != null)
{
current = current.Right;
}
}
else
{
if(current.Left != null)
{
current = current.Left;
}
}
if (IsLeaf(current))
{
decoded += current.Symbol;
current = this.Root;
}
}
return decoded;
}
public bool IsLeaf(Node node)
{
return (node.Left == null && node.Right == null);
}
}
public class Node
{
public char Symbol { get; set; }
public int Frequency { get; set; }
public Node Right { get; set; }
public Node Left { get; set; }
public List<bool> Traverse(char symbol,List<bool> data)
{
// Leaf
if (Right == null && Left == null)
{
if (symbol.Equals(this.Symbol))
{
return data;
}
else
{
return null;
}
}
else
{
List<bool> left = null;
List<bool> right = null;
if (Left != null)
{
List<bool> leftPath = new List<bool>();
leftPath.AddRange(data);
leftPath.Add(false);
left = Left.Traverse(symbol, leftPath);
}
if (Right != null)
{
List<bool> rightPath = new List<bool>();
rightPath.AddRange(data);
rightPath.Add(true);
right = Right.Traverse(symbol, rightPath);
}
if (left != null)
{
return left;
}
else
{
return right;
}
}
}
}
class Program
{
static void Main()
{
HuffmanTree huffmanTree = new HuffmanTree();
string input;
using (StreamReader fileIn = new StreamReader(@""))
{
input = fileIn.ReadToEnd();
}
huffmanTree.Build(input);
BitArray encoded = huffmanTree.Encode(input);
string decoded = huffmanTree.Decode(encoded);
Console.WriteLine("Decoded: " + decoded);
Console.Write("Encoded: ");
using (StreamWriter file =
new StreamWriter(@""))
{
foreach (bool bit in encoded)
{
file.Write((bit? 1 : 0) + "");
Console.Write((bit ? 1 : 0) + "");
}
Console.WriteLine();
}
}
}