昨天老师讲完了哈夫曼书,回到宿舍就开始写,到今天才算是通过。题目如下:
分析一下题目,首先要构建一个哈夫曼树,然后先输出编码,再根据编码进行译码并输出。
构建哈夫曼树,就是取所有数据中权重最小的两个,组成一个小树,这个小树的权重就是这两个数据权重之和,然后反复进行这个操作(已成为叶节点的数据不再进行权重比较),就可以得到一课哈夫曼书。这里并没有用二叉链表来存储,而是使用了一种顺序结构(记录下左支右支和父节点位置),这样也可以实现。若输入:3 a b c 1 2 4,则可以构建出如下的哈夫曼树:
而进行编码时只要找到需编码数据在树中位置,再循环判断当前节点是其父节点的左支还是右支,若是左支则记录0,右支记录1,直到当前节点为头结点,就可得到需编码数据编码的逆序,再将它反过来就是所求编码。a在上个哈夫曼树中编码如下图:
而到解码时,只需要从头结点开始走,0走左支1走右支,直到走到叶节点为止,叶节点中数据就是所求数据。01在上个哈夫曼树中解码如下图:
以下是我的实现:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct huffmanNode
{
char data;
int weight;
int parent;
int left;
int right;
};
struct huffmanTree
{
struct huffmanNode node[200];
int n;
};
void run ();
void putInData (struct huffmanTree *T);
void clear (struct huffmanNode *node);
void createNewTree (struct huffmanTree *T);
int findTwoMin (struct huffmanTree *T,int *min1,int *min2,int *weight);
int getCode (int A[],struct huffmanTree *T);
void printCode (int A[],int length);
int getEnCode (int A[],char B[],struct huffmanTree *T,int length1);
void printEnCode (char B[],int length);
int main()
{
run ();
return 0;
}
void run ()
{
struct huffmanTree T;
putInData(&T);
createNewTree (&T);
int A[2000]={0},length1;
length1=getCode (A,&T);
printCode (A,length1);
char B[2000]={0},length2;
length2=getEnCode (A,B,&T,length1);
printEnCode (B,length2);
}
void putInData (struct huffmanTree *T)
{
int i,n;
scanf ("%d",&(T->n));
n=T->n;
clear (&(T->node[0]));
for (i=1;i<=n;i++)
{
clear (&(T->node[i]));
getchar();
T->node[i].data=getchar();
}
for (i=1;i<=n;i++)
{
scanf ("%d",&(T->node[i].weight));
}
}
void clear (struct huffmanNode *node)
{
node->data='\0';
node->weight=0;
node->parent=0;
node->left=0;
node->right=0;
}
void createNewTree (struct huffmanTree *T)
{
int min1,min2,weight;
while (findTwoMin (T,&min1,&min2,&weight))
{
++(T->n);
clear (&(T->node[T->n]));
T->node[T->n].left=min1;
T->node[T->n].right=min2;
T->node[T->n].weight=weight;
T->node[min1].parent=T->n;
T->node[min2].parent=T->n;
}
}
int findTwoMin (struct huffmanTree *T,int *min1,int *min2,int *weight)
{
int i,n,m;
int minWeight1=2147483647;
int minWeight2=2147483647;
for (i=1,n=T->n;i<=n;i++)
{
if (!(T->node[i].parent))
{
m=T->node[i].weight;
if (m<minWeight2)
{
if (m>minWeight1)
{
minWeight2=m;
*min2=i;
}
else
{
minWeight2=minWeight1;
minWeight1=m;
*min2=*min1;
*min1=i;
}
}
}
}
if ((minWeight1!=2147483647)&&(minWeight2!=2147483647))
{
*weight=T->node[*min1].weight+T->node[*min2].weight;
return 1;
}
else
{
return 0;
}
}
int getCode (int A[],struct huffmanTree *T)
{
int length=0,n,i,j,parent;
char s[200]={0};
getchar ();
gets (s);
n=strlen (s);
for (i=n-1;i>=0;i--)
{
for (j=1;j<=T->n;j++)
{
if (s[i]==T->node[j].data)
{
parent=j;
break;
}
}
while (T->node[parent].parent)
{
if (T->node[T->node[parent].parent].left==parent)
{
A[length]=0;
}
else
{
A[length]=1;
}
length++;
parent=T->node[parent].parent;
}
}
return length-1;
}
void printCode (int A[],int length)
{
int i;
for (i=length;i>=0;i--)
{
printf ("%d",A[i]);
}
printf ("\n");
}
int getEnCode (int A[],char B[],struct huffmanTree *T,int length1)
{
int i,length2=0,cur,head;
head=T->n;
for (i=length1,cur=head;i>=0;i--)
{
if (A[i])
{
cur=T->node[cur].right;
if (!(T->node[cur].right))
{
B[length2]=T->node[cur].data;
length2++;
cur=head;
}
}
else
{
cur=T->node[cur].left;
if (!(T->node[cur].left))
{
B[length2]=T->node[cur].data;
length2++;
cur=head;
}
}
}
return length2-1;
}
void printEnCode (char B[],int length)
{
int i;
for (i=0;i<=length;i++)
{
printf ("%c",B[i]);
}
printf ("\n");
}
以下是各函数的注释:
void run ()
{
struct huffmanTree T;
putInData(&T);//输入数据
createNewTree (&T);//构建哈夫曼树
int A[2000]={0},length1;
length1=getCode (A,&T);//得到编码
printCode (A,length1);//输出编码
char B[2000]={0},length2;
length2=getEnCode (A,B,&T,length1);//得到解码
printEnCode (B,length2);//输出解码
}
void putInData (struct huffmanTree *T)
{
int i,n;
scanf ("%d",&(T->n));//输入数据个数
n=T->n;
clear (&(T->node[0]));//节点初始化
for (i=1;i<=n;i++)//循环输入数据
{
clear (&(T->node[i]));
getchar();
T->node[i].data=getchar();
}
for (i=1;i<=n;i++)//循环输入权重
{
scanf ("%d",&(T->node[i].weight));
}
}
void clear (struct huffmanNode *node)
{
node->data='\0';//初始化都设为0
node->weight=0;
node->parent=0;
node->left=0;
node->right=0;
}
void createNewTree (struct huffmanTree *T)
{
int min1,min2,weight;
while (findTwoMin (T,&min1,&min2,&weight))//如果能找出最小的两个权重的数据所在位置,就循环
{
++(T->n);//创建新节点
clear (&(T->node[T->n]));//新节点初始化
T->node[T->n].left=min1;//新节点左支赋值
T->node[T->n].right=min2;//新节点右支赋值
T->node[T->n].weight=weight;//新节点权重赋值
T->node[min1].parent=T->n;//最小权重的父赋值
T->node[min2].parent=T->n;//第二小权重的父赋值
}
}
int findTwoMin (struct huffmanTree *T,int *min1,int *min2,int *weight)
{
int i,n,m;
int minWeight1=2147483647;
int minWeight2=2147483647;
for (i=1,n=T->n;i<=n;i++)//循环判断每一个节点
{
if (!(T->node[i].parent))//若其无头结点(无头结点说明其未组成小树)
{
m=T->node[i].weight;
if (m<minWeight2)//判断是否最小或第二小,并赋值
{
if (m>minWeight1)
{
minWeight2=m;
*min2=i;
}
else
{
minWeight2=minWeight1;
minWeight1=m;
*min2=*min1;
*min1=i;
}
}
}
}
if ((minWeight1!=2147483647)&&(minWeight2!=2147483647))//如果找到
{
*weight=T->node[*min1].weight+T->node[*min2].weight;//权重赋值
return 1;//返回真,循环继续
}
else/如果未找到
{
return 0;//返回假,循环停止
}
}
int getCode (int A[],struct huffmanTree *T)//编码
{
int length=0,n,i,j,parent;
char s[200]={0};
getchar ();
gets (s);//得到需编码数据串
n=strlen (s);//得到其长度
for (i=n-1;i>=0;i--)//循环每一个数据元素
{
for (j=1;j<=T->n;j++)//在树中寻找到其位置
{
if (s[i]==T->node[j].data)
{
parent=j;
break;
}
}
while (T->node[parent].parent)//如果它无父,说明到达头结点,结束,否则继续循环
{
if (T->node[T->node[parent].parent].left==parent)//如果是左支
{
A[length]=0;//记录0
}
else//同上
{
A[length]=1;
}
length++;//编码记录数组长度加一
parent=T->node[parent].parent;
}
}
return length-1;//返回编码记录数组最后一个数据的位置
}
void printCode (int A[],int length)
{
int i;
for (i=length;i>=0;i--)//逆序输出编码记录数组
{
printf ("%d",A[i]);
}
printf ("\n");
}
int getEnCode (int A[],char B[],struct huffmanTree *T,int length1)//解码
{
int i,length2=0,cur,head;
head=T->n;
for (i=length1,cur=head;i>=0;i--)//循环编码记录数组每一个数据
{
if (A[i])//如果是1
{
cur=T->node[cur].right;//走右支
if (!(T->node[cur].right))//如果本节点是叶节点
{
B[length2]=T->node[cur].data;//记录解码数据
length2++;//解码记录数组长度加一
cur=head;//从头开始
}
}
else//同上
{
cur=T->node[cur].left;
if (!(T->node[cur].left))
{
B[length2]=T->node[cur].data;
length2++;
cur=head;
}
}
}
return length2-1;//返回解码记录数组最后一个数据的位置
}
void printEnCode (char B[],int length)
{
int i;
for (i=0;i<=length;i++)//输出解码记录数组
{
printf ("%c",B[i]);
}
printf ("\n");
}
以上就是我的实现,希望给大家带来帮助。