1、哈夫曼树
- Huffman Tree:给定N个权值作为N个叶子节点,构造一棵二叉树,若该树的带权路径长度达到最小,称这样的二叉树为最优二叉树,也称为哈夫曼树。、
- 1、路径:在一棵树中,从一个节点往下可以达到的孩子或孙子节点之间的通路,称为路径;
- 2、路径长度:路径分支(叉)的次数称为路径长度,则从根结点到第L层结点的路径长度为 L-1;
- 3、节点的权:节点被赋予的值;
- 4、带权路径长度:路径长度与节点权值的乘积;
- 5、树的带权路径:所有叶子节点的带权路径长度之和,记为WPL(weight path length)
- 6、哈夫曼树:WPL最小的一种二叉树,一般权值越大,离根节点越近;
- 构建哈夫曼树的步骤:
- 1、遍历arr数组 ;
- 2、将arr的每个元素构成一个节点Node,Node含权值域即左右指针域;
- 3、将Node放入ArrayList中,做排序处理;
- 4、取出权值最小和第二小的两个节点(或二叉树),构建成一棵新的二叉树;
- 5、从ArrayList中删除刚才使用过的两个节点(或二叉树);
- 6、将新构建的二叉树放入ArrayList;
- 7、重复 2-6,直到ArrayList中的元素只剩下一个;
![](https://i-blog.csdnimg.cn/blog_migrate/e296c9e8e436256d64100ebe8da3ae0b.png)
2、Java代码 -- 构建哈夫曼树
package DataStructures.Tree;
import java.util.ArrayList;
import java.util.Collections;
/**
* @author yhx
* @date 2020/10/16
*/
public class HuffmanTree {
public static void main(String[] args) {
int[] arr = {13, 7, 8, 3, 29, 6, 1};
Node root = createHuffmanTree(arr);
System.out.println("哈夫曼树前序遍历结果为:");
preOrder(root);
}
/**
* 创建哈夫曼树
* 1、遍历arr数组
* <p>
* 2、将arr的每个元素构成一个节点Node
* 3、将Node放入ArrayList中,做排序处理
* 4、取出权值最小和第二小的两个节点(或二叉树),构建成一棵新的二叉树
* 5、从ArrayList中删除刚才使用过的两个节点(或二叉树)
* 6、将新构建的二叉树放入ArrayList
* <p>
* 7、重复 2-6,直到ArrayList中的元素只剩下一个
*
* @param arr 原始数组
* @return 返回创建好的哈夫曼树的根节点
*/
public static Node createHuffmanTree(int[] arr) {
ArrayList<Node> nodes = new ArrayList<>();
for (int value : arr) {
nodes.add(new Node(value));
}
while (nodes.size() > 1) {
// 升序排序
Collections.sort(nodes);
// 取出权值最小和第二小的节点(或二叉树)
Node leftNode = nodes.get(0);
Node rightNode = nodes.get(1);
// 构建成一棵新的二叉树,这棵二叉树的父节点权值等于两个子节点权值之和
Node parent = new Node(leftNode.value + rightNode.value);
parent.left = leftNode;
parent.right = rightNode;
// 删除刚才使用过的两个二叉树
nodes.remove(leftNode);
nodes.remove(rightNode);
// 将新构建的二叉树放入ArrayList
nodes.add(parent);
}
// 返回哈夫曼树的root节点
return nodes.get(0);
}
/**
* 前序遍历
*
* @param root 根节点
*/
public static void preOrder(Node root) {
if (root != null) {
root.preOrder();
} else {
System.out.println("空树,不能遍历");
}
}
}
/**
* 节点类
* comparable接口:使继承它的类比较大小
*/
class Node implements Comparable<Node> {
/**
* value:节点权值
* left:指向左子节点
* right:指向右子节点
*/
int value;
Node left;
Node right;
/**
* 构造器
*
* @param value 节点权值
*/
public Node(int value) {
this.value = value;
}
@Override
public String toString() {
return "Node [value = " + value + "]";
}
@Override
public int compareTo(Node o) {
// 升序排序
return this.value - o.value;
// 降序排序
// return -(this.value - o.value);
}
/**
* 前序遍历方法
*/
public void preOrder() {
System.out.println(this);
if (this.left != null) {
this.left.preOrder();
}
if (this.right != null) {
this.right.preOrder();
}
}
}
3、运行结果
哈夫曼树前序遍历结果为:
Node [value = 67]
Node [value = 29]
Node [value = 38]
Node [value = 15]
Node [value = 7]
Node [value = 8]
Node [value = 23]
Node [value = 10]
Node [value = 4]
Node [value = 1]
Node [value = 3]
Node [value = 6]
Node [value = 13]