转载请注明来源:http://blog.chinaunix.net/uid-26833883-id-3158234.html
哈夫曼树的基本概念:
哈夫曼树(Huffman Tree),又叫最优二叉树,指的是对于一组具有确定权值的叶子结点的具有最小带权路径长度的二叉树。
(1)路劲(Path):从树中的一个结点到另一个结点之间的分支构成两个结点间的路径。
(2)路径长度(Path Length):路径上的分支树。
(3)树的路径长度(Path Length of Tree):从树的根结点到每个结点的路径长度之和。在结点数目相同的二叉树中,完全二叉树的路径长度最短。
(4)结点的权(Weight of Node):在一些应用中,赋予树中结点的一个有实际意义的树。
(5)结点的带权路径长度(Weight Path Length of Node):从该结点到树的根结点的路径长度与该结点的权的乘积。
(6)树的带权路径长度(WPL):树中所有叶子结点的带权路径长度之和,记为
在下图所示的四棵二叉树,都有4个叶子结点,其权值分别1、2、3、4,他们的带权路径长度分别为:
(a)WPL = 1 x 2 + 2 x 2 + 3 x 2 + 4 X 2 = 20
(b)WPL = 1 x 1 + 2 x 2 + 3 x 3 + 4 x 3 = 28
(c)WPL = 1 x 3 + 2 x 3 + 3 x 2 + 4 x 1 = 19
(d)WPL = 2 x 1 + 1 x 2 + 3 x 3 + 4 x 3 = 29
其中,(c)图所示的二叉树的带权路径长度最小,这棵树就是哈夫曼树。可以验证,哈夫曼树的带权路径长度最小。
哈夫曼树的构造算法
假设有n个权值,则构造出得哈夫曼树有n个叶子结点。n个权值分别设为w1,w2,...,wn,则哈夫曼树的构造规则为:
(1)将w1,w2,...,wn看成是有n棵树的森林(每棵树仅有一个结点);
(2)在森林中选出两个根结点的权值最小的树合并,作为一棵新树的左、右子树,且新树的根结点权值为其左、右子树根结点权值之和;
(3)从森林中删除选取的两棵树,并将新树加入森林;
(4)重复(2)、(3)步,直到森林中只剩一棵树为止,该树即为所求得的哈夫曼树。
代码如下:
#include <stdio.h>
#include <stdlib.h>
#define MAX 4
int input_weight(int *p)
{
int i = 0;
for(i = 0;i < MAX;i ++)
{
scanf("%d",p + i);
}
while(getchar()!= '\n');
return 0;
}
int order_weight(int *p)
{
int i = 0;
int j = 0;
int temp;
for(i = 0;i < MAX;i ++)
{
for(j = 0;j < MAX - i - 1;j ++)
{
if(p[j] > p[j+1])
{
temp = p[j];
p[j] = p[j+1];
p[j+1] = temp;
}
}
}
return 0;
}
//哈夫曼树结点
typedef struct HuffNode
{
int weight;
struct HuffNode *rchild;
struct HuffNode *lchild;
}HuffMan;
//队列设计
typedef struct _node_
{
HuffMan *data;
struct _node_ *next;
}ListNode;
typedef struct
{
ListNode *front;
ListNode *rear;
}Queue;
//create empty queue
Queue *create_empty_queue()
{
ListNode *HList;
Queue *Hqueue;
HList = (ListNode *)malloc(sizeof(ListNode));
HList->next = NULL;
Hqueue = (Queue *)malloc(sizeof(Queue));
Hqueue->front = Hqueue->rear = HList;
return Hqueue;
}
//入队
int EnterQueue(Queue *head,HuffMan *data)
{
ListNode *temp;
temp = (ListNode *)malloc(sizeof(ListNode));
temp->data = data;
temp->next = NULL;
head->rear->next = temp;
head->rear = temp;
return 0;
}
//有序插入结点
int OrderEnterQueue(Queue *head,HuffMan *p)
{
ListNode *m = head->front->next;
ListNode *n = head->front;
ListNode *temp;
#if 0
if(head->front->next == NULL)
{
printf("emty!\n");
temp = (ListNode *)malloc(sizeof(ListNode));
temp->data = p;
temp->next = NULL;
n->next = temp;
head->rear = temp;
}
#endif
while(m)
{
if(m->data->weight < p->weight)
{
m = m->next;
n = n->next;
}
else{
break;
}
}
//插到最后一个结点
if(m == NULL)
{
temp = (ListNode *)malloc(sizeof(ListNode));
temp->data = p;
temp->next = NULL;
n->next = temp;
head->rear = temp;
}
//插入中间结点
temp = (ListNode *)malloc(sizeof(ListNode));
temp->data = p;
n->next = temp;
temp->next = m;
return 0;
}
//判断队列是否为空(注意,我们认为队列含有一个结点为空,想想为什么
//这样做?
int is_empty_queue(Queue *head)
{
if(head->front->next->next == NULL)
{
printf("is_empty_queue\n");
return 1;
}
return 0;
}
//出队
HuffMan *DeleteQueue(Queue * head)
{
ListNode *temp;
temp = head->front;
head->front = temp->next;
free(temp);
temp = NULL;
return head->front->data;
}
//将结点按权值从小到大放入队列
int create_forest(Queue *head,int *p)
{
int i = 0;
HuffMan *temp;
for(i = 0;i < MAX;i ++)
{
temp = (HuffMan *)malloc(sizeof(HuffMan));
temp->weight = p[i];
temp->rchild = temp->rchild = NULL;
EnterQueue(head,temp);
}
return 0;
}
//创建哈夫曼树
HuffMan *create_huffman_tree(Queue *head)
{
HuffMan *right,*left,*current;
//循环结束时,队列只含有一个结点
while(!is_empty_queue(head))
{
left = DeleteQueue(head);
right = DeleteQueue(head);
current = (HuffMan *)malloc(sizeof(HuffMan));
current->weight = left->weight + right->weight;
current->rchild = right;
current->lchild = left;
#if 0
printf("%d\n",left->weight);
printf("%d\n",right->weight);
printf("%d\n",current->weight);
#endif
OrderEnterQueue(head,current);
}
return head->front->next->data;
}
//访问结点
int vist_node(HuffMan *p)
{
printf("%d ",p->weight);
return 0;
}
//树的中序遍历
int InOrder(HuffMan *p)
{
if(p != NULL)
{
InOrder(p->lchild);//左
vist_node(p);//根
InOrder(p->rchild);//右
}
return 0;
}
int main()
{
int Wbuf[MAX];
Queue *head;
HuffMan *root;
//输入权值
input_weight(Wbuf);
//排序权值
order_weight(Wbuf);
//创建空队列
head = create_empty_queue();
//将结点按权值从小到大放入队列
create_forest(head,Wbuf);
//创建哈夫曼树
root = create_huffman_tree(head);
//中序遍历
InOrder(root);
printf("\n");
return 0;
}
结果如下: