目的是读取文件,计算每个字符的频率并执行霍夫曼编码,其中最常见的字母将是短二进制代码,即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;
答案 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
的字符数组,所有初始化为\0
和len
的值都包含当前代码的值。
编辑2 ::
我已经看到了尝试将字符tree
节点组合成1 tree
节点的方法,将最后两个节点从升序排序数组中取出,并将它们组合起来创建一个新节点放在数组的末尾。至于我对霍夫曼编码的了解,你不要将元素与最大频率相结合,而是将元素与最低频率组合,然后形成用于查找霍夫曼代码的树。
答案 1 :(得分:0)
尝试更改
huffman -> left = array[len--];
huffman -> right = array[len--];
到
huffman -> left = array[--len];
huffman -> right = array[--len];
以获取数组的最后一个元素。