给定一组权值,根据权值求其一个哈夫曼树,并通过中序遍历的顺序输出叶子节点的哈夫曼编码。
首先回顾哈夫曼树的求解过程:
一个重要的点是我们希望输入的权值有序,并且时刻保持有序,因此选用链表来存储权重,并每次插入时都按序排序,接下来只要用代码实现上述步骤便可完成哈夫曼树的构建;
那么如何得到叶子节点的哈夫曼编码呢?
考虑使用递归为每个节点都分配一个编码,储存在树节点中。
struct node
{
int weight, idx;
struct node *parent, *lchild, *rchild;
char *code;
};
struct linknode
{
int info;
struct linknode *next;
struct node *tree;
};
typedef struct linknode *Plink;
typedef struct node *Ptree;
Ptree createNULLtree()
{
Ptree head = (Ptree)malloc(sizeof(struct node));
if (head == NULL)
printf("fail to create tree node!\n");
head->parent = NULL;
head->lchild = NULL;
head->rchild = NULL;
head->idx = 0;
head->code = (char *)malloc(sizeof(char) * 10);
return head;
}
Plink createNULLlink()
{
Plink head = (Plink)malloc(sizeof(struct linknode));
if (head == NULL)
printf("fail to create link node!\n");
head->next = NULL;
head->tree = NULL;
return head;
}
树节点中包含指向父亲节点和孩子节点的指针、权值、以及储存着编码的code和编码长度索引idx;
链表节点中包含权值大小info、指向下个节点的next指针以及指向权值对应树节点的tree指针。
void insertwithorder(Plink head, int x, Ptree tree)
{
Plink cur = head->next, last = head;
if (tree == NULL)
tree = createNULLtree();
tree->weight = x;
while (cur != NULL)
{
if (x <= cur->info)
{
last->next = createNULLlink();
last->next->info = x;
last->next->tree = tree;
last->next->next = cur;
return;
}
last = cur;
cur = cur->next;
}
last->next = createNULLlink();
last->next->info = x;
last->next->tree = tree;
last->next->next = cur;
}
将数据有序插入链表,小数据在前,插入和删除都比较方便
int is_over(Plink head)
{
if (head->next->next == NULL)
return 1;
return 0;
}
判断是否应该结束程序,当链表中仅剩一个数据时结束
void LDR(Ptree head)
{
if (head == NULL)
return;
LDR(head->lchild);
visitleaf(head);
LDR(head->rchild);
}
中序遍历
void visitleaf(Ptree head)
{
if (head->lchild == NULL && head->rchild == NULL)
printf("%d %s\n", head->weight, head->code);
}
只打印叶子节点的信息
使用两个权值来创建一个二叉树,根节点权值为两权值之和;
实现过程中由于不仅仅需要链表节点的权值信息,所以没有单独使用函数实现这个这个功能;
大致流程如下:
void createBiTree(Plink Link)
{
if (is_over(Link))
return;
int nums[2]; //储存两个权值
Plink temp = Link->next;
Ptree p = createNULLtree(), lch, rch;
nums[0] = temp->info;
lch = temp->tree;
Link->next = temp->next;
free(temp);
temp = Link->next;
nums[1] = temp->info;
rch = temp->tree;
Link->next = temp->next;
free(temp);
p->weight = nums[0] + nums[1];
p->lchild = lch;
p->rchild = rch;
lch->weight = nums[0];
rch->weight = nums[1];
lch->parent = p;
rch->parent = p;
insertwithorder(Link, p->weight, p);
createBiTree(Link);
}
void encode(Ptree head, char info)
{
if (head == NULL)
return;
if (head->parent != NULL)
{
strcpy(head->code, head->parent->code);
head->idx = strlen(head->code);
}
head->code[head->idx++] = info;
head->code[head->idx] = '\0';
encode(head->lchild, '0');
encode(head->rchild, '1');
}
encode函数接收树节点和一个字符变量,左子树接收’0’,右子树接收‘1’,并且每个树节点会copy父亲节点的code信息,如此递归,便完成了编码。
int main()
{
int num, temp;
Plink linkhead = createNULLlink();
scanf("%d", &num);
for (int i = 0; i < num; i++)
{
scanf("%d", &temp);
insertwithorder(linkhead, temp, NULL);
}
createBiTree(linkhead);
Ptree treehead = linkhead->next->tree;
if (treehead == NULL)
printf("wrong!");
encode(treehead, '\0');
LDR(treehead);
return 0;
}
至此便完成了题目要求。
#include
#include
#include
struct node
{
int weight, idx;
struct node *parent, *lchild, *rchild;
char *code;
};
struct linknode
{
int info;
struct linknode *next;
struct node *tree;
};
typedef struct linknode *Plink;
typedef struct node *Ptree;
Ptree createNULLtree()
{
Ptree head = (Ptree)malloc(sizeof(struct node));
if (head == NULL)
printf("create tree wrongly!\n");
head->parent = NULL;
head->lchild = NULL;
head->rchild = NULL;
head->idx = 0;
head->code = (char *)malloc(sizeof(char) * 10);
return head;
}
Plink createNULLlink()
{
Plink head = (Plink)malloc(sizeof(struct linknode));
if (head == NULL)
printf("create link wrongly!\n");
head->next = NULL;
return head;
}
void insertwithorder(Plink head, int x, Ptree tree)
{
Plink cur = head->next, last = head;
if (tree == NULL)
tree = createNULLtree();
tree->weight = x;
while (cur != NULL)
{
if (x <= cur->info)
{
last->next = createNULLlink();
last->next->info = x;
last->next->tree = tree;
last->next->next = cur;
return;
}
last = cur;
cur = cur->next;
}
last->next = createNULLlink();
last->next->info = x;
last->next->tree = tree;
last->next->next = cur;
}
int is_over(Plink head)
{
if (head->next->next == NULL)
return 1;
return 0;
}
void createBiTree(Plink Link)
{
if (is_over(Link))
return;
int nums[2];
Plink temp = Link->next;
Ptree p = createNULLtree(), lch, rch;
nums[0] = temp->info;
lch = temp->tree;
Link->next = temp->next;
free(temp);
temp = Link->next;
nums[1] = temp->info;
rch = temp->tree;
Link->next = temp->next;
free(temp);
p->weight = nums[0] + nums[1];
p->lchild = lch;
p->rchild = rch;
lch->weight = nums[0];
rch->weight = nums[1];
lch->parent = p;
rch->parent = p;
insertwithorder(Link, p->weight, p);
createBiTree(Link);
}
void encode(Ptree head, char info)
{
if (head == NULL)
return;
if (head->parent != NULL)
{
strcpy(head->code, head->parent->code);
head->idx = strlen(head->code);
}
head->code[head->idx++] = info;
head->code[head->idx] = '\0';
encode(head->lchild, '0');
encode(head->rchild, '1');
}
void visitleaf(Ptree head)
{
if (head->lchild == NULL && head->rchild == NULL)
printf("%d %s\n", head->weight, head->code);
}
void LDR(Ptree head)
{
if (head == NULL)
return;
LDR(head->lchild);
visitleaf(head);
LDR(head->rchild);
}
int main()
{
int num, temp;
Plink linkhead = createNULLlink();
scanf("%d", &num);
for (int i = 0; i < num; i++)
{
scanf("%d", &temp);
insertwithorder(linkhead, temp, NULL);
}
createBiTree(linkhead);
Ptree treehead = linkhead->next->tree;
if (treehead == NULL)
printf("wrong!");
encode(treehead, '\0');
LDR(treehead);
return 0;
}