什么是赫夫曼树?
赫夫曼树(Huffman Tree)是指给定N个权值作为N个叶子结点,构造一棵二叉树,若该树的带权路径长度达到最小。哈夫曼树(也称为最优二叉树)是带权路径长度最短的树,权值较大的结点离根较近。
public class HNode<T>
{
public HNode()
{
data = default(T);
weight = 0;
leftNode = null;
rightNode = null;
}
public HNode(T val)
{
data = val;
weight = 0;
leftNode = null;
rightNode = null;
}
/// <summary>
/// 权重
/// </summary>
public int weight { get; set; }
/// <summary>
/// 内容
/// </summary>
public T data { get; set; }
/// <summary>
/// 左树
/// </summary>
public HNode<T> leftNode { get; set; }
/// <summary>
/// 右树
/// </summary>
public HNode<T> rightNode { get; set; }
}
/// <summary>
/// 赫夫曼树
/// </summary>
/// <typeparam name="T"></typeparam>
public class HTree<T>
{
/// <summary>
/// 树的头结点
/// </summary>
public HNode<T> head { get; set; }
/// <summary>
/// 构造函数
/// </summary>
/// <param name="val"></param>
public HTree(T val)
{
head = new HNode<T>(val);
}
public HTree()
{
head = new HNode<T>();
}
/// <summary>
/// 构建树结构
/// </summary>
/// <param name="list"></param>
public void build(List<T> list)
{
//判断是否能构建树结构
if (list == null || list.Count <2)
throw new ArgumentOutOfRangeException("params error");
//分组统计
List<HNode<T>> nodes = new List<HNode<T>>();
nodes.AddRange(from m in list group m by m into g
select new HNode<T> { data = g.Key,weight = g.Count()});
//排序
nodes = nodes.OrderBy(i => i.weight).ToList();
for (int i =1; i< nodes.Count; i++)
{
HNode<T> parentNode = new HNode<T>();
if (i == 1)
{
//先取最小的两个节点
parentNode.leftNode = nodes[0];
parentNode.rightNode = nodes[1];
parentNode.weight = nodes[0].weight + nodes[1].weight;
}
else
{
//依次取节点构建树
if (head.weight >= nodes[i].weight)
{
parentNode.leftNode = head;
parentNode.rightNode = nodes[i];
}
else
{
parentNode.rightNode = head;
parentNode.leftNode = nodes[i];
}
parentNode.weight = head.weight + nodes[i].weight;
}
head = parentNode;
}
}
/// <summary>
/// 先序遍历
/// </summary>
/// <param name="index"></param>
public void PreorderTraversal(HNode<T> node)
{
//递归的终止条件
if (head == null)
{
Console.WriteLine("当前树为空");
return;
}
if (node != null)
{
if(node.data != null)
Console.WriteLine($"{node.data} {node.weight}");
PreorderTraversal(node.leftNode);
PreorderTraversal(node.rightNode);
}
}
}
测试代码:
List<string> list = new List<string>() { "A","B", "B", "C", "C", "C", "D", "D", "D", "D", "E", "E", "E", "E", "E" };
HTree<string> tree = new HTree<string>();
tree.build(list);
tree.PreorderTraversal(tree.head);
打印结果:
A 1
B 2
C 3
D 4
E 5
用这个例子现在我们看下构建的二叉树结构: