[英]Constructing sequential Huffman Tree From Scratch
給定一些文本文件,我需要讀取每個字母數字字符並使用霍夫曼算法對它們進行編碼。
解決了讀取字符、存儲概率和創建節點以及使用指針創建 Huffman 樹的問題。
但是,我需要使用二叉樹的順序表示來創建和初始化霍夫曼樹,而不需要任何指針。
這可以通過使用指針創建常規樹然后將其讀入數組來完成,但我的目標是直接用節點填充數組。
我考慮過創建較小的樹並將它們合並在一起,但選擇了矩陣表示,我將從二進制堆中收集概率最小的元素並將它們存儲到矩陣的行中,矩陣的行將表示節點所在的級別應該在二叉樹中,以相反的順序。
E.g. Given characters and their probabilities as char[int] pairs.
a[1], b[1], c[2], d[1], e[3], f[11], g[2]
I aim to create matrix that looks like
____________________________________
a | b | d | g |
____________________________________
ab | c | dg | e |
____________________________________
abc | deg | | |
____________________________________
abcdeg | f | | |
____________________________________
abcdefg | | | |
____________________________________
Where levels of a, b, c, d, e & f would be rows of a matrix.
目前,我被困在如何在元素的“父”移動時遞歸遞增元素的級別(如果我將來自不同級別 ['ab' 和 'c'] 的兩個節點組合在一起,我很容易將 c 的級別與 ab 相等並解決問題,但如果例如'c'和'd'都在第二行)以及如何創建只有終端級別的完整二叉樹(如果它有左子樹,它需要有正確的一個)節點。
事先,我知道這個問題不是很具體,如果有另一種方法來解決這個問題,而不是僅僅解決提到的方法,我將不勝感激。
這是家庭作業的人為問題嗎? 我問是因為不使用鏈接的樹的表示需要 O(2^h) 空間來存儲高度為 h 的樹。 這是因為他們假設樹是完整的,允許索引計算來替換指針。 由於對於大小為 m 的字母表,霍夫曼樹的高度可以為 h=m-1,因此最壞情況數組的大小可能非常大。 大部分將不會被使用。
但是,如果您放棄鏈接必須是指針並允許它是數組索引的想法,那么您就可以了。 很久以前——在動態內存分配器變得普遍之前——這是標准的。 這個問題對這個方法特別好,因為你總是提前知道樹中的節點數:一個小於字母表大小的兩倍。 在 C 中你可能會做這樣的事情
typedef struct {
char ch;
int f;
int left, right; // Indices of children. If both -1, this is leaf for char ch.
} NODE;
#define ALPHABET_SIZE 7
NODE nodes[2 * ALPHABET_SIZE - 1] = {
{ 'a', 1, , -1, -1},
{ 'b', 1, -1, -1 },
{ 'c', 2, -1, -1 },
{ 'd', 1, -1, -1 },
{ 'e', 3, -1, -1 },
{ 'f', 11, -1, -1 },
{ 'g', 2, -1, -1 },
// Rest of array for internal nodes
};
int n_nodes = ALPHABET_SIZE;
int add_internal_node(int f, int left, int right) {
// Allocate a new node in the array and fill in its values.
int i = n_nodes++;
nodes[i] = (NODE) { .f = f, .left = left, .right = right };
return i;
}
現在您將使用標准的樹構建算法,如下所示:
int build_huffman_tree(void) {
// Add the indices of the leaf nodes to the priority queue.
for (int i = 0; i < ALPHABET_SIZE; ++i)
add_to_frequency_priority_queue(i);
while (priority_queue_size() > 1) {
int a = remove_min_frequency(); // Removes index of lowest freq node from the queue.
int b = remove_min_frequency();
int p = add_internal_node(nodes[a].f + nodes[b].f, a, b);
add_to_frequency_priority_queue(p);
}
// Last node is huffman tree root.
return remove_min_frequency();
}
解碼算法將像這樣使用根的索引:
char decode(BIT bits[], int huffman_tree_root_index) {
int i = 0, p = huffman_tree_root_index;
while (node[p].left != -1 || node[p].right != -1) // while not a leaf
p = bits[i++] ? nodes[p].right : nodes[p].left;
return nodes[p].ch;
}
當然,這不會返回消耗了多少位,這是真正的解碼器需要做的。 真正的解碼器也沒有在數組中獲取其位。 最后,對於編碼,除了子項之外,您還需要父索引。 解決這些問題應該很有趣。 祝你好運。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.