霍夫曼樹是帶權路徑長度最小的二叉樹,廣泛用於無損壓縮編碼。構建步驟:
typedef struct _HUFFMAN_NODE {
char symbol; // 葉節點字元,內部節點為 '\0'
double frequence; // 權重/頻率
struct _HUFFMAN_NODE* left;
struct _HUFFMAN_NODE* right;
struct _HUFFMAN_NODE* parent;
int bit; // 0 或 1,指示來自父節點的哪一支
} HUFFMAN_NODE;
採用函數指針實現泛型冒泡排序,僅需提供 compare、swap 兩個適配函數:
void bubble_sort(void* array[], int length,
int (*compare)(void*, void*),
void (*swap)(void**, void**)) {
for (int outer = length - 1; outer > 0; outer--) {
for (int inner = 0; inner < outer; inner++) {
if (compare(array[inner], array[inner + 1])) {
swap(&array[inner], &array[inner + 1]);
}
}
}
}
int compare_huffman(void* a, void* b) {
HUFFMAN_NODE* n1 = (HUFFMAN_NODE*)a;
HUFFMAN_NODE* n2 = (HUFFMAN_NODE*)b;
return n1->frequence > n2->frequence ? 1 : 0;
}
void swap_huffman(void** a, void** b) {
HUFFMAN_NODE* tmp = *(HUFFMAN_NODE**)a;
*(HUFFMAN_NODE**)a = *(HUFFMAN_NODE**)b;
*(HUFFMAN_NODE**)b = tmp;
}
HUFFMAN_NODE* create_huffman_tree(HUFFMAN_NODE* nodes[], int length) {
if (!nodes || length <= 1) return NULL;
HUFFMAN_NODE* root = NULL;
while (length > 1) {
// 1. 排序取最小兩個
bubble_sort((void**)nodes, length, compare_huffman, swap_huffman);
// 2. 建立新父節點
root = create_new_node('\0', nodes[0]->frequence + nodes[1]->frequence);
assert(root);
root->left = nodes[0];
root->right = nodes[1];
nodes[0]->parent = root; nodes[0]->bit = 1;
nodes[1]->parent = root; nodes[1]->bit = 0;
// 3. 陣列壓縮:移除前兩個,將新節點放入末尾
memmove(&nodes[0], &nodes[2], sizeof(HUFFMAN_NODE*) * (length - 2));
nodes[length - 2] = root;
length--;
}
return root;
}
void print_code_for_str(HUFFMAN_NODE* leaf, HUFFMAN_NODE* root) {
if (!leaf || !root) return;
while (leaf != root) {
printf("%d", leaf->bit); // 逆序輸出
leaf = leaf->parent;
}
// 實際應用中需反轉字串或用堆疊暫存
}
void test() {
HUFFMAN_NODE* n1 = create_new_node('a', 0.1);
HUFFMAN_NODE* n2 = create_new_node('b', 0.2);
HUFFMAN_NODE* n3 = create_new_node('c', 0.3);
HUFFMAN_NODE* n4 = create_new_node('d', 0.4);
HUFFMAN_NODE* nodes[] = {n1, n2, n3, n4};
HUFFMAN_NODE* root = create_huffman_tree(nodes, 4);
print_code_for_str(n1, root); // 輸出編碼 (逆序)
print_code_for_str(n2, root);
print_code_for_str(n3, root);
print_code_for_str(n4, root);
}
預期編碼長度:高頻符號編碼短、低頻符號編碼長,符合最優前綴碼性質。
malloc/free。huffman_encode/decode 函數,支援流式處理。