昨天老师讲完了哈夫曼书,回到宿舍就开始写,到今天才算是通过。题目如下:
分析一下题目,首先要构建一个哈夫曼树,然后先输出编码,再根据编码进行译码并输出。
构建哈夫曼树,就是取所有数据中权重最小的两个,组成一个小树,这个小树的权重就是这两个数据权重之和,然后反复进行这个操作(已成为叶节点的数据不再进行权重比较),就可以得到一课哈夫曼书。这里并没有用二叉链表来存储,而是使用了一种顺序结构(记录下左支右支和父节点位置),这样也可以实现。若输入: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"); }
以上就是我的实现,希望给大家带来帮助。