哈夫曼樹 是帶權路徑長度 (WPL) 最小的二元樹,廣泛應用於資料壓縮編碼 (如 ZIP、JPEG、MP3)。核心思想:權重越大的節點離根節點越近,權重越小的節點離根節點越遠,以達到整體編碼長度最短。
package boom;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Queue;
class Node<T> implements Comparable<Node<T>> {
private T data;
private int weight;
private Node<T> left;
private Node<T> right;
public Node(T data, int weight) {
this.data = data;
this.weight = weight;
}
@Override
public int compareTo(Node<T> other) {
// 由小排到大,權重小的優先
if (this.weight < other.getWeight()) return -1;
if (this.weight > other.getWeight()) return 1;
return 0;
}
// Getter/Setter 省略...
public T getData() { return data; }
public int getWeight() { return weight; }
public Node<T> getLeft() { return left; }
public void setLeft(Node<T> left) { this.left = left; }
public Node<T> getRight() { return right; }
public void setRight(Node<T> right) { this.right = right; }
@Override
public String toString() {
return "data:" + data + ";weight:" + weight;
}
}
public class Huffman<T> {
// 建立哈夫曼樹
public static <T> Node<T> create(List<Node<T>> nodes) {
while (nodes.size() > 1) {
Collections.sort(nodes); // 簡單實作,生產環境建議用 PriorityQueue
Node<T> right = nodes.remove(nodes.size() - 1); // 權重最小
Node<T> left = nodes.remove(nodes.size() - 1); // 次小
Node<T> parent = new Node<>(null, left.getWeight() + right.getWeight());
parent.setLeft(left);
parent.setRight(right);
nodes.add(parent);
}
return nodes.get(0);
}
// 層序遍歷 (廣度優先)
public static <T> List<Node<T>> breadth(Node<T> root) {
List<Node<T>> result = new ArrayList<>();
Queue<Node<T>> queue = new ArrayDeque<>();
queue.offer(root);
while (!queue.isEmpty()) {
Node<T> current = queue.poll();
result.add(current);
if (current.getLeft() != null) queue.offer(current.getLeft());
if (current.getRight() != null) queue.offer(current.getRight());
}
return result;
}
public static void main(String[] args) {
List<Node<String>> nodes = new ArrayList<>();
nodes.add(new Node<>("a", 7));
nodes.add(new Node<>("b", 5));
nodes.add(new Node<>("c", 4));
nodes.add(new Node<>("d", 2));
Node<String> root = create(nodes);
System.out.println("層序遍歷結果: " + breadth(root));
// 預期輸出結構:
// root(weight=18)
// ├── left: a(7)
// └── right: internal(11)
// ├── left: b(5)
// └── right: internal(6)
// ├── left: c(4)
// └── right: d(2)
}
}
由根節點出發,左分支編碼 0,右分支編碼 1:
0 (權重 7,最短)10 (權重 5)110 (權重 4)111 (權重 2,最長)驗證 WPL = 7×1 + 5×2 + 4×3 + 2×3 = 7 + 10 + 12 + 6 = 35 (最小)
PriorityQueue 替代 Collections.sort,建樹複雜度從 O(n²log n) 降為 O(n log n)Map<Character, String> 快速查找