我的霍夫曼树出了问题;当我尝试构建它时,我将节点放在错误的位置。例如,我希望我的重量为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;
}
答案 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
时永远不会删除previous
或NULL
。您的特殊情况“最后插入”由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任意值,选择该值足够高。在实际树中,代码的内存可能会单独分配。