【问题标题】:Constructing sequential Huffman Tree From Scratch从零开始构建顺序霍夫曼树
【发布时间】:2020-03-19 10:33:25
【问题描述】:

给定一些文本文件,我需要读取每个字母数字字符并使用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' 都在第二行)以及如何创建完整的二叉树(如果它有左子,它需要有右子)只有终端节点的级别。

事先,我知道这个问题不是很具体,如果有另一种方法来解决这个问题,而不是仅仅解决提到的问题,我将不胜感激。

【问题讨论】:

    标签: c algorithm data-structures binary-tree huffman-code


    【解决方案1】:

    这是一个人为的家庭作业问题吗?我问是因为不使用链接的树的表示需要 O(2^h) 空间来存储高度为 h 的树。这是因为他们假设树是完整的,允许索引计算来替换指针。由于 Huffman 树对于大小为 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,除了子级之外,您还需要父级索引。解决这些问题应该很有趣。祝你好运。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-02-27
      • 2014-03-18
      • 1970-01-01
      相关资源
      最近更新 更多