#include <stdio.h>
#include <string.h>
#include <stdlib.h>
typedef struct node//每个树的节点至少包含3个内容,节点的权值,左子树,右子树的地址
{
int element;
char ch;
char u[100];
int num;
struct node *Lchild,*Rchild;
}node;
typedef struct tree
{
struct node *root;
}tree;//每一棵树都是由一个个节点构成的
tree start;
void Maketree(tree *bt,int x,char c,tree *Lt,tree *Rt)//该函数的目的是传入x的值,建立一棵左子树是Lt,右子树是Rt的树bt(创建方法就是先申请一个空间保存权值,然后记录下左子树右子树的地址,此时注意访问子树有两种方式:
//1直接通过左子树Lt->root来访问2通过p->Lchild来访问,而事实上,我们希望的是第二种方式,即这时左子树已经成为整体的一部分,所以都要清零( Lt->root=Rt->root=NULL;)
{
node *p=(node*)malloc(sizeof(node));
p->ch=c;
p->element=x;
p->Lchild=Lt->root;
p->Rchild=Rt->root;
Lt->root=Rt->root=NULL;
bt->root=p;//最后把先建立的节点赋值给bt(我们就是通过bt传递的)
}
tree CreatHFMtree(int w[],char s[],int n)//传入两个参数,一个是数组w,一个是节点的数量n
{
tree zero,h[1000];
int i,k,k1,k2;
tree *p;
p=&zero;
p->root=NULL;
for (i=0;i<n;i++)
Maketree(&h[i],w[i],s[i],p,p);//先建成n个树,再进行合并
for (k=n-1;k>0;k--)//n棵树合并,进行n-1次
{
Fmin(h,&k1,&k2,k);//在已经建成的n棵树中,找出最小值的下标k1,次小值得下标k2,最小值每次只会在前k个值(每一次找出两个值都会在数组中忽略最小值)
Maketree(&h[k1],h[k1].root->element+h[k2].root->element,'#',&h[k1],&h[k2]);//这步可以说是哈夫曼树的核心代码,把找到的两个小值求和h[k1]+h[k2],作为h[k2]的树,而他的子树就是h[k1],h[k2]
h[k2]=h[k];//每一次把最小值换成队尾的那个,此时最小值就没有了,而有了两个队尾元素,然后由于k--,队尾元素相当于被删除了一个,所以只剩下了除了最小数的全部元素(如果最小值就是队尾元素,那也是成立,可以自己思考一下)
}
return h[0];
}
void makecode(node *t)//得出译码(每一个子节点的译码都是从父节点那继承来的)
{
int i,l;
if (t==start.root)
{
for (i=0;i<100;i++)
start.root->u[i]='\0';
start.root->num=0;
}
if ((t->Lchild==NULL)&&(t->Rchild==NULL))
{
printf("%c:",t->ch);
for (i=0;i<t->num;i++)
printf("%c",t->u[i]);
printf("\n");
return;
}
if (t->Lchild!=NULL)
{
for (i=0;i<t->num;i++)
t->Lchild->u[i]=t->u[i];
t->Lchild->u[t->num]='0';
t->Lchild->num=t->num+1;
makecode(t->Lchild);
}
if (t->Rchild!=NULL)
{
for (i=0;i<t->num;i++)
t->Rchild->u[i]=t->u[i];
t->Rchild->u[t->num]='1';
t->Rchild->num=t->num+1;
makecode(t->Rchild);
}
}
void translate(node *t,char p[])//翻译,先记录下来,因为不知道是否符合规范
{
char s[100];
node *q=t;
int l,i,k=0,max;
l=strlen(p);
for (i=0;i<l;i++)
{
if (p[i]=='0')
if (q->Lchild)
q=q->Lchild;
else
printf("请输入正确的字符串\n");
else
{
if (p[i]=='1')
if (q->Rchild)
q=q->Rchild;
else
printf("请输入正确的字符串\n");
}
if ((q->Lchild==NULL)&&(q->Rchild==NULL))
{
s[k++]=q->ch;
max=i;
q=t;
}
}
if (max!=l-1)
printf("请输入正确的字符串\n");
else
{
for (i=0;i<k;i++)
printf("%c",s[i]);
}
printf("\n");
}
void Fmin(tree h[],int *k1,int *k2,int k)//k1是最小值的下标,k2是次小值的下标(这一部分其实就是维护由两个元素组成的堆)
{
int i,min1,min2;
if (h[0].root->element<h[1].root->element)
{
*k1=0;
*k2=1;
min1=h[0].root->element;
min2=h[1].root->element;
}
else
{
*k1=1;
*k2=0;
min1=h[1].root->element;
min2=h[0].root->element;
}
for (i=2;i<=k;i++)
if (h[i].root->element<min1)//如果比最小值还小
{
*k2=*k1;//先更新次小值的为原来的最小值,原来的最小值更新为h[i].root->element
*k1=i;
min2=min1;
min1=h[i].root->element;
}
else
if (h[i].root->element<min2)
{
*k2=i;
min2=h[i].root->element;//直接更新次小值
}
}
void PreOrd(node *t)
{
if (t)
{
printf("%d %c ",t->element,t->ch);
PreOrd(t->Lchild);
PreOrd(t->Rchild);
}
}
void menu()
{
printf("**********************************************************\n");
printf("*****欢迎使用B14040312宋宇通的小小哈夫曼编译系统**********\n");
printf("*********创建新的哈夫曼的编译系统请按1***************\n");
printf("*********从文件输入待编译的字符串请按2***************\n");
printf("*********从键盘输入待编译的字符串请按3***************\n");
printf("*********如果你残忍地想退出本系统请按4*******************\n");
}
int main()
{
FILE *fp;
int w[1000];
char s[1000];
char p[1000];
char cha;
int i,n,ok=1;
fp=fopen("d://1.txt","r");
menu();
cha=getchar();
while(cha!='4')
{
switch (cha)
{
case '1':
printf("请输入树节点的个数\n");
scanf("%d",&n);
printf("请输入节点(格式为频率 对应的字母)\n");
for (i=0;i<n;i++)
scanf("%d %c",&w[i],&s[i]);
start=CreatHFMtree(w,s,n);
printf("建成的哈夫曼树的中序遍历结果为:");
PreOrd(start.root);
printf("\n");
makecode(start.root);
printf("*********从文件输入待编译的字符串请按2(文本保存在D://1.txt)***************\n");
printf("*********从键盘输入待编译的字符串请按3***************\n");
break;
case '2':
if (start.root==NULL)
printf("你还没给我创建哈夫曼编译系统呢,过分了!\n");
else
{
printf("注意文件是保存在d下的1.txt下的哦,亲~~\n");
fscanf(fp,"%s",p);
printf("你在文件中保存的字符串是:");
printf("%s\n",p);
printf("翻译结果为:");
translate(start.root,p);
printf("\n");
}
printf("*********从文件输入待编译的字符串请按2***************\n");
printf("*********从键盘输入待编译的字符串请按3***************\n");
printf("*********如果你残忍地想退出本系统请按4*******************\n");
break;
case '3':
if (start.root==NULL)
printf("你还没给我创建哈夫曼编译系统呢,过分了!\n");
else
{
printf("请输入待翻译的字符串\n");
scanf("%s",p);
printf("翻译结果为:");
translate(start.root,p);
}
printf("*********从文件输入待编译的字符串请按2***************\n");
printf("*********从键盘输入待编译的字符串请按3***************\n");
printf("*********如果你残忍地想退出本系统请按4*******************\n");
break;
default:printf("请输入正确的数字,不然人家要生气了~~\n");
ok=0;
}
if (ok) getchar();
cha=getchar();
}
printf("谢谢使用\n");
fclose(fp);
return 0;
}
数据结构--我的哈夫曼编译系统
最新推荐文章于 2021-05-25 20:43:30 发布
这是一个使用C语言实现的哈夫曼编码编译系统,能够创建哈夫曼树,进行中序遍历,并根据哈夫曼树对输入字符串进行编码和解码。用户可以通过文件或键盘输入字符串进行操作。
摘要由CSDN通过智能技术生成