class Node {
int weight; // 权重
int left; // 当前节点的左孩子
int right; // 当前节点的右孩子
int parent; // 当前节点的父结点
public Node() {}
}
public class Huffman {
static Scanner sc = new Scanner(System.in);
// 获得 hfTree[1...len] 权值最小且没有父结点的两个节点的下标
public static int[] getMin(int len){
int min1 = Integer.MAX_VALUE, min2 = Integer.MAX_VALUE;
int pos1 = -1, pos2 = -1;
for(int i = 1; i <= len; i++){
if (hfTree[i].parent == 0) { // parent!=0 说明当前节点已经放到哈夫曼树中了
if(hfTree[i].weight < min1){
min2 = min1;
pos2 = pos1;
min1 = hfTree[i].weight;
pos1 = i;
}else if(hfTree[i].weight < min2){
min2 = hfTree[i].weight;
pos2 = i;
}
}
}
return new int[]{pos1, pos2};
}
static Node[] hfTree;
// 将 n 个节点组成一棵哈夫曼树,需要经过 n-1 次合并,并且该哈夫曼树中有 2n-1 个节点
public static void createHuffmanTree(int n){
int m = 2 * n - 1; // 哈夫曼树中有 2 * n - 1 个节点
hfTree = new Node[m + 1]; // 0 号位置不用
for(int i = 1; i <= m; i++) hfTree[i] = new Node();
// 初始化 n 个节点的信息
for(int i = 1; i <= n; i++){
hfTree[i].weight = sc.nextInt();
hfTree[i].left = hfTree[i].right = 0;
hfTree[i].parent = 0;
}
// 哈夫曼树一共有 2n-1 个节点,初始时有 n 个节点,存放在 [1-n] 号位置,
// 新生成的节点存放在 [n+1~m] 号位置
for(int i = n + 1; i <= m; i++){
// 获得 hfTree[1...i-1] 中权值最小且没有父结点的两个节点的下标
int[] temp = getMin(i - 1);
int minPos1 = temp[0], minPos2 = temp[1];
// 下标为 minPos1 的节点和下标为 minPos2 的节点合并成了新的节点
hfTree[minPos1].parent = hfTree[minPos2].parent = i;
hfTree[i].weight = hfTree[minPos1].weight + hfTree[minPos2].weight;
hfTree[i].left = minPos1;
hfTree[i].right = minPos2;
}
}
// 获得 n 个字符的编码
public static String[] enCode(int n){
String[] codes = new String[n + 1]; // 不使用 0 号位置
Arrays.fill(codes, "");
// 哈夫曼树的根是在最后一个位置
for(int i = 1; i <= n; i++){
int cur = i; // 当前节点
int parent = hfTree[i].parent; // 当前节点的父结点
// 哈夫曼树根节点没有父结点,其 parent 值为 0
while(parent != 0){
// 如果当前节点是其父结点的左孩子,编码为 '0'
if(hfTree[parent].left == cur){
codes[i] = "0" + codes[i];
}else { // 如果当前节点是其父结点的右孩子,编码为 '1'
codes[i] = "1" + codes[i];
}
// 让父结点成为新的孩子结点,继续朝树根的方向遍历
cur = parent;
parent = hfTree[cur].parent;
}
}
return codes;
}
}
哈夫曼编码(Java)
于 2024-06-10 00:48:17 首次发布