分配二叉树值(霍夫曼编码)

时间:2015-12-07 15:06:13

标签: c linked-list binary-tree huffman-code

目的是读取文件,计算每个字符的频率并执行霍夫曼编码,其中最常见的字母将是短二进制代码,即001,最不常见的字母将更长,即01000100。

我创建了一个链表,其中包含所有字符及其各自频率的排序(按升序排列)列表。这将传递给下面的函数。在这个函数中,我的目标是添加两个最低频率并构建二进制树,直到树的长度为1.我不知道从哪里开始,我知道我必须透过树看看在哪个阶段向左或向右,然后存储0(左)或1(右)。 - 但我不知道如何建立一个功能来做到这一点!

void traverse_list(pqueue *list)
    {
    char letters[CHARACTERS] = { 0 };
    int frequencies[CHARACTERS] = { 0 };
    int j = 0, l = 0, len = 0;
    node *temp = list->head;
    tree *array[CHARACTERS];
    while (temp != NULL)
    {
        letters[j] = temp->letter;
        frequencies[j] = temp -> frequency;
        temp = temp->next;
        j++;
    }
    for (l = 0; l < CHARACTERS; l++)
    {
        if (frequencies[j])
        {
            tree* huffman = calloc(1, sizeof(tree));
            huffman -> letter = letters[l];
            huffman -> frequency = frequencies[l];
            array[len++] = huffman;
        }
    }

    while (len > 1)
    {
        tree* huffman = malloc(sizeof(tree));
        huffman -> left = array[len--];
        huffman -> right = array[len--];
        huffman -> frequency = huffman -> left -> frequency + huffman -> right -> frequency;
        array[len++] = huffman;
    } 
}

为了便于阅读,结构看起来像:

typedef struct Node
{
    char letter;
    int frequency;
    struct Node *next;

}node;

typedef struct pqueue
{
    node *head;

}pqueue;

typedef struct tree
{
    struct tree *left;
    struct tree *right;
    char letter;
    int frequency;
}tree;

2 个答案:

答案 0 :(得分:1)

我不明白为什么要创建这么多数组然后再使用它们再次创建新节点。我认为这可以通过修改Node的结构轻松完成。像这样的东西::

typedef struct Node
{
    char letter;
    int frequency;
    struct Node *next;
    struct Node *left, *right;
}node;

因此,您可以执行以下操作来形成树。

void huffman(plist *list) {
    while(1) {
        node *left = list->head;
        list->head = list->head->next;
        node *right = list->head;
        list->head = list->head->next;

        node *huffman = malloc(sizeof(node));
        huffman->frequency = left->frequency;
        huffman->left = left;
        huffman->right = right;
        huffman->next = NULL;

        if(list->head == NULL) {
            list->head = huffman;
            break;
        }
        insertHuffman(root, huffman);
    }
}

您的insertHuffman()只会按排序顺序在node中插入新的pList。所以,最后你在树中只剩下一个node,然后你可以简单地进行遍历来决定每个节点的值。你绝对可以选择比我使用的while(1)更好的条件! :P我用它是因为这是我想到的第一件事。你绝对可以写insertHuffman()我相信。

修改::

void printHuffman(node *head, node *parent, char *a, int len) {
    if(head->left == NULL && head->right == NULL) {
        if(parent != NULL && parent->right == head) {
            cout << head->letter << " " << a << "1";
        } else if(parent != NULL && parent->left == head) {
            cout << head->letter << " " << a;
        }
    } else {
        a[len] = '0';
        printHuffman(head->left, head, a, len + 1);
        a[len] = '1';
        printHuffman(head->right, head, a, len + 1);
    }
}

我认为这将打印每个角色的霍夫曼的价值观。

此处,a是大小为CHARACTERS的字符数组,所有初始化为\0len的值都包含当前代码的值。

编辑2 ::

我已经看到了尝试将字符tree节点组合成1 tree节点的方法,将最后两个节点从升序排序数组中取出,并将它们组合起来创建一个新节点放在数组的末尾。至于我对霍夫曼编码的了解,你不要将元素与最大频率相结合,而是将元素与最低频率组合,然后形成用于查找霍夫曼代码的树。

答案 1 :(得分:0)

尝试更改

        huffman -> left = array[len--];
        huffman -> right = array[len--];

        huffman -> left = array[--len];
        huffman -> right = array[--len];

以获取数组的最后一个元素。