一、哈夫曼树的概念
给定n个权值作为n个叶子结点,构造一棵二叉树,若该树的带权路径长度达到最小,则称该二叉树为哈夫曼树,也被称为最优二叉树。
1、路径—从树中一个结点到另一个结点之间的分支构成这两个结点间的路径
结点路径长度—两结点间路径上的分支数
树的路径长度—根节点到每个结点路径长度之和(TL)
TL = 1+1+2+2+3+3+4+4 = 20
2、权—结点所赋的值
结点带权路径长度—从根节点到该结点间路径长度和权的乘积
树的带权路径长度—结点之和(WPL)
WPL = 7*2+5*2+2*2+4*2 = 36
(构造哈夫曼树时首先选择权值小的叶子结点,权越大离根越近)
3、哈夫曼编码
利用哈夫曼树求得的用于通信的二进制编码称为哈夫曼编码。树中从根到每个叶子节点都有一条路径,对路径上的各分支约定指向左子树的分支表示”0”码,指向右子树的分支表示“1”码,取每条路径上的“0”或“1”的序列作为各个叶子节点对应的字符编码,即是哈夫曼编码。
二、代码展示
#include<stdio.h>
#define MAX_SIZE 1000
typedef struct NODE Node;
struct NODE
{
int weight;//结点权值
int parent,lchild,rchild;
};
//初始化结点
void initNode(Node &node,int weight,int parent,int lchild,int rchild)
{
node.weight = weight;
node.parent = parent;
node.lchild = lchild;
node.rchild = rchild;
}
/*
1、n个结点,需分配n*2-1个内存空间,前n个表示新输入的结点,后n-1表示结点的父结点;
2、初始化数组,给权赋值;
3、遍历数组,标记最小结点;
4、将新结点插入最后;
5、重复3、4,最后一个结点即为根结点。
*/
void createHuffmanTree(Node *node,int *a,int n)
//n为叶子结点个数
{
int i,j,m1,m2,x1,x2,total;
for(i = 0;i < n;i++)
{
initNode(node[i],a[i],-1,-1,-1);
}
total = n*2-1;//哈夫曼树所有结点的个数
for(i = n;i < total;i++)
{
m1 = 100;
m2 = m1;
x1 = x2 =0;
for(j = 0;j < i;j++)
{
if(node[j].parent == -1)
{
if(node[j].weight < m1)
{
m2 = m1;
x2 = x1;
m1 = node[j].weight;
x1 = j;
}
else if(node[j].weight < m2)
{
m2 = node[j].weight;
x2 = j;
}
}
}
node[x1].parent = i;
node[x2].parent = i;
initNode(node[i],m1+m2,-1,x1,x2);
}
}
//哈夫曼编码
void huffmanCode(Node *node,int child,int *str)
{
int i,parent,j = 0,e;
parent = node[child].parent;//父结点
while(parent != -1)
{
if(node[parent].lchild == child)//若此结点为该父结点的左子结点,0入数组,否则1入数组
{
str[j++] = 0;
}
else
{
str[j++] = 1;
}
child = parent;
parent = node[child].parent;
}
e = j;
for(j = e-1;j >= 0;j--)
printf("%d",str[j]);
printf("\n");
}
int main()
{
Node node[MAX_SIZE];
int a1[MAX_SIZE];//存放权值
int a2[MAX_SIZE];//存放哈夫曼编码
int n,i,j,e;
printf("请输入叶子结点的个数:");
scanf("%d",&n);
for(i = 0;i < n;i++)
{
scanf("%d",&a1[i]);
}
createHuffmanTree(node,a1,n);
for(i = 0;i < n;i++)
{
huffmanCode(node,i,a2);
}
return 0;
}
请输入叶子结点的个数:8
15 14 1 25 6 24 26 12
101
100
11000
00
11001
111
01
1101