【问题标题】:Inserting into a Huffman Tree插入霍夫曼树
【发布时间】:2014-05-02 04:20:35
【问题描述】:

我的霍夫曼树有问题;当我尝试构建它时,我将节点放在错误的位置。例如,我希望我的权重为 2 的节点(带有子 i:1 和 n:1)进入 m:2 和 space:3 的节点之间,但它正好在我放入的前一个节点之后(2与 e:1 和 g:1 的孩子)。

我的问题是:如何根据权重(即两个子节点的总和)和子节点符号(即右孩子'n'在'g'的另一个右孩子之前)。

感谢您的帮助!

编辑:另外,我如何按字母顺序打印树的代码;现在我让他们从最右边的树打印到最左边

这是我的插入函数...

    struct node* insert(struct node* head, struct node* temp)

    {

    struct node* previous = NULL;

    struct node* current = head;



     printf("entering insert function\n");



    // finds the previous node, where we want to insert new node

   while (temp->freq > current->freq && current->next != NULL)

  {

     printf("traversing: tempfreq is %lu and currentfreq is %lu\n", temp->freq, current->freq);
     previous = current;

    current = current->next;

   }

   if (current->next == NULL)

   {

    printf("hit end of list\n");

    temp = current->next;

   }

  else

  {

printf("inserting into list\n");

temp->next = current;

previous->next = temp;

  }  

  return head;

 }

【问题讨论】:

  • 关于您的附加问题:在树中,字母顺序消失了。如果要按字母顺序创建代码表,请创建一个包含代码和编码字母的结构的无序数组,然后按字母对该表进行排序。或者,创建一个包含所有可能字母(但可能更多,最好是所有 ASCII 字符)的数组,并将其 Huffman 代码初始化为 "" 或 null。然后在遍历树时将霍夫曼代码写入相应的字段。然后扫描数组并打印它,跳过任何空条目。
  • 我该怎么做呢?我想在我已经拥有的结构中添加一个数组吗?
  • 您需要一个单独的数据结构以及 Huffman 树。例如,您可以将 char 缓冲区添加到包含 0 和 1 字符的代码的节点结构中。然后创建指向(现有)节点的指针的线性数组。

标签: c insert linked-list huffman-code


【解决方案1】:

当您到达列表末尾时,您插入错误。这个:

temp = current->next;

应该反过来,否则你只需将NULL 分配给一个临时变量,它不会对你的列表做任何事情。

但我认为你也弄错了你的特殊情况。特例不是“在末尾插入”,而是“插入新的头部”。如果head == NULL,您的代码将失败。 (这可能不会发生,因为您已经有一个没有子节点的节点列表,并且您删除节点直到只剩下一个节点,但仍然存在。)

因此,更好的实现可能是:

struct node *insert(struct node *head, struct node *temp)
{
    struct node *previous = NULL;
    struct node *current = head;

    while (current && temp->freq > current->freq) {
        previous = current;
        current = current->next;
    }

    if (previous == NULL) {
        temp->next = head;
        return temp;
    }

    temp->next = current;
    previous->next = temp;

    return head;
}

请注意,当 currentpreviousNULL 时,此代码永远不会取消引用。 current == NULL 时,您的特殊情况“在末尾插入”由常规代码处理。

编辑:关于您按字母顺序打印节点的请求:有很多可能性可以做到这一点。一种是在包含字母编码的结构中添加一个字符缓冲区:

struct node {
    int value;
    unsigned long freq;
    struct node *next;
    struct node *left;
    struct node *right;
    char code[32];
};

然后您创建一个“字母表”,即指向 Huffman 树节点的 256 个指针的列表,最初全部为空。 (无论如何,您都需要该字母表进行编码。)

struct node *alpha[256] = {NULL};

然后遍历你的树,传递一个临时的 char 缓冲区并根据需要将节点分配给你的字母表:

void traverse(struct node *n, int level, char buf[], struct node *alpha[])
{
    if (n == NULL) return;

    if (n->value) {
        alpha[n->value] = n;
        strcpy(n->code, buf);
    } else {
        buf[level] = '0';
        traverse(n->left, level + 1, buf, alpha);
        buf[level] = '1';
        traverse(n->right, level + 1, buf, alpha);
    }
}

当节点有值,即没有子节点时,将值(ASCII码)分配给字母表,使alpha['a']指向值为'a'的节点。请注意,字母表不会创建节点,它指向现有节点。

最后,打印字母表:

char buf[32];
traverse(head, 0, buf, alphabet);

for (i = 0; i < 256; i++) {
    if (alpha[i] != NULL) {
        printf("%c: %s\n", alpha[i]->value, alpha[i]->code);
    }
}

请注意,32 是 n 个任意值,选择的值对于示例来说足够高。在真实的树中,代码的内存可能是单独分配的。

【讨论】:

  • 谢谢!但是,当两个节点具有相同的频率但 temp 的最右边的符号大于 current 的最右边的符号时,这仍然不起作用。所有只是插入像 temp->next = current & previous->next = temp;
  • 这段代码从不查看子节点,只查看直接存储在该节点的频率。我认为您不需要霍夫曼树的子节点信息。 “a”编码为 0100,“s”编码为 0101,或者相反,如果它们的频率相等,则无关紧要。
  • 对于分配,获得优先权的节点是右孩子更大的那个
  • @user3366369:您可以将&gt; 更改为&gt;=。因为当前节点由频率至少与已排序到列表中的所有其他子频率一样大的子节点组成,所以无需显式查看子节点即可工作。 (如果您要这样做,您还必须检查您比较的两个节点是否实际上个子节点,以免取消对空指针的引用。)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-03-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多