实验编排宁.docx
《实验编排宁.docx》由会员分享,可在线阅读,更多相关《实验编排宁.docx(39页珍藏版)》请在冰豆网上搜索。
实验编排宁
数据结构实验指导
宁黎华编
数学与计算科学学院
目录
实验一顺序表的基本操作1
实验二链表的基本操作4
实验三栈的基本运算8
实验四二叉树的操作11
实验五马踏棋盘问题14
实验六二叉检索树16
实验七排序18
附录一 TURBOTC出错信息一览21
附录二实验报告的一般格式24
实验一顺序表的基本操作
1、实验目的
(1)掌握顺序表的基本运算,熟悉对顺序表的一些基本操作和具体函数的定义。
(2)掌握顺序存储的概念,学会定义线性表的顺序存储类型。
(3)熟悉c语言程序的基本结构,掌握程序中的用户头文件、实现文件和主文件之间的相互关系及各自的作用。
(4)熟悉c语言环境的使用及程序的输入、编辑、调试和运行的全过程。
(5)加深对顺序存储结构的理解,逐步培养解决实际问题的编程能力。
2、实验要求
(1)熟练掌握线性表的存储结构及其基本操作。
(2)理解所给出的算法,掌握线性表在实际中的应用。
(3)将上机程序调试通过,并能独立完成一至两个拓展题目。
3、实验内容
实现顺序表上的插入、删除等操作。
调试程序并对相应的输出作出分析;修改输入数据,预期输出并验证输出的结果。
加深对有关算法的理解。
4、实验方法
第一步:
定义顺序表的存储结构。
第二步:
编写顺序表操作的具体函数定义。
第三步:
使用定义的顺序表并调用顺序表的一些操作,实现具体运算。
具体函数的定义有:
1)insert(L,i,x)在顺序表的第i个元素之前插入一个新元素x.
2)deletet(L,i)删除顺序表的第i个元素。
3)listprint(L)输出顺序表。
注意:
每完成一个步骤,必须及时输出线性表元素,以便于观察操作结果。
#defineMAXSIZE100/*宏定义*/
#defineOK1
#defineOVERFLOW-2
#include"stdio.h"/*包含输入输出文件*/
typedefintelemtype;
typedefstruct/*定义顺序表的结构*/
{elemtypevec[MAXSIZE];/*顺序表数据成员所占据的存储空间*/
intlast;/*顺序表中最后一个元素在数组中的下标(或向量中的位置)从0开始*/
}sequenlist;
intinsert(L,i,x)/*在顺序表的第i个元素之前插入一个新元素x*/
sequenlist*L;
inti;
elemtypex;
{intj;
if(((*L).last)>=MAXSIZE-1)
{printf("thelistisoverflow!
\n");
return(0);/*溢出判断*/
}
else
if((i<1)||(i>(*L).last+1))
{printf("positionisnotcorrect!
\n");
return(0);/*插入位置不正确*/
}
else
{for(j=(*L).last;j>=i-1;j--)/*后移元素*/
(*L).vec[j+1]=(*L).vec[j];
(*L).vec[i-1]=x;/*插入新元素*/
(*L).last=(*L).last+1;/*修改last的值*/
}
return
(1);
}
voiddelete(L,i)/*删除顺序表的第i个元素*/
sequenlist*L;
inti;
{intj;
if((i<1)||(i>(*L).last+1))
printf("deletefail\n");
else
{for(j=i;j<=(*L).last;j++)
(*L).vec[j-1]=(*L).vec[j];/*前移元素,覆盖掉要删除元素的值*/
(*L).last--;/*修改last的值*/
}
}
voidlistprint(sequenlist*L)/*输出线性表*/
{inti;
for(i=0;i<=(*L).last;i++)
printf("i,e=%d,%d\n",i,L->vec[i]);
}
main()
{
sequenlistsl={{1,2,3,4,5,6,7,8,9,10},9};//直接给顺序表赋初值
sequenlist*L;/*定义一个指向顺序表类型的指针变量*/
inti,j,x;
elemtypee;
L=&sl;/*给指针变量赋值*/
printf("pleaseinputtheinsertpositionandinsertvalue\n");
scanf("%d,%d",&i,&x);
printf("theinsertposition:
%d\ninsertvalue:
%d\n",i,x);
insert(L,i,x);
listprint(L);
printf("pleaseintputthedeleteposition:
");
scanf("%d",&j);
delete(L,j);
listprint(L);
}
5、预习思考题
调试好上述程序后,试着完成以下拓展内容:
(1)定义一个定位函数locate(L,x),具有元素检索的功能。
当顺序表中存在一个值为x的数据元素时,返回第一次找到的数据元素的位序,否则,给出一个值,表示值为x的元素不存在。
在主程序中调用该函数,分析操作结果。
(2)定义一个逆置函数diverse(L),把顺序表进行逆置。
在主程序中调用该函数,分析操作结果。
(3)定义一个函数delsame(L),把顺序表中重复的元素删除掉,只保留一个。
在主程序中调用该函数,分析操作结果。
6、分析讨论题:
在c语言中,用户向系统申请一块地址连续的有限空间的方法是使用数组。
而数组分为动态数组和静态数组。
静态数组的存储空间的申请和释放是由系统自动完成的,一旦申请成功,其所占用的内存大小也就固定不变了,一般的申请方式如inta[10];而动态数组存储空间的申请和释放是由用户通过调用系统函数自己完成的,常见的申请方式如int*a;a=newint[10];动态数组的大小运行时给定,但运行过程中可以改变。
那么,你知道什么时候使用动态数组,什么时候使用静态数组么?
如果顺序表的结构体定义中使用的不是静态数组,而是动态数组,那么有什么问题需要考虑?
如果线性表中需要频繁地插入或者删除元素,那么使用哪种数组申请方式好?
实验二链表的基本操作
1、实验目的
(1)学会单链表结点的定义
(2)掌握单链表的基本运算,熟悉对单链表的一些基本操作和具体函数的定义。
(3)加深对链表的理解,逐步培养解决实际问题的编程能力。
2、实验要求
(1)熟练掌握链表的存储结构及其基本操作。
(2)理解所给出的算法,掌握链表在实际中的应用。
(3)将上机程序调试通过,并能独立完成一至两个拓展题目。
3、实验内容
从键盘输入数据,创建一个初始链表。
通过调用定义的基本操作函数来实现单链表上的插入、删除元素等操作。
调试程序并对相应的输出作出分析;修改输入数据,预期输出并验证输出的结果。
加深对有关算法的理解。
4、实验方法
第一步:
定义单链表的存储结构。
第二步:
编写单链表操作的具体函数定义。
第三步:
使用定义的单链表并调用单链表的一些操作,实现具体运算。
具体函数的定义有:
1)insert(L,i,x)在单链表的第i个元素之前插入一个新元素x.
2)deletet(L,i)删除单链表的第i个元素。
3)listprint(L)输出单链表。
注意:
每完成一个步骤,必须及时输出链表元素,以便于观察操作结果。
#include"stdio.h"
#include"malloc.h"/*包含动态分配内存函数*/
#defineNULL0
#defineTRUE1
#defineFALSE0
typedefintelemtype;
typedefstructnode/*链表结点类型定义*/
{elemtypedata;/*结点数据域*/
structnode*next;/*结点的指针域*/
}linklist;
linklist*creatlist()/*创建链表函数—以按下任意建开始创建,以输入字符‘?
’{charch;表示结束标志*/
intx;
linklist*head,*r,*p;
p=(linklist*)malloc(sizeof(linklist));
head=p;
p->next=NULL;
r=p;
ch=getchar();
while(ch!
='?
')
{scanf("%d",&x);
p=(linklist*)malloc(sizeof(linklist));
p->data=x;
p->next=NULL;
r->next=p;
r=r->next;
ch=getchar();
}
return(head);
}
intlocate(head,k)/*定位检索函数—如链表中存在值为k的结点,则返回真,否
linklist*head;则返回假*/
elemtypek;
{linklist*s;
s=head->next;
while(s!
=NULL)
if(s->data!
=k)
s=s->next;
else
returnTRUE;
returnFALSE;
}
voidinsert(linklist*head,inti,elemtypex)/*在链表head的第i个位置插入{linklist*s,*p;元素x*/
intj;
p=head;
j=0;
while(p->next&&jnext;j++;}
if(!
p||j>i-1)printf("error!
");
s=(linklist*)malloc(sizeof(linklist));
if(!
s)printf("overflow!
");
s->data=x;
s->next=p->next;
p->next=s;
}
voiddelete(linklist*head,inti)/*删除链表的第i个结点*/
{intj=0;
linklist*p,*s,*q;
p=head;j=0;
while((p->next!
=NULL)&&(j{p=p->next;
j++;
}
if(p->next!
=NULL)
{q=p->next;
p->next=p->next->next;
free(q);
}
elseprintf("illegaldeleteposition,deletefailed!
");
}
voidprint(linklist*head)/*打印出链表head中各个结点的值*/
{linklist*p;
p=head->next;
while(p!
=NULL)
{printf("%d",p->data);
p=p->next;
}
printf("\n");
}
voidmain()/*主函数*/
{linklist*head;/*定义指向链表的指针head*/
intx;
inti,j;
printf("pleaseinputtheinitialnodeandstartbyanykey('?
'execpt)endwith'?
'\n");
head=creatlist();
printf("wehavecreatedalinklistasfollow:
\n");
print(head);
printf("nowstartsearch,pleaseinputthesearchvalue:
");
scanf("%d",&x);
printf("\n");
if(locate(head,x))printf("exsist!
\n");
else
printf("notexsist!
\n");
printf("startinsertoperation,pleaseinputinsertposition:
");
scanf("%d",&i);
insert(head,i,x);
printf("afterinsertion:
\n");
print(head);
printf("nowstartdeleteoperation,inputthedeletepositionplease:
");
scanf("%d",&j);
delete(head,j);
printf("afterdeletion:
\n");
print(head);
}
5、预习思考题
调试好上述程序后,试着完成以下拓展内容:
(1)定义一个逆置函数diverse(L),把链表进行逆置。
在主程序中调用该函数,分析操作结果。
(2)定义一个函数delsame(L),把链表中重复的元素删除掉,只保留一个。
在主程序中调用该函数,分析操作结果。
6、分析讨论题:
带头结点的单链表和不带头结点的单链表有什么区别?
如果上述程序中采用的是不带头结点的单链表,程序需要做哪些改动?
实验三栈的基本运算
1、实验目的
(1)掌握栈的各种存储结构及基本运算的实现。
(2)掌握堆栈后进先出的运算原则在解决实际问题中的应用。
(3)复习c语言中相关语句及函数的用法。
2、实验要求
(1)熟练掌握栈的存储结构及其基本操作。
(2)理解所给出的算法,掌握栈在实际中的应用。
(3)将上机程序调试通过,并能独立完成一至两个拓展题目。
3、实验内容
括号配对检查。
试设计一个程序对任意输入的语句或数学表达式,判断其括号是否匹配。
若匹配,则返回1,否则返回0。
调试程序并对相应的输出作出分析;修改输入数据,预期输出并验证输出的结果。
加深对算法的理解。
4、实验方法
首先建立一个栈结构,且初始化栈为空。
然后由键盘上随即输入一个带括号的语句或带括号的数学表达式,同时将它们保存在一个字符型数组exps[]中。
扫描表达式exps,当遇到“(”、“[”、“{”时,将其入栈。
遇到“)”、“]”、“}”时,判断栈顶是否有相匹配的括号。
若没有,则退出扫描过程,返回0,否则直到exps扫描完毕为止。
若top为0,则返回1。
#include“stdio.h”
#defineMAXSIZE100
#defineTRUE1
#defineFALSE0
#defineNULL0
typedefintdatatype;
typedefstruct/*顺序栈的结构体类型定义*/
{datatypestack[MAXSIZE];
inttop;
}seqstack;
voidsetnull(seqstack*s)/*置空栈—由于c语言的数组下标是从0开始的,所以置{s->top=-1;}空栈操作时将栈顶指针放在下标为0之前,即-1处。
*/
intempty(seqstack*s)/*判断当前栈是否为空栈*/
{if(s->top<0)
returnTRUE;
else
returnFALSE;
}
intpush(seqstack*s,datatypex)/*把元素x压入栈s中*/
{if(s->top>=MAXSIZE-1)
{printf("stackoverflow!
\n");/*发生上溢*/
returnFALSE;
}
else
{s->stack[++s->top]=x;/*栈顶指针上移,数据元素入栈*/
returnTRUE;
}
}
datatypepop(seqstack*s)/*弹出当前栈s的栈顶元素*/
{if(s->top<0)
{printf("stackempty!
\n");/*栈空,返回空值*/
returnNULL;
}
else
{s->top--;
return(s->stack[s->top+1]);
}/*由于return语句的特点,必须先使top减1,然后再执行return语句。
而此
}时栈顶元素的表示应该为s->top+1.*/
intjudge(seqstack*s)/*括号匹配检查算法。
--遇到“(”、“[”、“{”时,将其压{入栈s中。
*/
datatypesymb,ch,store;
push(s,'#');
symb=getchar();/*从键盘接受字符*/
while(symb!
='#')
{
switch(symb)
{
case'(':
case'[':
case'{':
push(s,symb);break;
case')':
ch=pop(s);
if(ch!
='(')returnFALSE;
break;
case']':
ch=pop(s);
if(ch!
='[')returnFALSE;
break;
case'}':
ch=pop(s);
if(ch!
='{')returnFALSE;
break;
default:
;
}
symb=getchar();
}
if(pop(s)=='#')returnTRUE;
elsereturnFALSE;
}
main()
{
seqstackq;
setnull(&q);
printf("pleaseinputanexpressendwithsymbol'#':
\n");
if(judge(&q))printf("yes\n");/*括号匹配,则输出yes*/
elseprintf("no\n");/*括号不匹配,则输出no*/
}
5、预习思考题
调试好上述程序后,试着完成以下拓展内容:
(1)假定表达式不是通过getchar()函数一个个传送的,而是存放在一个字符数组A[n]中,程序需要做哪些改变?
(2)在judge()函数中,如果不用switch()函数,你会怎么处理?
6、分析讨论题:
数制转换问题是栈应用的一个典型实例。
将十进制数转换成其它进制的数有一种简单的方法:
例:
十进制转换成八进制:
(66)10=(102)8
66/8=8余2
8/8=1余0
1/8=0余1
结果为余数的逆序:
102。
如果用栈的算法来实现,怎样实现?
其基本原理是什么?
实验四二叉树的操作
1、实验目的
(1)掌握二叉树链表的结构和二叉树的建立过程。
(2)掌握队列的先进先出的运算原则在解决实际问题中的应用。
(3)进一步掌握指针变量、指针数组、动态变量的含义。
(4)掌握递归程序设计的特点和编程方法。
2、实验要求
(1)熟练掌握二叉链表的存储结构。
(2)熟练掌握循环队列的基本操作。
(3)理解所给出的算法,掌握循环队列在实际中的应用。
(4)加深对递归算法的理解。
(5)将上机程序调试通过,并能独立完成一至两个拓展题目。
3、实验内容
已知以二叉链表作存储结构,试编写按层次遍历二叉树的算法。
(所谓层次遍历,是指从二叉树的根结点开始从上到下逐层遍历二叉树,在同一层次中从左到右依次访问各个节点。
)调试程序并对相应的输出作出分析;修改输入数据,预期输出并验证输出的结果。
加深对算法的理解。
4、实验方法
本算法要采用一个循环队列que,先将二叉树根结点入队列,然后退队列,输出该结点;若它有左子树,便将左子树根结点入队列;若它有右子树,便将右子树根结点入队列,直到队列空为止。
因为队列的特点是先进先出,从而达到按层次顺序遍历二叉的目的。
#defineM100
#defineNull0
typedefstructnode/*二叉链表结点结构*/
{intdata;/*数据域*/
structnode*lchild,*rchild;/*左、右孩子域*/
}bitree;
bitree*que[M];/*定义一个指针数组,说明队列中的元素类型为bitree指针类型*/
intfront=0,rear=0;/*初始化循环队列*/
bitree*creat()/*建立二叉树的递归算法*/
{bitree*t;
intx;
scanf("%d",&x);
if(x==0)t=Null;/*以x=0表示输入结束*/
else{
t=malloc(sizeof(bitree));/*动态生成结点t,分别给结点t的数据域、左右孩子域t->data=x;赋值,给左右孩子域赋值时用到了递归的思想。
*/
t->lchild=creat();
t->rchild=creat();
}
returnt;
}
voidinorder(bitree*t)/*中序遍历二叉树的递归算法*/
{if(t!
=Null)
{inorder(t->lchild);
printf("%4d",t->data);
inorder(t->rchild);
}
}
voidenqueue(t)/*把bitree类型的结点*t入队列*/
bitree*t;
{if(front!
=(rear+1)%M)/*判断队列是否已满*/
{rear=(rear+1)%M;
que[rear]=t;
}
}
bitree*delqueue()
{
if(front==rear)/*判断队列不为空*/
returnNull;
front=(front+1)%M;
return(que[front]);
}
voidlevorder(t)/*层次遍历二叉树的算法*/
bitree*t;
{bitree*p;
if(t!
=Null)
{enqueue(t);/*根结点入队*/
while(front!
=rear)/*当当前队列不为空时*/
{p=delqueue();/*输出对头元素,并把其左右孩子入队。
此过程一直递归,直到队列printf("%4d",p->data);为空*/
if(p->lchild!
=Null)
enqueue(p->lchild);
if(p->rchild!
=Null)
enqueue(p->rchild);}
}
}
main()/*主函数*/
{bitree*root;
printf("\n");
root=cr