树-哈夫曼树
一、概念
哈夫曼树又被称为最优二叉树,是一类带权(权值就是定义的路径上面的值,哈夫曼树中的权值可以理解为:权值大表明出现概率大)路径最短的二叉树。哈夫曼树是二叉树的一种应用,在信息检索中很常用
路径:树中一个节点到另一个节点之间的分支构成这两个节点之间的路径;
节点之间的路径长度(不带权):从一个节点到另一个节点之间的分支数量称为两个节点之间的路径长度。
树的路径长度:从根节点到树中每一个节点的路径之和。
节点的带权路径长度:从该节点到根节点之间的路径长度与节点上权的乘积。
树的带权路径长度:树中所有叶子节点的带权路径长度之和
带权路径最小的二叉树被称为哈夫曼树或最优二叉树。
二、哈夫曼树的重要定理
对于具有n个叶子节点的哈夫曼树,一共需要2*n-1个节点。。
因为对于二叉树来说,有3种类型节点,即度数(节点拥有的子树的个数被称为节点的度)为2的节点,和度数为1的节点和度数为0的节点。而哈夫曼树的非叶子节点都是由两个节点合并产生,所以不会出现度数为1的节点。而生成的非叶子节点的个数为叶子节点个数-1,因此n个叶子节点的哈夫曼树,一共需要2*n-1个节点。
三、创建哈夫曼树
WPL:指的是哈夫曼树最终的带权路径
前两个数的和小于等于后面排序紧跟的两个数的话,同方向继续生长
前两个数的和大于后面排序紧跟的那两个数的话,就并列生长。
package com.zxc.TreeLearning.HaffmanTree; import com.zxc.TreeLearning.BinaryTreeLearning.BinaryTreeDW; import org.junit.Test; import java.util.ArrayDeque; import java.util.ArrayList; import java.util.Collections; import java.util.List; /** * Created by Administrator on 2018/2/20 0020. * 哈尔曼树 */ public class HaffmanTree{ public Node createTree(List<Node> list){ while(list.size()>1){//只要nodes数组中还有两个以上的节点 Collections.sort(list);//先排序数据 Node left=list.get(0);//最小的数 Node right=list.get(1);//第二小的数 Node parent=new Node(left.data+right.data,left.getWeight()+right.getWeight()); //新生成的节点,其权值是left和right权值的和 parent.setLeft(left); parent.setRight(right); list.remove(left); list.remove(right); list.add(parent); } return list.get(0); } class Node implements Comparable<Node>{ private String data; private double weight; private Node left; private Node right; public Node(String data,double weight){ this.data=data; this.weight=weight; } public String getData() { return data; } public void setData(String data) { this.data = data; } public double getWeight() { return weight; } public void setWeight(double weight) { this.weight = weight; } public Node getLeft() { return left; } public void setLeft(Node left) { this.left = left; } public Node getRight() { return right; } public void setRight(Node right) { this.right = right; } @Override public int compareTo(Node other) { if(this.getWeight()>other.getWeight()){ return 1; }if(this.getWeight()<other.getWeight()){ return -1; } return 0; } @Override public String toString() { return "data:"+this.data+",weight:"+this.weight; } } /** * 对哈夫曼树进行初始化 */ @Test public void init(){ List<Node> list=new ArrayList<>(); list.add(new Node("A",6)); list.add(new Node("B",7)); list.add(new Node("C",13)); list.add(new Node("D",16)); list.add(new Node("E",18)); list.add(new Node("F",30)); levelOrderTraversal(this.createTree(list)); // System.out.println(this.createTree(list).weight); } /** * * @param node1:所有节点的集合 */ public void levelOrderTraversal(Node node1){ ArrayDeque<Node> ad=new ArrayDeque(); if(node1==null){ System.out.println("不能广度,因为没有根节点"); }//使用队列功能,先进先出 ad.add(node1); while(!ad.isEmpty()){ Node node=ad.remove(); System.out.print(node.data+"--"); System.out.println(node.weight); if(node.getLeft()!=null){ ad.add(node.getLeft()); } if(node.getRight()!=null){ ad.add(node.getRight()); } } } }
二、哈夫曼编码
哈夫曼树可以解决报文编码问题,假设需要把一个字符串如“abcdabcaba”进行编码,将它转换为唯一的二进制码,但要求转换出来的二进制长度最小。
假设每个字符在字符串中出现的频率为W,其编码长度为L,编码字符n个,则编码后二进制码的总长度为:
W1L1+W2L2+W3L3+...+WnLn,这正好符合哈夫曼树的处理原则。
对于这个字符串,总共有abcd4个字符,他们出现的次数分别为4,3,2,1次,这就是他们的权值,于是将abcd4个字符以出现次数为权值构造哈夫曼树。