数据结构入门学习系列-10(霍夫曼树)
来源:互联网 发布:网络信息安全实施方案 编辑:程序博客网 时间:2024/05/22 01:28
什么是哈夫曼树呢?
哈夫曼树是一种带权路径长度最短的二叉树,也称为最优二叉树。下面用一幅图来说明。
它们的带权路径长度分别为:
图a: WPL=5*2+7*2+2*2+13*2=54
图b: WPL=5*3+2*3+7*2+13*1=48
可见,图b的带权路径长度较小,我们可以证明图b就是哈夫曼树(也称为最优二叉树)。
一般可以按下面步骤构建:
1,将所有左,右子树都为空的作为根节点。
2,在森林中选出两棵根节点的权值最小的树作为一棵新树的左,右子树,且置新树的附加根节点的权值为其左,右子树上根节点的权值之和。注意,左子树的权值应小于右子树的权值。
3,从森林中删除这两棵树,同时把新树加入到森林中。
4,重复2,3步骤,直到森林中只有一棵树为止,此树便是哈夫曼树。
下面是构建哈夫曼树的图解过程:
利用哈夫曼树求得的用于通信的二进制编码称为哈夫曼编码。树中从根到每个叶子节点都有一条路径,对路径上的各分支约定指向左子树的分支表示”0”码,指向右子树的分支表示“1”码,取每条路径上的“0”或“1”的序列作为各个叶子节点对应的字符编码,即是哈夫曼编码。
就拿上图例子来说:
A,B,C,D对应的哈夫曼编码分别为:111,10,110,0
用图说明如下:
记住,设计电文总长最短的二进制前缀编码,就是以n个字符出现的频率作为权构造一棵哈夫曼树,由哈夫曼树求得的编码就是哈夫曼编码。
算法实现:
namespace HuffTree.CSharp{ class Program { static void Main(string[] args) { //四个叶子节点 int leafNum = 4; //赫夫曼树的节点总数 int totalNodes = 2 * leafNum - 1; //各叶子节点的权值 int[] weight = new int[] { 5,7,2,13}; //各叶子节点的值 string[] alphabet = new string[] { "A","B","C","D"}; //初始化赫夫曼树 HuffmanTree[] huffmanTree = new HuffmanTree[totalNodes].Select(p => new HuffmanTree() { }).ToArray(); //构建赫夫曼树 HuffmanTreeBLL.Create(huffmanTree,leafNum,weight); //赫夫曼编码 string[] huffmanCode = HuffmanTreeBLL.Coding(huffmanTree,leafNum); //打印结果 PrintResult(alphabet,huffmanTree,huffmanCode,leafNum); Console.ReadKey(); } /// <summary> /// 打印结果 /// </summary> /// <param name="alphabet"></param> /// <param name="huffmanTree"></param> /// <param name="huffmanCode"></param> /// <param name="leafNum"></param> private static void PrintResult(string[] alphabet,HuffmanTree[] huffmanTree,string[] huffmanCode,int leafNum) { if (alphabet.Count() < 1 || huffmanTree.Count() < 1 || huffmanCode.Count() < 1) return; for (int i = 0; i < leafNum; i++) { Console.WriteLine("字符:{0},权重值:{1},赫夫曼编码:{2}",alphabet[i],huffmanTree[i].Weight,huffmanCode[i]); } } }}namespace DS.BLL{ /// <summary> /// 描述:赫夫曼树操作类 /// 作者:鲁宁 /// 时间:2013/9/17 18:14:33 /// </summary> public class HuffmanTreeBLL { /// <summary> /// 构建赫夫曼树 /// 思路:一步一步向上搭建 /// </summary> /// <param name="huffmanTree">待操作的赫夫曼树</param> /// <param name="leafNum">叶节点数量</param> /// <param name="weight">节点权重值</param> /// <returns>构建好的赫夫曼树</returns> public static HuffmanTree[] Create(HuffmanTree[] huffmanTree, int leafNum, int[] weight) { //获取赫夫曼树结点总数 int totalNodes = 2 * leafNum - 1; InitLeafNode(huffmanTree,leafNum,weight); //构造赫夫曼树(4个节点只需要3步就可以完成构建) for (int i = leafNum; i < totalNodes; i++) { //获取权重最小的两个叶子节点的下标 int minIndex1 = -1; int minIndex2 = -1; SelectNode(huffmanTree,i,ref minIndex1,ref minIndex2); huffmanTree[minIndex1].Parent = i; huffmanTree[minIndex2].Parent = i; huffmanTree[i].Left = minIndex1; huffmanTree[i].Right = minIndex2; huffmanTree[i].Weight = huffmanTree[minIndex1].Weight + huffmanTree[minIndex2].Weight; } return huffmanTree; } /// <summary> /// 赫夫曼编码 /// 思路:左子树为0,右子树为1,对应的编码后的规则是:从根节点到子节点 /// </summary> /// <param name="huffmanTree">待操作的赫夫曼树</param> /// <param name="leafNum">叶子节点的数量</param> /// <returns>赫夫曼编码</returns> public static string[] Coding(HuffmanTree[] huffmanTree, int leafNum) { string[] huffmanCode= new string[leafNum]; //当前节点下标 int current = 0; //父节点下标 int parent = 0; for (int i = 0; i < leafNum; i++) { string codeTemp = string.Empty; current = i; //第一次获取最左节点 parent = huffmanTree[current].Parent; while (parent != 0) { if (huffmanTree[parent].Left == current) codeTemp += "0"; else codeTemp += "1"; current = parent; parent = huffmanTree[parent].Parent; } huffmanCode[i] = new string(codeTemp.Reverse().ToArray()); } return huffmanCode; } /// <summary> /// 初始化叶节点 /// </summary> /// <param name="huffmanTree"></param> /// <param name="leafNum"></param> /// <param name="weight"></param> private static void InitLeafNode(HuffmanTree[] huffmanTree, int leafNum, int[] weight) { if (huffmanTree == null || leafNum<1 || weight.Count()<1) return; for (int i = 0; i < leafNum; i++) { huffmanTree[i].Weight = weight[i]; } } /// <summary> /// 获取叶子节点中权重最小的两个节点 /// </summary> /// <param name="huffmanTree">待操作的赫夫曼</param> /// <param name="searchNode">要查找的节点数</param> /// <param name="minIndex1"></param> /// <param name="minIndex2"></param> private static void SelectNode(HuffmanTree[] huffmanTree, int searchNode, ref int minIndex1, ref int minIndex2) { HuffmanTree minNode1 = null; HuffmanTree minNode2 = null; for (int i = 0; i < searchNode; i++) { //只查找独根树叶子节点 if (huffmanTree[i].Parent == 0) { //如果为null,则表示当前节叶子节点最小 if (minNode1 == null) { minIndex1 = i; minNode1= huffmanTree[i]; continue; } if (minNode2 == null) { minIndex2 = i; minNode2= huffmanTree[i]; //交换位置,确保minIndex1为最小 if (minNode1.Weight >= minNode2.Weight) { //节点交换 var temp = minNode1; minNode1 = minNode2; minNode2 = temp; //交换下标 var tempIndex = minIndex1; minIndex1 = minIndex2; minIndex2 = tempIndex; continue; } } if (minNode1 != null && minNode2 != null) { if (huffmanTree[i].Weight < minNode1.Weight) //注意,不能是“<=” { //将min1临时转存给min2 minNode2 = minNode1; minNode1 = huffmanTree[i]; //记录在数组中的下标 minIndex2 = minIndex1; minIndex1 = i; } else { if (huffmanTree[i].Weight < minNode2.Weight) { minNode2= huffmanTree[i]; minIndex2 = i; } } } } } } } /// <summary> /// 赫夫曼树存储结构 /// </summary> public class HuffmanTree { public int Weight { get; set; } //权值 public int Parent { get; set; } //父节点 public int Left { get; set; } //左孩子节点 public int Right { get; set; } //右孩子节点 }}
阅读全文
0 0
- 数据结构入门学习系列-10(霍夫曼树)
- 数据结构入门学习系列-1(基本数据结构)
- 数据结构入门学习系列-2(算法的时间复杂度)
- 数据结构学习系列(一)
- 数据结构入门学习中。。。
- 数据结构学习入门
- ERP入门系列学习
- theano学习入门和进阶系列1: 基础数据结构和语法
- 数据结构入门学习系列-3(线性表的顺序存储)
- 数据结构入门学习系列-4(线性表的链式存储)
- 数据结构入门学习系列-5(链表的基本操作算法)
- 数据结构入门学习系列-6(链表合并与多项式合并算法)
- 数据结构入门学习系列-7(栈的结构以及存储方式和算法)
- 数据结构入门学习系列-8(栈的经典算法用例)
- 数据结构入门学习系列-9(二叉树遍历的算法实现)
- 数据结构学习(一):入门
- iPhone入门学习系列教程
- Shiro系列学习 -- 入门篇
- 产品总监进阶|突破晋升瓶颈,实现3-5年产品经理的完美进阶
- 前端优化知多少
- 2017年,那些冷门却逆天的APP应用
- VOC2007_xml格式,属性示例
- ecshop模板如何修改详细图解
- 数据结构入门学习系列-10(霍夫曼树)
- SQL左右连接中的on and和on where的区别
- jsp文件中引入js文件,文件中的函数失效不执行
- 从产品思维,看10W+爆文打造的秘密
- 产品定位:你是钉子,还是棒槌?
- 阿里云移动测试平台MQC移动测试沙龙第3期【北京站】
- 电商购买力模型:用大数据解锁智慧营销的新姿势
- 报名最后1周|与其年复一年被文案折磨,不如用4周快速摆脱文案困扰
- 使用RabbitMQ实现延迟任务(转载)