哈夫曼树上机实验报告
霍夫曼树
实验目的:
掌握结构体、指针及二叉树的生成、遍历等操作掌握霍夫曼编码/译码的原理。
基本要求:
熟练掌握树的操作。
程序实现:
程序第一遍统计原数据中各字符出现的频率,利用得到的频率值创建哈夫曼树,并把树的信息保存起来,以便解压时创建同样的哈夫曼树进行解压;第二遍,根据第一遍扫描得到的哈夫曼树进行编码,并把编码后的码字存储。
要点分析:
题目中涉及的主要知识点:
1、本程序参考霍夫曼算法(由给定的权值构造赫夫曼树):
(1)由给定的n个权值{w0, w1, w2, …, wn-1},构造具有n棵二叉树的集合F ={T0, T1, T2, …, Tn-1},其中每一棵二叉树Ti只有一个带有权值wi的根结点,其左、右子树均为空。
(2)重复以下步骤, 直到F中仅剩下一棵树为止:①在F中选取两棵根结点的权值最小的二叉树, 做为左、右子树构造一棵新的二叉树。置新的二叉树的根结点的权值为其左、右子树上根结点的权值之和。②在F中删去这两棵二叉树。③把新的二叉树加入F。
2、用构造赫夫曼树以完成赫夫曼编码:把d1,d2,…, dn 作为叶子
结点,把w1,w2,…,wn作为叶子结点的权,构造赫夫曼树。在赫夫曼树中结点的左分支赋0,右分支赋1,从根结点到叶子结点的路径上的数字拼接起来就是这个叶子结点字符的编码。
3、译码的过程是分解电文中的字符串,从根出发,按字符‘0’或‘1’确定找左孩子或右孩子,直至叶子节点,便求得该子串相应的字符。心得体会:
通过本次实验,我熟练掌握了结构体、指针及二叉树的生成、遍历等操作,掌握了霍夫曼编码和译码的原理,熟练掌握树的操作,尤其是对霍夫曼树有了更深刻的理解。同时,在编写代码的过程中方,对字符串的相关知识进行了回顾。
代码
#include
#include
#include
typedef struct
{
int weight;
int parent,lchild,rchild;
int sign;
}HTNode,*HuffmanTree;
typedef char * *HuffmanCode;
void HuffmanCoding(HuffmanTree &HT,HuffmanCode &HC,int *w,int n,char *s);
void select(HuffmanTree &HT,int i,int &s1,int &s2);
void creatHuffmanTree(int *w,char *s,char *r);
void pr(HuffmanCode &HC,char r[],char s,char a[]);
void HuffmanYM(HuffmanCode &HC,char r[],char a[],int n,HuffmanTree &HT);
void HuffmanPass(HuffmanCode &HC,char r[],int n,HuffmanTree &HT);
int main()
{
char s[100];
char r[100];
char a[100]="a";
int w[100];
int n,p;
HuffmanTree HT;
HuffmanCode HC;
printf("请输入进行编码的字符串\n");
scanf("%s",s);
p=strlen(s);
if(p!=1)creatHuffmanTree(w,s,r);
printf("进行编码......\n");
if(p!=1)
HuffmanCoding(HT,HC,w,strlen(r)-1,r);
else printf("%c的霍夫曼编码是: %c\n",s[0],'0');
printf("霍夫曼码序列为:\n");
if(p!=1)
for(int i=0;i pr(HC,r,s[i],a); printf("\n"); n=strlen(r)-1; if(p==1)printf("0\n"); printf("霍夫曼编码进行译码:\n"); if(p==1) printf("%c",s[0]); else HuffmanYM(HC,r,a,n,HT); printf("\n"); printf("先序遍历输出叶子节点\n"); if(p==1) { printf("%c\n",s[0]); } else HuffmanPass(HC,r,n,HT); return 0; } void HuffmanCoding(HuffmanTree &HT,HuffmanCode &HC,int w[],int n,char s[]) { int s1,s2,f,c; int m,i,l; int start; char cd[101]; if(n<1)return; l=strlen(s); m=2*n-1; HT=(HuffmanTree)malloc((m+1)*sizeof(HTNode)); HT[0].weight=10000; for (i=1;i<=n;++i) { HT[i].weight=w[i-1]; HT[i].parent=0; HT[i].lchild=0; HT[i].rchild=0; HT[i].sign=0; } for(;i<=m+1;++i) { HT[i].weight=0; HT[i].parent=0; HT[i].lchild=0; HT[i].rchild=0; HT[i].sign=0; } for(i=n+1;i<=m;i++) { select(HT,i-1,s1,s2);//选择最小的两个结点 HT[s1].parent=i;HT[s2].parent=i;//将它们的父节点赋值 HT[i].lchild=s1;HT[i].rchild=s2; HT[i].weight=HT[s1].weight+HT[s2].weight; } HC=(HuffmanCode)malloc((n+1)*sizeof(char *)); cd[n-1]='\0'; for(i=1;i<=n;i++) { start=n; c=i; for(f=HT[i].parent;f!=0;f=HT[f].parent) { if(HT[f].lchild==c) { start--; cd[start]='0'; } else { start--; cd[start]='1'; } c=f; } HC[i]=(char *)malloc((n-start)*sizeof(char)); for(int a=0;a { HC[i][a]=cd[start+a]; } HC[i][a]='\0'; printf("%c的霍夫曼编码是: %s\n",s[i],HC[i]); } } void select(HuffmanTree &HT,int i,int &s1,int &s2) { s1=0; s2=0; for(int j=1;j<=i;j++) { if(HT[j].parent==0) if(HT[j].weight<=HT[s1].weight) s1=j; else continue; } else continue; } for(j=1;j<=i;j++) { if(j==s1)continue; else if(HT[j].parent==0) { if(HT[j].weight<=HT[s2].weight) s2=j; else continue; } else continue; } } void creatHuffmanTree(int w[],char s[],char r[]) { int g=1; int q=0; r[0]='0'; r[1]=s[0]; w[0]=1; for(int e=1;e { for(int k=1;k<=g;k++) { if(r[k]==s[e]) { w[k-1]++; q=1; } else continue; } if(q==0) { r[++g]=s[e]; w[g-1]=1; q=0; } r[++g]='\0'; } void pr(HuffmanCode &HC,char r[],char s,char a[]) { for(int i=1;i { if(r[i]==s) { printf("%s",HC[i]); strcat(a,HC[i]); } else continue; } } void HuffmanYM(HuffmanCode &HC,char r[],char a[],int n,HuffmanTree &HT) { int e=strlen(a); int k=0; int f=2*n-1; char b[10]="1"; for(int j=1;j<=e;j++) { if(HT[f].lchild!=0||HT[f].rchild!=0) { b[k]=a[j]; k++; if(a[j]=='1') f=HT[f].rchild; else if(a[j]=='0') f=HT[f].lchild; } else { for(int s=1;s<=n;s++) { if(strcmp(HC[s],b)==0) { printf("%c",r[s]); break;