????????赫夫曼树,又称最优二叉树,是带权路径最短的树。它的基本概念包括路径、路径长度、树的路径长度、权、结点的带权路径长度和树的带权路径长度。其中,路径是从树中一个结点到另一个结点之间的分支构成,路径长度是路径上的分支数目,树的路径长度是从树根到每个结点的路径长度之和。权是赋予树中每个结点的一个有实际意义的数值,比如表示该结点出现的频率等。结点的带权路径长度是从根结点到该结点之间的路径长度与该结点的权的乘积,而树的带权路径长度是树中所有叶子结点的带权路径长度之和。
????????构造赫夫曼树的方法是采用赫夫曼算法,即根据给定的权值集合构造出对应的二叉树集合,然后从中选取两棵权值最小的树作为新构造的二叉树的左右子树,新二叉树的根结点的权值为其左右子树根结点的权值之和,最后重复这一步骤,直到只剩下一棵树为止,这棵树便是赫夫曼树。
????????赫夫曼树在计算机科学和信息处理领域中有着广泛的应用,比如数据压缩和编码等。其中,赫夫曼编码是一种基于赫夫曼树的编码方式,可以用于数据压缩,其基本原理是给出现频率较高的字符分配较短的编码,给出现频率较低的字符分配较长的编码,从而达到压缩数据的目的。
package com.example.datastructures.tree;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/**
* @author maoyouhua
* @version jdk21
*
* 赫夫曼树,又称最优二叉树,是带权路径最短的树。它的基本概念包括路径、路径长度、树的路径长度、权、结点的带权路径长度和树的带权路径长度。
* 其中,路径是从树中一个结点到另一个结点之间的分支构成,路径长度是路径上的分支数目,树的路径长度是从树根到每个结点的路径长度之和。
* 权是赋予树中每个结点的一个有实际意义的数值,比如表示该结点出现的频率等。
* 结点的带权路径长度是从根结点到该结点之间的路径长度与该结点的权的乘积,而树的带权路径长度是树中所有叶子结点的带权路径长度之和。
*
* 构造赫夫曼树的方法是采用赫夫曼算法,即根据给定的权值集合构造出对应的二叉树集合,
* 然后从中选取两棵权值最小的树作为新构造的二叉树的左右子树,新二叉树的根结点的权值为其左右子树根结点的权值之和,
* 最后重复这一步骤,直到只剩下一棵树为止,这棵树便是赫夫曼树。
*
* 赫夫曼树在计算机科学和信息处理领域中有着广泛的应用,比如数据压缩和编码等。
* 其中,赫夫曼编码是一种基于赫夫曼树的编码方式,可以用于数据压缩,
* 其基本原理是给出现频率较高的字符分配较短的编码,给出现频率较低的字符分配较长的编码,从而达到压缩数据的目的。
*/
public class HuffmanTree {
public static Node createHuffmanTree(int[] arr){
List<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.getValue() + rightNode.getValue(), leftNode, rightNode);
nodes.remove(leftNode);
nodes.remove(rightNode);
nodes.add(parent);
}
return nodes.get(0);
}
public static void preOrder(Node root){
if (root != null) {
root.preOrder();
} else {
System.out.println("空树,不能遍历");
}
}
/**
* 67
* ↙ ↘
* 29 38
* ↙ ↘
* 15 23
* ↙ ↘ ↙ ↘
* 7 8 10 13
* ↙ ↘
* 4 6
* ↙ ↘
* 1 3
*
* @param args
*/
public static void main(String[] args) {
int[] arr = {13,7,8,3,29,6,1};
Node huffmanTree = createHuffmanTree(arr);
preOrder(huffmanTree);
}
}
/**
* 实现自然排序接口,方便集合排序
*/
class Node implements Comparable<Node>{
private Node left;
private Node right;
private int value;
public Node(int value) {
this.value = value;
}
public Node(int value, Node left, Node right) {
this.left = left;
this.right = right;
this.value = value;
}
public int getValue() {
return value;
}
public void preOrder(){
System.out.println(this);
if (this.left != null) {
this.left.preOrder();
}
if (this.right != null) {
this.right.preOrder();
}
}
@Override
public String toString() {
return "Node{" +
"value=" + value +
'}';
}
@Override
public int compareTo(Node o) {
return this.value - o.value;
}
}