赫夫曼树的基本介绍:
给定n个权值作为n个叶子结点,构造一棵二叉树,若该树的带权路径长度(wpl)达到最小,称这样的二叉树为最优二叉树,也称为哈夫曼树(Huffman Tree), 还有的书翻译为霍夫曼树。赫夫曼树是带权路径长度最短的树,权值较大的结点离根较近。
如下图中第二个树才是赫夫曼树,因为它的wpl值最小
赫夫曼树的几个重要概念:
1)、路径和路径长度:在一棵树中,从一个结点往下可以达到的孩子或孙子结点之间的通路,称为路径。通路中分支的数目称为路径长度。若规定根结点的层数为1,则从根结点到第L层结点的路径长度为L-1
2)、结点的权及带权路径长度:若将树中结点赋给一个有着某种含义的数值,则这个数值称为该结点的权。结点的带权路径长度为:从根结点到该结点之间的路径长度与该结点的权的乘积
3)、树的带权路径长度:树的带权路径长度规定为所有叶子结点的带权路径长度之和,记为WPL(weighted path length) ,权值越大的结点离根结点越近的二叉树才是最优二叉树。
4)、WPL最小的就是赫夫曼树
题目描述:
给你一个数列 {13, 7, 8, 3, 29, 6, 1},要求转成一颗赫夫曼树
构成赫夫曼树的步骤:
- 从小到大进行排序, 将每一个数据,每个数据都是一个节点 , 每个节点可以看成是一颗最简单的二叉树
- 取出根节点权值最小的两颗二叉树
- 组成一颗新的二叉树, 该新的二叉树的根节点的权值是前面两颗二叉树根节点权值的和
- 再将这颗新的二叉树,以根节点的权值大小 再次排序,不断重复 1-2-3-4 的步骤,直到数列中,所有的数据都被处理,就得到一颗赫夫曼树
代码实现:
package Tree;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
/**
* @ClassName: HuffmanTree
* @Description: 创建一个赫夫曼树以及它的前序遍历
* @author Golven
* @date 2019年10月27日
*
*/
public class HuffmanTree {
public static void main(String[] args) {
int[] arr = { 13, 7, 8, 3, 29, 6, 1 };
preOrder(createHuffmanTree(arr));
}
public static void preOrder(Node root) {
if (root != null) {
root.preOrder();
} else {
System.out.println("是空树");
return;
}
}
/**
*
* @Title: createHuffmanTree
* @Description: 创建一个赫夫曼树
* @param @param arr 需要创建成赫夫曼数的数组
* @return Node 返回的是树的根节点
*/
public static Node createHuffmanTree(int[] arr) {
// 遍历arr数组,将arr数组中的每一个元素放到ArrayList中
ArrayList<Node> nodes = new ArrayList<Node>();
for (int value : arr) {// 对arr中的每个元素执行以此,并会将每个元素的值赋给value
nodes.add(new Node(value));
}
// 处理的过程是一个循环的过程
while (nodes.size() > 1) {
Collections.sort(nodes);// 排序从小到大
// 取出权值最小的结点
Node leftNode = nodes.get(0);
// 取出权值第二小的结点
Node rightNode = nodes.get(1);
// 创建left和right结点的根节点,value等于两个子节点的value和
Node parent = new Node(leftNode.value + rightNode.value);
// 构建一个二叉树
parent.left = leftNode;
parent.right = rightNode;
// 将已经处理的结点从ArrayList中删除
nodes.remove(leftNode);
nodes.remove(rightNode);
// 将创建出的新的结点加入到数组中
nodes.add(parent);
}
return nodes.get(0);
}
}
//创建一个Node结点类
//因为初始化的数组要进行升序排序,要用到Collections,故要在Node类中实现一个comparable接口
class Node implements Comparable<Node> {
public int value;
public Node left;
public Node right;
// 前序遍历
public void preOrder() {
System.out.println(this);
if (this.left != null) {
this.left.preOrder();
}
if (this.right != null) {
this.right.preOrder();
}
}
public Node(int value) {
this.value = value;
}
@Override
public String toString() {
return "Node [value=" + value + "]";
}
@Override
// this.value-o.value表示升序
public int compareTo(Node o) {
// 表示升序
return this.value - o.value;
}
}