概念

  • 给定n个权值作为n个叶子节点,构造一颗二叉树,若该数的代全路径长度(wpl)达到最小,称这样的的二叉树为最优二叉树,也成霍夫曼树

  • 霍夫曼树是带权路径长度最短的树,权值较大的节点离根较近

  • 路径和路径长度:

    • 在一棵树中,从一个结点往下可以达到的孩子结点之间的通路,称为路径。通路中分支的数目称为路径长度。若规定根结点的层数为1,则从根节点到L层结点的路径长度为L-1

  • 结点的权及带权路径长度:

    • 若将树中结点赋给一个有着某种含义的数值,则这个数值成为该节点的权。结点的带权路径长度为:从根节点到该节点之间的路径长度与该节点的权的乘积

  • 树的带权路径长度:树的带权路径长度规定为所有叶子节点的带权路径长度之和,记为WPL(weighted path length),权值越大的节点离根节点越近。

原理

因为带权路径长度是权值*路径长度,要使带权路径长度最小,节点的权值越大,其路径长度就要越小

  • 给定一个序列,将其从小到大排序,这样我们序列的前两个就是权值最小的两个元素

  • 创建一个新的节点,其权值为权值最小的两个元素的权值之和,然后将这两个最小元素,分别放到新节点的左右子节点上,并将新节点的权值放回序列,代替原来的两个元素

  • 重新排序后重复上述操作,直到序列中只剩一个节点,即构建完毕

  • 这样创建出的赫夫曼树的根结点为所有节点的权值之和,根结点的两个子节点是最大节点与其他节点的权值之和构建的新节点,以此类推,权值越大,越靠近根结点,路径越短

赫夫曼编码

  • 赫夫曼编码是哈夫曼树在电讯通信中的经典应用之一

  • 赫夫曼编码广泛地用于数据文件压缩。其压缩率通常都在20%~90%之间

  • 赫夫曼码是可变字长编码的一种

  • 构建好赫夫曼树后,按照左0右1的规则生成编码,因为生成的赫夫曼树后,每个编码都是叶子节点,所以不会产生有两个编码有同样前缀的情况(即每个编码的父节点都不可能是另一个编码),即赫夫曼编码是前缀编码

代码

class  HuffNode implements Comparable<HuffNode> {int value;HuffNode left;HuffNode right;char c;String huffCode;public HuffNode(int value, char c) {this.value = value;this.left = null;this.right = null;this.c = c;this.huffCode = "";}public HuffNode(int value) {this.value = value;this.left = null;this.right = null;this.huffCode = "";}public HuffNode() {this.value = 0;this.left = null;this.right = null;this.huffCode = "";}@Overridepublic String toString() {if (left != null && right != null) {return "HuffNode{ " +" value=" + value +" left=" + left.value +" right=" + right.value +" c=" + c +" huffCode=" + huffCode +" }";}else if (left != null && right == null){return "HuffNode{ " +" value=" + value +" left=" + left.value +" c=" + c +" huffCode=" + huffCode +" }";}else {return "HuffNode{ " +" value=" + value +" c=" + c +" huffCode=" + huffCode +" }";}}/*** 先序遍历*/public void preOrder() {System.out.println(this);if (this.left != null) {this.left.preOrder();}if (this.right != null) {this.right.preOrder();}}/*** 设置哈弗曼编码,路径左0右1* 哈弗曼编码是前缀编码的原因为:生成哈夫曼树时每个元素都为叶子节点* @param c 根据字符查询* @param code 存储路径信息,最后保存到huffCode中*/public void setHuffCode(char c , String code) {if (this.c == c) {String str = "";for (int i = 1; i < code.length(); i++) {str = str + code.charAt(i);}this.huffCode = str;return;}// 左0if (this.left != null) {code = code+"0";this.left.setHuffCode(c,code);}// 右1if (this.right != null) {code = code+"1";this.right.setHuffCode(c,code);}}/*** 实现Comparable接口* 实现方法,此为从小到大排序** @param o* @return*/@Overridepublic int compareTo(HuffNode o) {return this.value - o.value;}
}
class HuffmaTree {private ArrayList<HuffNode> huffNodeArrayList ;private HuffNode[] arrHuff;private HuffNode root;public void setHuffNodeArrayList(ArrayList<HuffNode> huffNodeArrayList) {this.huffNodeArrayList = new ArrayList<HuffNode>();for (int i = 0 ; i < huffNodeArrayList.size() ; i++) {HuffNode node = huffNodeArrayList.get(i);this.huffNodeArrayList.add(node);}}public void list() {Iterator iterator = huffNodeArrayList.iterator();while (iterator.hasNext()) {System.out.println(iterator.next());}}public void setRoot(HuffNode root) {this.root = root;}public void preOrder() {if (root == null) {System.out.println("空");}else {root.preOrder();}}/*** 根据数组中的值放置arrHuff* @param arr*/public void setArrHuff(int[] arr) {arrHuff = new HuffNode[arr.length];for (int i = 0 ; i < arr.length ; i++) {HuffNode node = new HuffNode(arr[i]);arrHuff[i] = node;}}public HuffNode[] getArrHuff() {return arrHuff;}public ArrayList<HuffNode> getHuffNodeArrayList() {return huffNodeArrayList;}/*** 构造哈夫曼树,所有叶子节点的带权路径之和最小的树(路径长度*权值)* @param arr* @return 返回最优二叉树的根结点*/public HuffNode createHuffmanTree_2(int[] arr) {ArrayList<HuffNode> arrayList = new ArrayList();for (int value : arr) {arrayList.add(new HuffNode(value));}while (arrayList.size() > 1) {// 1. 将数组从小到大排序Collections.sort(arrayList);// 2. 选择权值最小的两个节点组成树,其根结点为两子节点权值之和HuffNode leftNode = arrayList.get(0);HuffNode rightNode = arrayList.get(1);HuffNode parent = new HuffNode(leftNode.value + rightNode.value);parent.right = rightNode;parent.left = leftNode;// 3. 将根节点权值放回数组中,并重复上述操作arrayList.remove(leftNode);arrayList.remove(rightNode);arrayList.add(parent);}return arrayList.get(0);}/*** 构造哈夫曼树,所有叶子节点的带权路径之和最小的树(路径长度*权值)* @param arr*/public HuffNode createHuffmanTree_1(int[] arr) {// 1. 将数组从小到大排序QuickSort quickSort = new QuickSort();quickSort.quickSort(arr,0,arr.length-1);setArrHuff(arr);for (int i = 0 ; i < arr.length-1 ; i++) {// 2. 选择权值最小的两个节点组成树,其根结点为两子节点权值之和int value = arrHuff[i].value + arrHuff[i+1].value;HuffNode node = new HuffNode(value);node.left = arrHuff[i];node.right = arrHuff[i+1];// 3. 将根节点权值放回数组中,并重复上述操作arrHuff[i+1] = node;for (int j = i+1 ; j < arrHuff.length-1 ; j++) {for (int k = i+1 ; k < arrHuff.length-1 ; k++) {if (arrHuff[k].value>arrHuff[k+1].value) {HuffNode temp = arrHuff[k];arrHuff[k] = arrHuff[k+1];arrHuff[k+1] = temp;}}}}return arrHuff[arrHuff.length-1];}/*** 构造哈夫曼树,所有叶子节点的带权路径之和最小的树(路径长度*权值)* @param arr* @return 返回最优二叉树的根结点*/public HuffNode createHuffmanTree_3(int[] arr , char[] letter) {ArrayList<HuffNode> arrayList = new ArrayList();for (int i = 0 ; i < arr.length ; i++) {arrayList.add(new HuffNode(arr[i],letter[i]));}setHuffNodeArrayList(arrayList);while (arrayList.size() > 1) {// 1. 将数组从小到大排序Collections.sort(arrayList);// 2. 选择权值最小的两个节点组成树,其根结点为两子节点权值之和HuffNode leftNode = arrayList.get(0);HuffNode rightNode = arrayList.get(1);HuffNode parent = new HuffNode(leftNode.value + rightNode.value);parent.right = rightNode;parent.left = leftNode;// 3. 将根节点权值放回数组中,并重复上述操作arrayList.remove(leftNode);arrayList.remove(rightNode);arrayList.add(parent);}return arrayList.get(0);}/*** 设置哈夫曼编码* @param c 字符,根据字符查找,并记录路径* @param code*/public void setHuffCode(char c , String code) {if (this.root==null) {System.out.println("空");}else {root.setHuffCode(c,code);}}
}
public class HuffmanTreeDemo {/*** 统计字符串中每个字符出现的次数* @param str* @return*/public static char[][] countTimes(String str) {char[][] letter = new char[2][str.length()];ArrayList arrayList = new ArrayList();for (int i = 0 ; i < str.length() ; i++) {arrayList.add(str.charAt(i));}int temp = 0 ;while (arrayList.size() > 0) {int i = 0;// 每次根据队列的第一个元素进行查询,若有相同元素计数++,并且将其删除letter[0][temp] = (char) arrayList.get(0);while (i < arrayList.size()) {if (letter[0][temp] == (char)arrayList.get(i)) {letter[1][temp]++;arrayList.remove(arrayList.get(i));}else {i++;}}temp++;}char[][] le = new char[2][temp];for (int i = 0 ; i < temp ; i++) {le[0][i] = letter[0][i];le[1][i] = letter[1][i];}return le;}

算法学习之最优二叉树(赫夫曼树)相关推荐

  1. 最优二叉树(赫夫曼树)

    赫夫曼树的介绍(写的不好地方大佬请指教) 最优二叉树又称哈夫曼树,是带权路径最短的二叉树.根据节点的个数,权值的不同,最优二叉树的形状也不同. 图 6-34 是 3 棵最优二叉树的例子,它们共同的特点 ...

  2. 6.6.1最优二叉树(赫夫曼树)

    首先我们来看一个伪代码.这个是代表成绩的等级. 然后我们知道,每一次高考,学生的成绩分布应该接近某个比例,现在我们假如分别规律如下: 为此可以作出下面的这个树. 我们发现,概率分布主要是在70-79, ...

  3. 最优二叉树——哈夫曼树

      一:什么是最优二叉树? 从我个人理解来说,最优二叉树就是从已给出的目标带权结点(单独的结点) 经过一种方式的组合形成一棵树.使树的权值最小. 最优二叉树是带权路径长度最短的二叉树.根据结点的个数, ...

  4. 【id:180】【20分】D. DS二叉树--赫夫曼树解码(不含代码框架)

    题目描述 已知赫夫曼编码算法和程序,在此基础上进行赫夫曼解码 在赫夫曼树的类定义中增加了一个公有方法: int  Decode(const string codestr, char txtstr[]) ...

  5. 【id:179】【20分】C. DS二叉树--赫夫曼树的构建与编码(不含代码框架)

    题目描述 给定n个权值,根据这些权值构造huffman树,并进行huffman编码 参考课本P147算法6.12 HuffmanCoding代码,注意数组访问是从位置1开始 要求:赫夫曼的构建中,默认 ...

  6. 最优二叉树-哈夫曼树

    关于最优二叉树, 一开始看书 , 做题 还是蒙的 后来多做几题大致就懂得了 , 百度百科给出的官方定义: 给定N个权值作为N个叶子结点,构造一棵二叉树,若该树的带权路径长度达到最小,称这样的二叉树为最 ...

  7. 最优二叉树(哈夫曼树)

    哈夫曼树 哈夫曼树的定义 哈夫曼树的构造 哈夫曼树的特点 哈夫曼编码 哈夫曼树的定义 例如: 哈夫曼树就是要构造一棵WPL最小的二叉树. 哈夫曼树的构造 哈夫曼树构造时,每次把权值最小的两颗二叉树合并 ...

  8. 算法系列之赫夫曼树的精解【构造流程及原理分析】

    赫夫曼树又称为最优树.最优二叉树 赫夫曼树百度百科 https://baike.baidu.com/item/%E5%93%88%E5%A4%AB%E6%9B%BC%E6%A0%91/2305769? ...

  9. 赫夫曼树编码的算法及应用习题--数据结构

    赫夫曼树编码的算法及应用习题 1.构造赫夫曼树的方法 1.根据给定的n个权值{w1,w2,---wn},构成n棵二叉树的集合F={T1,T2...,Tn},其中每棵二叉树中只有一个带权为Wi的根结点, ...

最新文章

  1. 解决Windows7下vs2008 Active control test container 不能运行的问题
  2. 2014年第五届蓝桥杯决赛Java本科B组试题解析
  3. 基于 GraphQL 实践的一点思考
  4. Java中的关于static的解释和应用
  5. 【javascript知识点】javascript 额外篇
  6. Solr-4.10.2安装
  7. 基于线性预测的语音编码原理解析
  8. haproxy透传用户ip-方法和原理
  9. Java中abstract与interface
  10. 多重继承java_Java中的多重继承与组合vs继承
  11. linux中的码字软件,码字写作软件下载
  12. java生成仿银行卡的会员号
  13. FirstApp,iphone开发学习总结1,UIview添加UIimage
  14. Python基础(dict类)
  15. alot英文怎么读_alot...of是什么意思
  16. 什么邮箱最好用?主流邮箱品牌如何选择
  17. 2019 计蒜之道 初赛 第一场(A. 商汤的AI伴游小精灵)
  18. 总结工作中nginx、git、linux、ES、lamada表达式、sql
  19. 云服务器ecs增加带宽,老鸟告诉你云服务器带宽多少合适?
  20. Win7及以上系统自带Windows 光盘映像刻录机

热门文章

  1. 框架 day81 涛涛商城项目-实现首页搜索功能,商品详情,描述,规格展示
  2. 2013年6月26 日我打开支付宝页面,向余额宝转入了 20元。
  3. 硬件-Array配置负载均衡
  4. 学习笔记 --- 工厂、单体、适配器、策略、观察者、MVC设计模式及ASP.NET MVC开发模式、关闭缓存的方法...
  5. 《南京印象》之一《秦淮断章》
  6. python xpath定位不到_Xpath定位方法深入探讨及元素定位失败常见情况
  7. 首发,字节大能在GitHub做出的刷题总结,霸榜GitHub
  8. 项目周期一般多久_净化车间初中高效空气过滤网的更换周期一般是多久?
  9. 游戏-关于星际争霸2各种卡顿原因详解
  10. 微信小程序 省市区三级地址选择实现