java
import java.util.*;
class HuffmanNode implements Comparable<HuffmanNode> {
int weight;
HuffmanNode left, right;
HuffmanNode(int weight) {
this.weight = weight;
this.left = this.right = null;
}
@Override
public int compareTo(HuffmanNode other) {
return this.weight - other.weight;
}
}
public class HuffmanTree {
/**
* 构建哈夫曼树
* 哈夫曼树是一种带权路径长度最短的二叉树,也称为最优二叉树
* 在数据压缩、编码等领域有广泛的应用
*
* @param weights 每个节点的权重,权重越小的节点,在构建哈夫曼树时,越靠近根节点
* @return 返回哈夫曼树的根节点
*/
public static HuffmanNode buildHuffmanTree(int[] weights) {
// 优先队列,用于存储哈夫曼树的节点,队列头部元素权值最小
PriorityQueue<HuffmanNode> pq = new PriorityQueue<>();
// 遍历所有节点权重,初始化哈夫曼树节点并加入优先队列
for (int weight : weights) {
pq.add(new HuffmanNode(weight));
}
// 当优先队列中节点数量大于1时,循环构建哈夫曼树
while (pq.size() > 1) {
// 从优先队列中取出权值最小的两个节点
HuffmanNode left = pq.poll();
HuffmanNode right = pq.poll();
// 断言right节点非空,确保树能正常构建
assert right != null;
// 创建新的哈夫曼节点,作为left和right节点的父节点,其权重为两个子节点权重之和
HuffmanNode parent = new HuffmanNode(left.weight + right.weight);
// 设置父节点的左右子节点
parent.left = left;
parent.right = right;
// 将新的父节点加入优先队列
pq.add(parent);
}
// 返回优先队列中剩余的唯一节点,即哈夫曼树的根节点
return pq.poll();
}
/**
* 中序遍历哈夫曼树
* 中序遍历的特点是左子树-根节点-右子树的顺序访问树中的节点
* 这种遍历顺序在哈夫曼树中主要用于验证树的结构,而不用于构建最短编码
*
* @param root 哈夫曼树的根节点
* @param result 用于存储遍历结果的列表,通常是节点的权重
*/
public static void inorderTraversal(HuffmanNode root, List<Integer> result) {
// 判断当前节点是否为空,为空则直接返回
if (root == null) {
return;
}
// 递归中序遍历左子树
inorderTraversal(root.left, result);
// 将当前节点的权重添加到结果列表中
result.add(root.weight);
// 递归中序遍历右子树
inorderTraversal(root.right, result);
}
/**
* 主函数入口
* 本程序用于演示霍夫曼树的构建及其遍历过程
* 霍夫曼树是一种带权路径长度最短的二叉树,具有重要应用价值
*
* @param args 命令行参数
*/
public static void main(String[] args) {
// 创建Scanner对象,用于读取命令行输入
Scanner scanner = new Scanner(System.in);
// 读取霍夫曼树节点数量
int n = scanner.nextInt();
// 初始化霍夫曼树节点权重数组
int[] weights = new int[n];
// 读取每个节点的权重
for (int i = 0; i < n; i++) {
weights[i] = scanner.nextInt();
}
// 构建霍夫曼树并返回根节点
HuffmanNode root = buildHuffmanTree(weights);
// 初始化用于存储中序遍历结果的列表
List<Integer> result = new ArrayList<>();
// 中序遍历霍夫曼树,并将结果存储到列表中
inorderTraversal(root, result);
// 输出中序遍历结果
for (int weight : result) {
System.out.print(weight + " ");
}
}
}