下面是节点类:
public class HuffmanNode <T>{
private T data;
public double weight;
public int parent;
public int lChild;
public int rChild;
public String huffmanCode; // 新增字段用于存储哈夫曼编码
public HuffmanNode(){
this.data= null;
this.weight= 0;
this.parent= 0;
this.lChild= -1;
this.rChild= -1;
}
public HuffmanNode(T x, double w){
data= x;
weight= w;
parent= 0;
lChild= -1;
rChild= -1;
}
public T getData(){
return data;
}
}
下面是哈夫曼树的构造以及哈夫曼编码方法:
public class HuffmanTree2<T> {
private final int maxSize = 100;
private HuffmanNode<T>[] nodes;
public int length;
public HuffmanTree2() {
nodes = new HuffmanNode[maxSize];
length = 0;
}
private int selectMin() {
int t = -1;
// 寻找第一个未被选择的节点
for (int i = 0; i < this.length; i++) {
if (nodes[i].parent == 0) {
t = i;
break;
}
}
// 寻找未被选择的、权重最小的节点
for (int i = 0; i < this.length; i++) {
if (nodes[i].parent == 0 && nodes[i].weight < nodes[t].weight) {
t = i;
}
}
if (t != -1) {
nodes[t].parent = 1;
return t;
}
return -1; // 如果所有节点都已被选择,则返回-1
}
public void buildHuffmanTree() {
int first = -1;
int second = -1;
do {
first = selectMin();
second = selectMin();
if (second != -1) {
double weight = nodes[first].weight + nodes[second].weight;
HuffmanNode<T> node = new HuffmanNode<>(null, weight);
node.lChild = first;
node.rChild = second;
nodes[length] = node;
nodes[first].parent = length;
nodes[second].parent = length;
length++;
}
} while (second != -1);
nodes[length - 1].parent = 0;
}
public void huffmanCoding(){
for (int i = 0; i < this.length; i++) {
int current = i;
int father = this.nodes[i].parent;
String t = "";
while (father != 0) {
if (this.nodes[father].lChild == current) {
t = "0" + t; // 从高位到低位记录路径
} else {
t = "1" + t; // 从高位到低位记录路径
}
current = father;
father = this.nodes[father].parent;
}
this.nodes[i].huffmanCode = t;
}
}
public static void main(String[] args) {
HuffmanTree2<Character> huffmanTree = new HuffmanTree2<>();
// 初始化一些节点
huffmanTree.nodes[huffmanTree.length++] = new HuffmanNode<>('A', 10);
huffmanTree.nodes[huffmanTree.length++] = new HuffmanNode<>('B', 15);
huffmanTree.nodes[huffmanTree.length++] = new HuffmanNode<>('C', 12);
huffmanTree.nodes[huffmanTree.length++] = new HuffmanNode<>('D', 3);
huffmanTree.nodes[huffmanTree.length++] = new HuffmanNode<>('E', 4);
huffmanTree.buildHuffmanTree();
huffmanTree.huffmanCoding();
System.out.println("哈夫曼树构造:");
for (int i = 0; i < huffmanTree.length; i++) {
System.out.println("Node " + i + ": Data=" + huffmanTree.nodes[i].getData() +
", Weight=" + huffmanTree.nodes[i].weight +
", Parent=" + huffmanTree.nodes[i].parent +
", Left Child=" + huffmanTree.nodes[i].lChild +
", Right Child=" + huffmanTree.nodes[i].rChild);
}
System.out.println("哈夫曼编码:");
for (int i = 0; i < huffmanTree.length; i++) {
System.out.println("Character: " + huffmanTree.nodes[i].getData() +
" Weight: " + huffmanTree.nodes[i].weight +
" Huffman Code: " + huffmanTree.nodes[i].huffmanCode);
}
}
}
主函数可以自己修改,是一些测试用的节点。
HuffmanNode类:
HuffmanNode
类定义了Huffman树的节点,每个节点包含数据、权重、父节点索引、左子节点索引和右子节点索引。初始时,节点的父节点和子节点索引设置为特殊值表示未连接。
HuffmanTree2类:
字段:
maxSize
:最大树大小,这里设置为常量100。nodes
:存储Huffman节点的数组。length
:当前树中节点的数量。
构造方法:
构造方法初始化nodes
数组和length
计数器。
selectMin
方法:
selectMin
方法选择未被选择的、权重最小的节点。首先找到第一个未被选择的节点,然后在剩余未选择的节点中找到权重最小的节点,并将其标记为已选择。
buildHuffmanTree
方法:
buildHuffmanTree
方法构建Huffman树。它重复选择两个最小权重的节点,合并它们成为新节点,然后添加到数组中,直到只剩下一个节点。构建过程中更新父节点和子节点的关系。
哈夫曼编码方法:
-
遍历每个节点: 使用
for
循环遍历哈夫曼树的每个节点。this.length
可能表示哈夫曼树中节点的个数。 -
初始化当前节点和父节点: 对于每个节点,初始化当前节点
current
为当前循环的节点的索引,初始化父节点father
为当前节点的父节点的索引。 -
循环生成编码: 进入
while (father != 0)
循环,该循环用于从当前节点一直追溯到根节点,生成哈夫曼编码。-
在循环中,判断当前节点是其父节点的左子节点还是右子节点。
-
如果是左子节点,将字符
'0'
添加到t
的前面。 -
如果是右子节点,将字符
'1'
添加到t
的前面。 -
更新
current
为父节点,father
为新的父节点,继续追溯。
-
-
保存哈夫曼编码: 将生成的哈夫曼编码
t
赋值给当前节点的huffmanCode
属性。
整体来说,这个方法是通过迭代从叶子节点向上追溯到根节点,生成每个节点的哈夫曼编码。由于哈夫曼编码是从根节点到叶子节点的路径编码,所以从叶子节点向上追溯能够正确地构建每个节点的编码。生成的编码会保存在每个节点的 huffmanCode
属性中,最终完成哈夫曼编码的生成过程。