插入霍夫曼树

时间:2014-05-02 04:20:36

标签: c insert linked-list huffman-code

我的霍夫曼树出了问题;当我尝试构建它时,我将节点放在错误的位置。例如,我希望我的重量为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;

 }

1 个答案:

答案 0 :(得分:0)

当您点击列表末尾时,插入错误。这样:

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;
}

请注意,此代码在current时永远不会删除previousNULL。您的特殊情况“最后插入”由current == NULL时的常规代码处理。

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

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

然后你创建一个“字母表”,即一个256个指向你的霍夫曼树节点的指针列表,最初都是空的。 (无论如何你都需要那个字母表进行编码。)

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

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

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任意值,选择该值足够高。在实际树中,代码的内存可能会单独分配。