给出一些文本文件,我需要阅读每个字母数字字符并使用Huffman's algorithm.
对其进行编码。解决字符读取,存储概率和创建节点以及使用指针创建霍夫曼的特里的问题。
但是,我需要使用二叉树的顺序表示形式创建和初始化霍夫曼树,而没有任何指针。
这可以通过使用指针创建规则树然后将其读入数组来完成,但是我的目标是直接用节点填充数组。
我考虑过创建较小的树并将它们合并在一起,但是选择了一种矩阵表示形式,从二进制堆中收集概率最小的元素,然后将它们存储到矩阵的行中,其中矩阵的行将表示级别该节点应以相反的顺序位于二叉树中。
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'的情况下,以及如何创建完整的二叉树(如果已离开子树,则需要有正确的一棵树)终端节点的级别。
事先,我了解到该问题不是很具体,并且希望知道是否还有其他方法可以解决此问题,而不仅仅是解决上述问题。
答案 0 :(得分:0)
这是人为作业的问题吗?我问是因为不使用链接的树表示需要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;
}
当然,这不会返回消耗了多少位,真正的解码器需要这样做。真正的解码器也不会将其位放入数组中。最后,对于 encoding ,您除了子元素外还需要父索引。解决这些问题应该很有趣。祝你好运。