在计算机数据处理中,哈夫曼编码使用变长编码表对源符号(如文件中的一个字母)进行编码,其中变长编码表是通过一种评估来源符号出现机率的方法得到的,出现机率高的字母使用较短的编码,反之出现机率低的则使用较长的编码,这便使编码之后的字符串的平均长度、期望值降低,从而达到无损压缩数据的目的。
//哈夫曼树及哈夫曼编码
#include<stdio.h>
#include<stdlib.h>
#define MAXSIZE 30
typedef struct node
{
int data;//节点数据
struct node* lchild, * rchild;//定义左右孩子指针
struct node* next;//单链表节点,next为节点指针
}BSTree_Link;//二叉树单链表节点类型
BSTree_Link* CreateLinkList(int n); //根据叶子节点的权值生成一个升序单链表
void print(BSTree_Link* h);//输出单链表
BSTree_Link* HuffTree(BSTree_Link* Link);//生成哈夫曼树
void Inorder(BSTree_Link* p);//中序遍历二叉树
void Preorder(BSTree_Link* p);//先序遍历二叉树
void HuffCode(BSTree_Link* p);//后序遍历哈夫曼树并输出哈夫曼编码
void main()
{
BSTree_Link* root;
int n;
printf("请输入叶子节点个数:\n");
scanf("%d", &n);
printf("请输入节点的权值:\n");
root = CreateLinkList(n);
printf("输出生成的升序单链表:\n");
print(root);
root = HuffTree(root);//生成哈夫曼树
printf("先序遍历输出哈夫曼树个结点的值:\n");
Preorder(root);
printf("\n");
printf("中序遍历输出哈夫曼树个结点的值:\n");
Inorder(root);
printf("后序遍历输出哈夫曼树个节点的值:\n");
HuffCode(root);
}
BSTree_Link* CreateLinkList(int n) //根据叶子节点的权值生成一个升序单链表
{
BSTree_Link* link, * p, * q, * s;
int i;
link = (BSTree_Link*)malloc(sizeof(BSTree_Link));//生成单链表的头节点
s = (BSTree_Link*)malloc(sizeof(BSTree_Link));//生成单链表第一个数据节点,即哈夫曼树的叶节点
scanf("%d", &s->data);//输入叶子节点权值
s->lchild = NULL;
s->rchild = NULL;
s->next = NULL;
link->next = s;
for (i = 2; i <= n; i++)
{
s = (BSTree_Link*)malloc(sizeof(BSTree_Link));//生成一个数据节点
scanf("%d", &s->data);
s->lchild = NULL;
s->rchild = NULL;
q = link;//按照升序插入单链表
p = q->next;
while(p != NULL)
if (s->data > p->data)//查找插入位置后进行插入
{
q = p;
p = p->next;
}
else
{
q->next = s;
s->next = p;
break;
}
if (s-> data > q->data)
{
q->next = s;
s->next = p;
}
return link;
}
}
void print(BSTree_Link* h)//输出单链表
{
BSTree_Link* p;
p = h->next;
while (p != NULL)
{
printf("%d,", p->data);
p = p->next;
}
printf("\n");
}
BSTree_Link* HuffTree(BSTree_Link* link)//生成哈夫曼树
{
BSTree_Link* p, * q, * s;
while (link->next != NULL)
{
p = link->next;
q = p->next;
link->next = q->next;
s = (BSTree_Link*)malloc(sizeof(BSTree_Link));
s->data = p->data + q->data;
s->lchild = p;
s->lchild = q;
q = link;
p = q->next;
while(p!=NULL)
if (s->data > p->data)
{
q = p;
p = p->next;
}
else
{
q->next = s;
s->next = p;
break;
}
if (q != link && s->data > q->data)
{
q->next = s;
s->next = p;
}
}
return s;
}
void Inorder(BSTree_Link* p)//中序遍历二叉树
{
if (p != NULL)
{
Inorder(p->lchild);
printf("%4d", p->data);
Inorder(p->rchild);
}
}
void Preorder(BSTree_Link* p)//先序遍历二叉树
{
if (p != NULL)
{
printf("%4d", p->data);
Preorder(p->lchild);
Preorder(p->rchild);
}
}
void HuffCode(BSTree_Link* p)//后序遍历哈夫曼树并输出哈夫曼编码
{
BSTree_Link* q, * stack[MAXSIZE];
int b, i = -1, j = 0, k, code[MAXSIZE];
do
{
while (p != NULL)
{
if (p->lchild == NULL && p->rchild == NULL)
{
printf("叶节点信息:key=%3d,code:", p->data);
for (k = 0; k < j; k++)
printf("%d", code[k]);
printf("%d", code[k]);
printf("\n");
j--;
}
stack[++i] = p;
p = p->lchild;
code[j++] = 0;
}
q = NULL;
b = 1;
while (i >= 0 && b)
{
p = stack[i];
if (p->rchild == q)
{
i--; j--;
q = p;
}
else
{
p = p->rchild;
code[j++] = 1;
b = 0;
}
}
} while (i >= 0);
}