129347707337343750《数据结构与算法实验》实验指导书暨实验报告13新.docx
《129347707337343750《数据结构与算法实验》实验指导书暨实验报告13新.docx》由会员分享,可在线阅读,更多相关《129347707337343750《数据结构与算法实验》实验指导书暨实验报告13新.docx(26页珍藏版)》请在冰豆网上搜索。
129347707337343750《数据结构与算法实验》实验指导书暨实验报告13新
湖北汽车工业学院实验报告
班号序号姓名
课程名称数据结构与算法实验第1号实验完成日期年月日午
实验一线性表操作
一、实验目的
1.掌握用C语言调试程序的基本方法。
2.掌握结构体类型的基本用法。
3.掌握线性表的基本运算,包括顺序表和链表的基本操作,如插入、删除等。
二、实验内容
1.利用顺序表完成一个班级的一个学期的所有课程的管理:
能够增加、删除、修改学生的成绩记录。
2.建立一个单链表,同时对该链表实现指定位置的插入、删除操作。
三、实验操作(在空白处填上合适的代码)
(一)利用顺序表完成一个班级学生课程成绩的简单管理
1、预定义以及顺序表结构类型的定义
(1)#defineListSize//根据需要自己设定一个班级能够容纳的最大学生数
(2)typedefstructStu
{
intnum;//学生的学号
charname[10];//学生的姓名
floatwuli;//物理成绩
floatshuxue;//数学成绩
floatyingyu;//英语成绩
}STUDENT;//存放单个学生信息的结构体类型
typedefstructList
stu[ListSize];//存放学生的数组定义,静态分配空间
intlength;//记录班级实际学生个数
}LIST;//存放班级学生信息的顺序表类型
2、建立班级的学生信息
voidlistcreate(LIST*Li,intm)//m为该班级的实际人数
inti;
Li->length=0;
for(i=0;i{printf("pleaseinputthe%dthstudent'sinformation:\n",i+1);printf("num=");scanf("%d",);//输入第i个学生的学号printf("name=");scanf("%s",);//输入第i个学生的姓名printf("wuli=");scanf("%f",);//输入第i个学生的物理成绩printf("shuxue=");scanf("%f",);//输入第i个学生的数学成绩printf("yingyu=");scanf("%f",);//输入第i个学生的英语成绩Li->length++;//学生人数加1}}3、插入一个学生信息intlistinsert(LIST*Li,inti)//将学生插入到班级Li的第i个位置。{intj;STUDENTe;if()//测试存储空间是否被占满{printf("无更多的存储空间!\n");return0;}if()//插入位置检验,如果错误就返回0退出程序。return0;else{printf("请输入插入的学生信息:");printf("num=");scanf("%d",&e.num);printf("name=");scanf("%s",e.name);printf("wuli=");scanf("%f",&e.wuli);printf("shuxue=");scanf("%f",&e.shuxue);printf("yingyu=");scanf("%f",&e.yingyu);for(j=;j>=;j--)//从i位置到最后的元素依次往后移动Li->stu[j+1]=Li->stu[j];=e;//学生e放入到i位置Li->length++;//学生实际人数加1return1;}} 4、删除一个学生信息intlistdel(LIST*Li,inti)//删除第i个学生的信息{intj;if()//删除位置检验,如果错误就返回0退出程序。return0;else{for(j=;j<;j++)//从删除位置后一个到最后的元素依次往前移动Li->stu[j-1]=Li->stu[j];Li->length--;return1;}} 5、显示所有学生信息voidlistdisplay(LISTL){inti;printf("班级学生信息如下:\n");for(i=0;i<;i++)printf("%10d[学号]%10s[姓名]%10.2f[物理成绩]%10.2f[数学成绩]%10.2f[英语成绩]\n",L.stu[i].num,L.stu[i].name,L.stu[i].wuli,L.stu[i].shuxue,L.stu[i].yingyu);}6、编写主函数main,要求测试以上所编写的listcreat、listinsert、listdel和listdisplayvoidmain()//自己设计主函数完成{ }(二)利用单链表完成一个班级学生课程成绩的简单管理1、单链表结构体类型的定义typedefstructStu{intnum;//学生的学号charname[10];//学生的姓名floatwuli;//物理成绩floatshuxue;//数学成绩floatyingyu;//英语成绩}STUDENT;//存放单个学生信息的结构体类型typedefstructSnode{STUDENTdata;//结点的值structSnode*link;//指向下一个结点的地址}SNODE; 2、建立班级学生信息SNODE*listcreate(intn)//n为该班级的实际人数{inti;SNODE*head,*p,*q;if(n==0)returnNULL;//如果要创建的是空表,返回NULLhead=p=(SNODE*)malloc(sizeof(SNODE));//动态建立第一个结点,head指针指向printf("pleaseinputthe1thstudent'sinformation:\n");printf("num=");scanf("%d",&p->data.num);//输入第1个学生的学号printf("name=");scanf("%s",p->data.name);//输入第1个学生的姓名printf("wuli=");scanf("%f",&p->data.wuli);//输入第1个学生的物理成绩printf("shuxue=");scanf("%f",&p->data.shuxue);//输入第1个学生的数学成绩printf("yingyu=");scanf("%f",&p->data.yingyu);//输入第1个学生的英语成绩 for(i=1;i{printf("\nThe%dthelement'sdata:\n",i+1);q=(SNODE*)malloc(sizeof(SNODE));printf("num=");scanf("%d",&q->data.num);printf("name=");scanf("%s",q->data.name);printf("wuli=");scanf("%f",&q->data.wuli);printf("shuxue=");scanf("%f",&q->data.shuxue);printf("yingyu=");scanf("%f",&q->data.yingyu);q->link=NULL;}} 3、插入一个学生信息intlistinsert(SNODE**Li_head,inti)//将学生插入到班级Li_head的第i个位置。{SNODE*p,*q,*newsnode;intm=0;//用来统计学生位置if(i<1)return0;//插入位置检验,如果错误就返回0退出程序newsnode=(SNODE*)malloc(sizeof(SNODE));//产生新结点printf("pleaseinputthenewstudent'sinformation:\n");printf("num=");scanf("%d",&newsnode->data.num);printf("name=");scanf("%s",newsnode->data.name);printf("wuli=");scanf("%f",&newsnode->data.wuli);printf("shuxue=");scanf("%f",&newsnode->data.shuxue);printf("yingyu=");scanf("%f",&newsnode->data.yingyu); p=*Li_head,q=NULL;//查找第i个结点,使p指向,q指向第i-1个结点while(p!=NULL){m++;if()break;else{}}if()//插入在表头{newsnode->link=p;*Li_head=newsnode;}else//插入在q和p之间{}return1;} 4、删除一个学生信息intlistdel(SNODE**Li_head,inti)//删除链表Li_head中第一个元素值为b的结点{intm=0;SNODE*p,*q;p=*Li_head;q=NULL;if(i<1||*Li_head==NULL)//单链表为空及插入位置校验,如果错误就退出程序return0;while(p!=NULL){m++;if(i==m)break;else{q=p;p=p->link;}}if(p==NULL)//i位置结点没有(超过最后一个结点)return0;if(p==*Li_head)//删除表头结点else//删除非表头结点//释放该结点所占的空间return1;} 5、显示所有学生信息voidlistdisplay(SNODE*Li_head){printf("班级学生信息如下:\n");while(){printf("%10d[学号]%10s[姓名]%10.2f[物理成绩]%10.2f[数学成绩]%10.2f[英语成绩]\n",Li_head->data.num,Li_head->data.name,Li_head->data.wuli,Li_head->data.shuxue,Li_head->data.yingyu);Li_head=Li_head->link;}} 6、编写主函数main,要求测试以上所编写的listcreat、listinsert、listdel和listdisplayvoidmain()//自己设计主函数完成{ }四、实验小结(自己总结本次实验的重难点及心得、体会、收获) 得分_____________评阅日期_____________教师签名____________湖北汽车工业学院实验报告班号序号姓名课程名称数据结构与算法实验第2号实验完成日期年月日午实验二栈和队列的操作与应用一、实验目的1.掌握栈和队列的基本操作,并能对其进行简单应用。二、实验内容1.利用栈将一个十进制的正整数转换成n进制数据,并将其转换结果输出。2.用顺序栈实现算术表达式求值。3.编程用一维数组模拟一个队列(顺序队列),实现入队列和出队列操作。三、实验操作(在空白处填上合适的代码)(一)利用顺序栈实现十进制整数转换转换成n进制1、算法思想将十进制数N转换为r进制的数,其转换方法利用辗转相除法,以N=3456,r=8为例转换方法如下:NN/8(整除)N%8(求余)34674333低4335415466606高所以:(3456)10=(6563)8我们看到所转换的8进制数按底位到高位的顺序产生的,而通常的输出是从高位到低位的,恰好与计算过程相反,因此转换过程中每得到一位8进制数则进栈保存,转换完毕后依次出栈则正好是转换结果。算法思想如下:当N>0时重复1,21.若N≠0,则将N%r压入栈s中,执行2;若N=0,将栈s的内容依次出栈,算法结束。2.用N/r代替N2、转换子程序#defineL_size//根据需要自己定义L_size为顺序栈的最大存储容量voidconversion(intN,intr)//将十进制数N转换为r进制的数{ints[L_size],top;//定义一个顺序栈,top为栈顶指针,注意此处没有使用结构体类型intx;//初始化栈while()//此循环为入栈操作{//余数入栈N=N/r;//商作为被除数继续}while()//此循环为出栈操作{printf(“%d”,x);}}3、编写主函数验证上述转换子函数是否正确。voidmain()//自己设计主函数完成{ } (二)用顺序栈实现算术后缀表达式求值1、算法思想后缀表达式求值步骤:a、循环读出后缀表达式中的每一个字符;b、若是数字,将对应的字符串转换成整数,入栈;c、若是运算符,从栈中弹出2个数,将运算结果再压入栈;d、若表达式输入完毕,栈顶即表达式值;2、后缀表达式求值子程序#defineL_size50voidpostexp(){intst[L_size],top=-1;//定义一个顺序栈,top为栈顶指针intd;//定义用来字符串转换整数的变量dcharch;printf("请输入规范的后缀表达式(操作数、运算符之间使用空格间隔开,eg:1560422/-3*+):\n");//输入范例while((ch=getchar())!='\n')//开始输入字符并赋给ch{if(ch=='')//如果输入的是空格,不做处理elseswitch(ch)//判断输入是否运算符,如果时就进行相应的操作{case'+':;;break;case'-':;;break;case'*':;;break;case'/':if(st[top]!=0){//分母不为零计算才有效}else{printf("除数为0!\n");//分母为零计算无效,退出程序exit(1);}break;default:while(ch>='0'&&ch<='9'){ch=getchar();}//将转换后的数值入栈}}printf("运算结果是:%d\n",st[top]);}3、编写主函数验证上述求值子函数是否正确。voidmain()//自己设计主函数完成{ } (三)链式队列基本操作1、队列结点定义根据实际处理数据的类型定义链队中结点的值域类型ElemTypetypedefstructnode//队列结点类型定义{ElemTypedata;//队列的数据元素类型structnode*link;//指向后继结点的指针}NODE;structQueueLk{//定义链队//定义链队队头和队尾指针} 2、入队NODE*ldcr(structQueueLk*QL,Elemtypex)//将元素x插入到链队列rear中,作为rear的新队尾{NODE*p;p->data=x;p->link=NULL;//置新结点的指针为空if(QL->front==NULL)//队列为空else//将链队列中最后一个结点的指针指向新结点//将队尾指向新结点returnQL->rear;}3、出队ElemTypeldsc(structQueueLk*QL)//若链队列不为空,则删除队头元素,返回其元素值{NODE*s;ElemTypex;if()//队空,退出程序exit(1);s=QL->front;//取队头保存在s中//删除队头结点if()//如果删除后队列为空,则处理队尾指针QL->rear=QL->front;x=s->data;//将刚才出队的结点值给x//释放出对结点的空间returnx;} 4、编写主函数验证上述子函数是否正确。voidmain()//自己设计主函数完成{ }四、实验小结(自己总结本次实验的重难点及心得、体会、收获) 得分_____________评阅日期_____________教师签名____________湖北汽车工业学院实验报告班号序号姓名课程名称数据结构与算法实验第3号实验完成日期年月日午实验三二叉树的应用一、实验目的1.熟悉二叉树结点的结构和对二叉树的基本操作。2.在二叉树基本操作的基础上掌握对二叉树的一些其它操作的具体实现方法。3.掌握构造哈夫曼树以及哈夫曼编码的方法。二、实验内容1.建立一棵二叉树,编写二叉树前序遍历、中序遍历、后序遍历的递归算法与非递归算法。2.构造一颗哈夫曼树并进行哈夫曼编码。三、实验操作(在空白处填上合适的代码)(一)按先序遍历序列建立二叉树的二叉链表1、二叉树结点定义typedefdatatypechar;typedefstructnode{datatypedata;//数据域structnode*lchild;//指向左孩子位置structnode*rchild;//指向右孩子位置}BiTree;2、构建二叉树子程序(依据字符串s递归创建二叉树bt,输入方式:ABC##DE#G##F###,先序方式,#号用于表示子树为空)BiTree*crt_bt_pre(){charch;BiTree*bt;ch=getchar();if(ch=='#')bt=NULL;else{bt=(BiTree*)malloc(sizeof(BiTree));bt->data=ch;//递归创建左子树//递归创建右子树}return(bt);} (二)二叉树前序遍历、中序遍历、后序遍历的递归和非递归算法1、算法思想先序遍历:先访问根结点,然后分别先序遍历左子树、右子树中序遍历:先中序遍历左子树,然后访问根结点,最后中序遍历右子树后序遍历:先后序遍历左、右子树,然后访问根结点2、递归遍历子程序voidPreOrder(BiTree*bt)//先序遍历二叉树bt{if(bt!=NULL){printf("%c",bt->data);//访问结点的数据域//先序递归遍历bt的左子树//先序递归遍历bt的右子树}}voidInOrder(BiTree*bt)//中序遍历二叉树bt{if(bt!=NULL){//中序递归遍历bt的左子树//访问结点的数据域//中序递归遍历bt的右子树}}voidPostOrder(BiTree*bt)//后序遍历二叉树bt{if(bt!=NULL){//后序递归遍历bt的左子树//后序递归遍历bt的右子树//访问结点的数据域}}3、非递归遍历子程序(需要借助栈来实现)(1)非递归先序遍历子程序算法的思想:当树不为空的时候,访问根结点p的数据域data后,将p入栈,遍历左子树;遍历完左子树返回时,栈顶元素应为p,出栈,再先序遍历p的右子树。#defineMAXNODE50//定义保存二叉树结点指针的栈的最大空间voidNRPreOrder(BiTree*bt)//非递归先序遍历二叉树{BiTree*stack[MAXNODE],*p;i
printf("pleaseinputthe%dthstudent'sinformation:
\n",i+1);
printf("num=");
scanf("%d",);//输入第i个学生的学号
printf("name=");
scanf("%s",);//输入第i个学生的姓名
printf("wuli=");
scanf("%f",);//输入第i个学生的物理成绩
printf("shuxue=");
scanf("%f",);//输入第i个学生的数学成绩
printf("yingyu=");
scanf("%f",);//输入第i个学生的英语成绩
Li->length++;//学生人数加1
}
3、插入一个学生信息
intlistinsert(LIST*Li,inti)//将学生插入到班级Li的第i个位置。
intj;
STUDENTe;
if()//测试存储空间是否被占满
printf("无更多的存储空间!
\n");
return0;
if()//插入位置检验,如果错误就返回0退出程序。
else
printf("请输入插入的学生信息:
");
printf("num=");scanf("%d",&e.num);
printf("name=");scanf("%s",e.name);
printf("wuli=");scanf("%f",&e.wuli);
printf("shuxue=");scanf("%f",&e.shuxue);
printf("yingyu=");scanf("%f",&e.yingyu);
for(j=;j>=;j--)//从i位置到最后的元素依次往后移动
Li->stu[j+1]=Li->stu[j];
=e;//学生e放入到i位置
Li->length++;//学生实际人数加1
return1;
4、删除一个学生信息
intlistdel(LIST*Li,inti)//删除第i个学生的信息
if()//删除位置检验,如果错误就返回0退出程序。
for(j=;j<;j++)//从删除位置后一个到最后的元素依次往前移动
Li->stu[j-1]=Li->stu[j];
Li->length--;
5、显示所有学生信息
voidlistdisplay(LISTL)
printf("班级学生信息如下:
for(i=0;i<;i++)
printf("%10d[学号]%10s[姓名]%10.2f[物理成绩]%10.2f[数学成绩]%10.2f[英语成绩]\n",L.stu[i].num,L.stu[i].name,L.stu[i].wuli,L.stu[i].shuxue,L.stu[i].yingyu);
6、编写主函数main,要求测试以上所编写的listcreat、listinsert、listdel和listdisplay
voidmain()//自己设计主函数完成
(二)利用单链表完成一个班级学生课程成绩的简单管理
1、单链表结构体类型的定义
typedefstructStu
typedefstructSnode
STUDENTdata;//结点的值
structSnode*link;//指向下一个结点的地址
}SNODE;
2、建立班级学生信息
SNODE*listcreate(intn)//n为该班级的实际人数
SNODE*head,*p,*q;
if(n==0)
returnNULL;//如果要创建的是空表,返回NULL
head=p=(SNODE*)malloc(sizeof(SNODE));//动态建立第一个结点,head指针指向
printf("pleaseinputthe1thstudent'sinformation:
printf("num=");scanf("%d",&p->data.num);//输入第1个学生的学号
printf("name=");scanf("%s",p->data.name);//输入第1个学生的姓名
printf("wuli=");scanf("%f",&p->data.wuli);//输入第1个学生的物理成绩
printf("shuxue=");scanf("%f",&p->data.shuxue);//输入第1个学生的数学成绩
printf("yingyu=");scanf("%f",&p->data.yingyu);//输入第1个学生的英语成绩
for(i=1;i{printf("\nThe%dthelement'sdata:\n",i+1);q=(SNODE*)malloc(sizeof(SNODE));printf("num=");scanf("%d",&q->data.num);printf("name=");scanf("%s",q->data.name);printf("wuli=");scanf("%f",&q->data.wuli);printf("shuxue=");scanf("%f",&q->data.shuxue);printf("yingyu=");scanf("%f",&q->data.yingyu);q->link=NULL;}} 3、插入一个学生信息intlistinsert(SNODE**Li_head,inti)//将学生插入到班级Li_head的第i个位置。{SNODE*p,*q,*newsnode;intm=0;//用来统计学生位置if(i<1)return0;//插入位置检验,如果错误就返回0退出程序newsnode=(SNODE*)malloc(sizeof(SNODE));//产生新结点printf("pleaseinputthenewstudent'sinformation:\n");printf("num=");scanf("%d",&newsnode->data.num);printf("name=");scanf("%s",newsnode->data.name);printf("wuli=");scanf("%f",&newsnode->data.wuli);printf("shuxue=");scanf("%f",&newsnode->data.shuxue);printf("yingyu=");scanf("%f",&newsnode->data.yingyu); p=*Li_head,q=NULL;//查找第i个结点,使p指向,q指向第i-1个结点while(p!=NULL){m++;if()break;else{}}if()//插入在表头{newsnode->link=p;*Li_head=newsnode;}else//插入在q和p之间{}return1;} 4、删除一个学生信息intlistdel(SNODE**Li_head,inti)//删除链表Li_head中第一个元素值为b的结点{intm=0;SNODE*p,*q;p=*Li_head;q=NULL;if(i<1||*Li_head==NULL)//单链表为空及插入位置校验,如果错误就退出程序return0;while(p!=NULL){m++;if(i==m)break;else{q=p;p=p->link;}}if(p==NULL)//i位置结点没有(超过最后一个结点)return0;if(p==*Li_head)//删除表头结点else//删除非表头结点//释放该结点所占的空间return1;} 5、显示所有学生信息voidlistdisplay(SNODE*Li_head){printf("班级学生信息如下:\n");while(){printf("%10d[学号]%10s[姓名]%10.2f[物理成绩]%10.2f[数学成绩]%10.2f[英语成绩]\n",Li_head->data.num,Li_head->data.name,Li_head->data.wuli,Li_head->data.shuxue,Li_head->data.yingyu);Li_head=Li_head->link;}} 6、编写主函数main,要求测试以上所编写的listcreat、listinsert、listdel和listdisplayvoidmain()//自己设计主函数完成{ }四、实验小结(自己总结本次实验的重难点及心得、体会、收获) 得分_____________评阅日期_____________教师签名____________湖北汽车工业学院实验报告班号序号姓名课程名称数据结构与算法实验第2号实验完成日期年月日午实验二栈和队列的操作与应用一、实验目的1.掌握栈和队列的基本操作,并能对其进行简单应用。二、实验内容1.利用栈将一个十进制的正整数转换成n进制数据,并将其转换结果输出。2.用顺序栈实现算术表达式求值。3.编程用一维数组模拟一个队列(顺序队列),实现入队列和出队列操作。三、实验操作(在空白处填上合适的代码)(一)利用顺序栈实现十进制整数转换转换成n进制1、算法思想将十进制数N转换为r进制的数,其转换方法利用辗转相除法,以N=3456,r=8为例转换方法如下:NN/8(整除)N%8(求余)34674333低4335415466606高所以:(3456)10=(6563)8我们看到所转换的8进制数按底位到高位的顺序产生的,而通常的输出是从高位到低位的,恰好与计算过程相反,因此转换过程中每得到一位8进制数则进栈保存,转换完毕后依次出栈则正好是转换结果。算法思想如下:当N>0时重复1,21.若N≠0,则将N%r压入栈s中,执行2;若N=0,将栈s的内容依次出栈,算法结束。2.用N/r代替N2、转换子程序#defineL_size//根据需要自己定义L_size为顺序栈的最大存储容量voidconversion(intN,intr)//将十进制数N转换为r进制的数{ints[L_size],top;//定义一个顺序栈,top为栈顶指针,注意此处没有使用结构体类型intx;//初始化栈while()//此循环为入栈操作{//余数入栈N=N/r;//商作为被除数继续}while()//此循环为出栈操作{printf(“%d”,x);}}3、编写主函数验证上述转换子函数是否正确。voidmain()//自己设计主函数完成{ } (二)用顺序栈实现算术后缀表达式求值1、算法思想后缀表达式求值步骤:a、循环读出后缀表达式中的每一个字符;b、若是数字,将对应的字符串转换成整数,入栈;c、若是运算符,从栈中弹出2个数,将运算结果再压入栈;d、若表达式输入完毕,栈顶即表达式值;2、后缀表达式求值子程序#defineL_size50voidpostexp(){intst[L_size],top=-1;//定义一个顺序栈,top为栈顶指针intd;//定义用来字符串转换整数的变量dcharch;printf("请输入规范的后缀表达式(操作数、运算符之间使用空格间隔开,eg:1560422/-3*+):\n");//输入范例while((ch=getchar())!='\n')//开始输入字符并赋给ch{if(ch=='')//如果输入的是空格,不做处理elseswitch(ch)//判断输入是否运算符,如果时就进行相应的操作{case'+':;;break;case'-':;;break;case'*':;;break;case'/':if(st[top]!=0){//分母不为零计算才有效}else{printf("除数为0!\n");//分母为零计算无效,退出程序exit(1);}break;default:while(ch>='0'&&ch<='9'){ch=getchar();}//将转换后的数值入栈}}printf("运算结果是:%d\n",st[top]);}3、编写主函数验证上述求值子函数是否正确。voidmain()//自己设计主函数完成{ } (三)链式队列基本操作1、队列结点定义根据实际处理数据的类型定义链队中结点的值域类型ElemTypetypedefstructnode//队列结点类型定义{ElemTypedata;//队列的数据元素类型structnode*link;//指向后继结点的指针}NODE;structQueueLk{//定义链队//定义链队队头和队尾指针} 2、入队NODE*ldcr(structQueueLk*QL,Elemtypex)//将元素x插入到链队列rear中,作为rear的新队尾{NODE*p;p->data=x;p->link=NULL;//置新结点的指针为空if(QL->front==NULL)//队列为空else//将链队列中最后一个结点的指针指向新结点//将队尾指向新结点returnQL->rear;}3、出队ElemTypeldsc(structQueueLk*QL)//若链队列不为空,则删除队头元素,返回其元素值{NODE*s;ElemTypex;if()//队空,退出程序exit(1);s=QL->front;//取队头保存在s中//删除队头结点if()//如果删除后队列为空,则处理队尾指针QL->rear=QL->front;x=s->data;//将刚才出队的结点值给x//释放出对结点的空间returnx;} 4、编写主函数验证上述子函数是否正确。voidmain()//自己设计主函数完成{ }四、实验小结(自己总结本次实验的重难点及心得、体会、收获) 得分_____________评阅日期_____________教师签名____________湖北汽车工业学院实验报告班号序号姓名课程名称数据结构与算法实验第3号实验完成日期年月日午实验三二叉树的应用一、实验目的1.熟悉二叉树结点的结构和对二叉树的基本操作。2.在二叉树基本操作的基础上掌握对二叉树的一些其它操作的具体实现方法。3.掌握构造哈夫曼树以及哈夫曼编码的方法。二、实验内容1.建立一棵二叉树,编写二叉树前序遍历、中序遍历、后序遍历的递归算法与非递归算法。2.构造一颗哈夫曼树并进行哈夫曼编码。三、实验操作(在空白处填上合适的代码)(一)按先序遍历序列建立二叉树的二叉链表1、二叉树结点定义typedefdatatypechar;typedefstructnode{datatypedata;//数据域structnode*lchild;//指向左孩子位置structnode*rchild;//指向右孩子位置}BiTree;2、构建二叉树子程序(依据字符串s递归创建二叉树bt,输入方式:ABC##DE#G##F###,先序方式,#号用于表示子树为空)BiTree*crt_bt_pre(){charch;BiTree*bt;ch=getchar();if(ch=='#')bt=NULL;else{bt=(BiTree*)malloc(sizeof(BiTree));bt->data=ch;//递归创建左子树//递归创建右子树}return(bt);} (二)二叉树前序遍历、中序遍历、后序遍历的递归和非递归算法1、算法思想先序遍历:先访问根结点,然后分别先序遍历左子树、右子树中序遍历:先中序遍历左子树,然后访问根结点,最后中序遍历右子树后序遍历:先后序遍历左、右子树,然后访问根结点2、递归遍历子程序voidPreOrder(BiTree*bt)//先序遍历二叉树bt{if(bt!=NULL){printf("%c",bt->data);//访问结点的数据域//先序递归遍历bt的左子树//先序递归遍历bt的右子树}}voidInOrder(BiTree*bt)//中序遍历二叉树bt{if(bt!=NULL){//中序递归遍历bt的左子树//访问结点的数据域//中序递归遍历bt的右子树}}voidPostOrder(BiTree*bt)//后序遍历二叉树bt{if(bt!=NULL){//后序递归遍历bt的左子树//后序递归遍历bt的右子树//访问结点的数据域}}3、非递归遍历子程序(需要借助栈来实现)(1)非递归先序遍历子程序算法的思想:当树不为空的时候,访问根结点p的数据域data后,将p入栈,遍历左子树;遍历完左子树返回时,栈顶元素应为p,出栈,再先序遍历p的右子树。#defineMAXNODE50//定义保存二叉树结点指针的栈的最大空间voidNRPreOrder(BiTree*bt)//非递归先序遍历二叉树{BiTree*stack[MAXNODE],*p;i
printf("\nThe%dthelement'sdata:
q=(SNODE*)malloc(sizeof(SNODE));
printf("num=");scanf("%d",&q->data.num);
printf("name=");scanf("%s",q->data.name);
printf("wuli=");scanf("%f",&q->data.wuli);
printf("shuxue=");scanf("%f",&q->data.shuxue);
printf("yingyu=");scanf("%f",&q->data.yingyu);
q->link=NULL;
intlistinsert(SNODE**Li_head,inti)//将学生插入到班级Li_head的第i个位置。
SNODE*p,*q,*newsnode;
intm=0;//用来统计学生位置
if(i<1)
return0;//插入位置检验,如果错误就返回0退出程序
newsnode=(SNODE*)malloc(sizeof(SNODE));//产生新结点
printf("pleaseinputthenewstudent'sinformation:
printf("num=");scanf("%d",&newsnode->data.num);
printf("name=");scanf("%s",newsnode->data.name);
printf("wuli=");scanf("%f",&newsnode->data.wuli);
printf("shuxue=");scanf("%f",&newsnode->data.shuxue);
printf("yingyu=");scanf("%f",&newsnode->data.yingyu);
p=*Li_head,q=NULL;//查找第i个结点,使p指向,q指向第i-1个结点
while(p!
=NULL)
m++;
if()
break;
if()//插入在表头
newsnode->link=p;
*Li_head=newsnode;
else//插入在q和p之间
intlistdel(SNODE**Li_head,inti)//删除链表Li_head中第一个元素值为b的结点
intm=0;
SNODE*p,*q;
p=*Li_head;q=NULL;
if(i<1||*Li_head==NULL)//单链表为空及插入位置校验,如果错误就退出程序
if(i==m)
q=p;p=p->link;
if(p==NULL)//i位置结点没有(超过最后一个结点)
if(p==*Li_head)//删除表头结点
else//删除非表头结点
//释放该结点所占的空间
voidlistdisplay(SNODE*Li_head)
while()
printf("%10d[学号]%10s[姓名]%10.2f[物理成绩]%10.2f[数学成绩]%10.2f[英语成绩]\n",Li_head->data.num,Li_head->data.name,Li_head->data.wuli,Li_head->data.shuxue,Li_head->data.yingyu);
Li_head=Li_head->link;
四、实验小结(自己总结本次实验的重难点及心得、体会、收获)
得分_____________
评阅日期_____________
教师签名____________
课程名称数据结构与算法实验第2号实验完成日期年月日午
实验二栈和队列的操作与应用
1.掌握栈和队列的基本操作,并能对其进行简单应用。
1.利用栈将一个十进制的正整数转换成n进制数据,并将其转换结果输出。
2.用顺序栈实现算术表达式求值。
3.编程用一维数组模拟一个队列(顺序队列),实现入队列和出队列操作。
(一)利用顺序栈实现十进制整数转换转换成n进制
1、算法思想
将十进制数N转换为r进制的数,其转换方法利用辗转相除法,以N=3456,r=8为例转换方法如下:
NN/8(整除)N%8(求余)
34674333低
433541
5466
606高
所以:
(3456)10=(6563)8
我们看到所转换的8进制数按底位到高位的顺序产生的,而通常的输出是从高位到低位的,恰好与计算过程相反,因此转换过程中每得到一位8进制数则进栈保存,转换完毕后依次出栈则正好是转换结果。
算法思想如下:
当N>0时重复1,2
1.若N≠0,则将N%r压入栈s中,执行2;若N=0,将栈s的内容依次出栈,算法结束。
2.用N/r代替N
2、转换子程序
#defineL_size//根据需要自己定义L_size为顺序栈的最大存储容量
voidconversion(intN,intr)//将十进制数N转换为r进制的数
ints[L_size],top;//定义一个顺序栈,top为栈顶指针,注意此处没有使用结构体类型
intx;
//初始化栈
while()//此循环为入栈操作
//余数入栈
N=N/r;//商作为被除数继续
while()//此循环为出栈操作
printf(“%d”,x);
3、编写主函数验证上述转换子函数是否正确。
}
(二)用顺序栈实现算术后缀表达式求值
后缀表达式求值步骤:
a、循环读出后缀表达式中的每一个字符;
b、若是数字,将对应的字符串转换成整数,入栈;
c、若是运算符,从栈中弹出2个数,将运算结果再压入栈;
d、若表达式输入完毕,栈顶即表达式值;
2、后缀表达式求值子程序
#defineL_size50
voidpostexp()
intst[L_size],top=-1;//定义一个顺序栈,top为栈顶指针
intd;//定义用来字符串转换整数的变量d
charch;
printf("请输入规范的后缀表达式(操作数、运算符之间使用空格间隔开,eg:
1560422/-3*+):
//输入范例
while((ch=getchar())!
='\n')//开始输入字符并赋给ch
if(ch=='')//如果输入的是空格,不做处理
switch(ch)//判断输入是否运算符,如果时就进行相应的操作
case'+':
;;break;
case'-':
case'*':
case'/':
if(st[top]!
=0)
//分母不为零计算才有效
printf("除数为0!
\n");//分母为零计算无效,退出程序
exit
(1);
default:
while(ch>='0'&&ch<='9')
ch=getchar();
//将转换后的数值入栈
printf("运算结果是:
%d\n",st[top]);
3、编写主函数验证上述求值子函数是否正确。
(三)链式队列基本操作
1、队列结点定义
根据实际处理数据的类型定义链队中结点的值域类型ElemType
typedefstructnode//队列结点类型定义
{ElemTypedata;//队列的数据元素类型
structnode*link;//指向后继结点的指针
}NODE;
structQueueLk{//定义链队
//定义链队队头和队尾指针
2、入队
NODE*ldcr(structQueueLk*QL,Elemtypex)//将元素x插入到链队列rear中,作为rear的新队尾
NODE*p;
p->data=x;
p->link=NULL;//置新结点的指针为空
if(QL->front==NULL)//队列为空
//将链队列中最后一个结点的指针指向新结点
//将队尾指向新结点
returnQL->rear;
3、出队
ElemTypeldsc(structQueueLk*QL)//若链队列不为空,则删除队头元素,返回其元素值
NODE*s;
ElemTypex;
if()//队空,退出程序
s=QL->front;//取队头保存在s中
//删除队头结点
if()//如果删除后队列为空,则处理队尾指针
QL->rear=QL->front;
x=s->data;//将刚才出队的结点值给x
//释放出对结点的空间
returnx;
4、编写主函数验证上述子函数是否正确。
课程名称数据结构与算法实验第3号实验完成日期年月日午
实验三二叉树的应用
1.熟悉二叉树结点的结构和对二叉树的基本操作。
2.在二叉树基本操作的基础上掌握对二叉树的一些其它操作的具体实现方法。
3.掌握构造哈夫曼树以及哈夫曼编码的方法。
1.建立一棵二叉树,编写二叉树前序遍历、中序遍历、后序遍历的递归算法与非递归算法。
2.构造一颗哈夫曼树并进行哈夫曼编码。
(一)按先序遍历序列建立二叉树的二叉链表
1、二叉树结点定义
typedefdatatypechar;
typedefstructnode
{datatypedata;//数据域
structnode*lchild;//指向左孩子位置
structnode*rchild;//指向右孩子位置
}BiTree;
2、构建二叉树子程序(依据字符串s递归创建二叉树bt,输入方式:
ABC##DE#G##F###,先序方式,#号用于表示子树为空)
BiTree*crt_bt_pre()
BiTree*bt;
if(ch=='#')bt=NULL;
bt=(BiTree*)malloc(sizeof(BiTree));
bt->data=ch;
//递归创建左子树
//递归创建右子树
return(bt);
(二)二叉树前序遍历、中序遍历、后序遍历的递归和非递归算法
先序遍历:
先访问根结点,然后分别先序遍历左子树、右子树
中序遍历:
先中序遍历左子树,然后访问根结点,最后中序遍历右子树
后序遍历:
先后序遍历左、右子树,然后访问根结点
2、递归遍历子程序
voidPreOrder(BiTree*bt)//先序遍历二叉树bt
if(bt!
printf("%c",bt->data);//访问结点的数据域
//先序递归遍历bt的左子树
//先序递归遍历bt的右子树
voidInOrder(BiTree*bt)//中序遍历二叉树bt
//中序递归遍历bt的左子树
//访问结点的数据域
//中序递归遍历bt的右子树
voidPostOrder(BiTree*bt)//后序遍历二叉树bt
//后序递归遍历bt的左子树
//后序递归遍历bt的右子树
3、非递归遍历子程序(需要借助栈来实现)
(1)非递归先序遍历子程序
算法的思想:
当树不为空的时候,访问根结点p的数据域data后,将p入栈,遍历左子树;遍历完左子树返回时,栈顶元素应为p,出栈,再先序遍历p的右子树。
#defineMAXNODE50//定义保存二叉树结点指针的栈的最大空间
voidNRPreOrder(BiTree*bt)//非递归先序遍历二叉树
BiTree*stack[MAXNODE],*p;
i
copyright@ 2008-2022 冰豆网网站版权所有
经营许可证编号:鄂ICP备2022015515号-1