《数据结构与算法》实验指导书
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
《数据结构》实验
指导书
计算机与软件学院
2014年9月
概述
实习目的和要求
《数据结构》在计算机科学中是一门实践性较强的专业基础课,上机实习是对学生的一种全面综合训练,是与课堂听讲、自习和练习相辅相成的必不可少的一个教学环节。
实习着眼于原理与应用的结合,使学生学会把学到的知识用于解决实际问题,起到深化理解和灵活掌握教学内容的目的。
同时,通过本课程的上机实习,使学生在程序设计方法及上机操作等基本技能和科学作风方面受到比较系统和严格的训练。
实习包括的步骤
1.简要描述题目要求,对问题的描述应避开算法及所涉及的数据类型,只是对所需完成的任务做出明确的陈述,例如输入数据的类型、值的范围以及输入的形式,输出数据的类型、值的范围以及输出的形式。
2.选定数据结构,写出算法,根据自顶向下发展算法的方法,首先描述算法的基本思想,然后进行算法细化,再对所设计的算法的时间复杂性和空间复杂性进行简单分析。
3.准备好上机所需的程序,选定一种程序设计语言(如C语言),手工编好上机程序,并进行反复检查,使程序中的逻辑错误和语法错误减少到最低程度。
对程序中有疑问的地方,应做出标记,以便在上机时给予注意。
4.上机输入和调试程序,在调试程序过程中除了系统的问题以外,一般应自己独立解决。
在程序调试通过后,打印输出程序清单和运行结果。
5.上机结束后,总结和整理实习报告。
实习报告的内容
1.简述题目要解决的问题是什么,并说明输入和输出数据的形式。
2.简述存储结构和算法的基本思想。
3.列出调试通过的源程序。
4.列出上面程序对应的运行结果。
5.分析程序的优缺点、时空性能以及改进思想,写出心得体会。
实验一线性表
一.目的与要求
本次实习的主要目的是为了使学生熟练掌握线性表的基本操作在顺序存储结构和链式存储结构上的实现,提高分析和解决问题的能力。
要求仔细阅读并理解下列例题,上机通过,并观察其结果,然后独立完成后面的实习题。
二.例题
[问题描述]
用链表形式存储一个字符串,插入、删除某个字符,最后按正序、逆序两种方式输出字符串。
[输入]
初始字符串,插入位置,插入字符,删除字符。
[输出]
已建立链表(字符串),插入字符后链表,删除字符后链表,逆转后链表。
[存储结构]
采用链式存储结构
[算法的基本思想]
建立链表:当读入字符不是结束符时,给结点分配存储空间,写数据域,将新结点插到表尾;插入字符:根据读入的字符在链表中找插入位置,将新结点插入到该位置之前;删除字符:根据读入的删除字符在链表中找到被删结点后,将其从链表中删除;链表逆转:从链表的第一个结点开始对所有结点处理,将每个结点的前驱变为它的后继;打印链表:从链表的第一个结点开始,依次打印各个结点的数据域。
[参考源程序]
#define NULL 0
typedef struct node{
char a;
struct node *link;
}node,*nodelink;
void readlink(nodelink head){
nodelink p,q;
char c;
p=head;
printf("Input a linktable(a string):");
scanf("%c",&c);
if (c=='\n') printf("This string is empty。
");
while(c!='\n'){
q=(nodelink)malloc(sizeof(node));
q->a=c;
p->link=q;
p=q;
scanf("%c",&c);
}
p->link=NULL;
}
void writelink(nodelink head){
nodelink q;
if (head->link==NULL) printf(" This link is empty。
\n");
for(q=head->link;q;q=q->link)
printf("%c",q->a);
printf("\n");
}
int insert(nodelink head,char k1,char k2){
nodelink p,q;
p=head->link;
while(p->a!=k1&&p)
p=p->link;
if(p){
q=(nodelink)malloc(sizeof(node));
q->a=k2;
q->link=p->link;
p->link=q;
return 1;
}
else {
printf("There is no %c\n",k1);
return 0;
}
}
int delete(nodelink head,char k){
nodelink p,q;
q=head;
p=head->link;
while(((p->a)!=k)&&p){
q=q->link;
p=p->link;
}
if(p){
q->link=p->link;
return 1;
}
else{
printf("There is no %c\n",k);
return 0;
}
}
void opside(nodelink head){
nodelink p,q;
p=head->link;
while(p->link){
q=p->link;
p->link=q->link;
q->link=head->link;
head->link=q;
}
}
main()
{
char k1,k2,k3;
nodelink head;
head=(nodelink)malloc(sizeof(node));
head->link=NULL;
readlink(head);
if (head->link!=NULL){
printf("Build link is :");
writelink(head); }
if (head->link!=NULL){
printf("Please input a char you want to insert after:");
k1=getch();
printf("%c\n",k1);
printf("Please input a char you want to insert:");
k2=getch();
printf("%c\n",k2);
if (insert(head,k1,k2)) {
printf("After %c insert %c,link is:",k1,k2);
writelink(head);
}
printf("Please input a char you want to delete:");
k3=getch();
printf("%c\n",k3);
if (delete(head,k3))
{ printf("after delete %c,link is:",k3);
writelink(head);
}
if (head->link!=NULL){
printf("Opsite result is :");
opside(head);
writelink(head);
free(head);
}
}
}
三.实习题
1.设顺序表A中的数据元素递增有序,试写一程序,将x插入到顺序表的适当位置上,使该表仍然有序。
2.用单链表ha 存储多项式A(x )=a0+a1x1+a2x2+…+a n x n(其中a I为非零系数),用单链表hb 存储多项式B(x )=b0+b1x1+b2x2+…+b m x m(其中b j为非零系数),要求计算C(x )= A(x )+B(x ),结果存到单链表hc中。
试写出程序。
3.设有n个人围坐在一个圆桌周围,现从第s个人开始报数,数到第m的人出列,然后从出列的下一个人重新开始报数,数到m的人又出列,如此重复,直到所有的人全部出列为止。
Josephus问题是:对于任意给定的n,m,s,求出按出列次序得到的n个人员的顺序表。
实验二树
一.目的与要求
熟悉树的各种表示方法和各种遍历方式,掌握有关算法的实现,了解树在计算机科学及其它工程技术中的应用。
二.例题
[问题描述]
任意给定一棵二叉树。
试设计一个程序,在计算机中构造该二叉树,并对它进行遍历。
[输入]
一棵二叉树的结点若无子树,则可将其子树看作“.”,输入时,按照前序序列的顺序输入该结点的内容。
对下图,其输入序列为ABD..EH...CF.I..G..。
[输出]
若为空二叉树,则输出:THIS IS A EMPTY BINARY TREE。
若二叉树不空,按后序序列输出,对上例,输出结果为:DHEBIFGCA。
[存储结构]
采用二叉链表存储。
[算法的基本思想]
采用递归方法建立和遍历二叉树。
首先建立二叉树的根结点,然后建立其左右子树,直到空子树为止。
后序遍历二叉树时,先遍历左子树,后遍历右子树,最后访问根结点。
[参考源程序]
#include<stdio.h>
#include<alloc.h>
struct node{
char info;
struct node *llink,*rlink;
};
typedef struct node NODE;
NODE *creat(){
char x;
NODE *p;
scanf("%c",&x);
printf("%c",x);
if(x!='.'){
p=(NODE *)malloc(sizeof(NODE));
p->info=x;
p->llink=creat();
p->rlink=creat();
}
else
p=NULL;
return p;
}
void run(NODE *t){
if(t){
run(t->llink);
run(t->rlink);
printf("%c",t->info);
}
}
main()
{
NODE *T;
printf("PLease input a tree:\n");
T=creat();
printf("\n");
if(!T)
printf("This is a empty binary tree.");
else
{ printf("The result of post travese is:\n ");
run(T);
}
printf("\n");
}
三.实习题
1.编写递归算法,计算二叉树中叶子结点的数目。
2.编写递归算法,在二叉树中求位于先序序列中第K个位置的结点。
3.将上述例题用非递归程序实现。
实验三图
一.目的与要求
熟悉图的存储结构,掌握有关算法的实现,了解图在计算机科学及其他工程技术中的应用。
二.例题
[问题描述]
给定一个图,设计一个程序,找出一条从某一顶点A到另一顶点B边数最少的一条路径。
[输入]
图的顶点个数N,图中顶点之间的关系及要找的路径的起点A和终点B。
[输出]
若A到B无路径,则输出“There is no path”,否则输出A到B路径上各顶点。
[存储结构]
图采用邻接矩阵的方式存储。
[算法的基本思想]
采用广度优先搜索的方法,从顶点A开始,依次访问与A邻接的顶点V A1,V A2,...,V AK,访问遍之后,若没有访问B,则继续访问与V A1邻接的顶点V A11,V A12,...,V A1M,再访问与V A2邻接顶点...,如此下去,直至找到B,最先到达B点的路径,一定是边数最少的路径。
实现时采用队列记录被访问过的顶点。
每次访问与队头顶点相邻接的顶点,然后将队头顶点从队列中删去。
若队空,则说明到不存在通路。
在访问顶点过程中,每次把当前顶点的序号作为与其邻接的未访问的顶点的前驱顶点记录下来,以便输出时回溯。
[参考源程序]
#include<stdio.h>
int number;
typedef struct{
int q[20];
int f,r;
}queue;
int nodelist[20][20];
queue Q;
int z[20];
int a,b,n,i,j,x,y;
int finished;
void enq(queue *Q,int x){
Q->q[Q->r]=x;
if(Q->r==19)
Q->r=0;
else
Q->r++;
if(Q->r==Q->f)
printf("Overflow!\n"); }
front(queue *Q){
if(Q->r==Q->f)
printf("Underflow!\n");
else
return(Q->q[Q->f]);
}
void deq(queue *Q){
if(Q->r==Q->f)
printf("Underflow!\n");
else{
if(Q->f==19)
Q->f=0;
else
Q->f++;
}
}
int qempty(queue Q){
if(Q.f==Q.r)
return 1;
else
return 0;
}
void readgraph(){
printf("\nPlease input n:");
scanf("%d",&n);
printf("Please input nodelist[i][j]:\n");
for(i=1;i<=n;i++){
for(j=1;j<=n;j++)
scanf("%d",&nodelist[i][j]);
}
printf("\n");
printf("List-link is bulit\n");
for(i=1;i<=n;i++){
for(j=1;j<=n;j++)
printf("%3d",nodelist[i][j]);
printf("\n");
}
}
void shortest(int a,int b){
if(a==b)
nodelist[a][a]=2;
else{
enq(&Q,a);
nodelist[a][a]=2;
finished=0;
while(!qempty(Q)&&!finished){
a=front(&Q);
deq(&Q);
j=1;
while((j<=n)&&!finished){
if((nodelist[a][j]==1)&&(nodelist[j][j]!=2)){
enq(&Q,j);
nodelist[j][j]=2;
z[j]=a;
if(j==b)/*&&(nodelist[a][j]==1))*/
finished=1;
}
if(!finished)
j++;
}
}
if (!finished) printf("There is no path.");
}
}
void writepath(int a,int b){
i=b;
while(i!=a){
printf("%d <- ",i);
i=z[i];
}
printf("%d",a);
}
main()
{
readgraph();
printf("Please input a:");
scanf("%d",&a);
printf("Please input b:");
scanf("%d",&b);
Q.f=0; Q.r=0;
shortest(a,b);
if (finished)
writepath(a,b);
}
三.实习题
1.采用邻接表存储结构,编写一个求无向图的连通分量个数的算法。
2.试基于图的深度优先搜索策略编写一程序,判别以邻接表方式存储的有向图中是否存
在有顶点V i到V j顶点的路径(i≠j)。
3.在上述例题中,如改用邻接表的方式存储图,试编一程序实现上述算法。
顶点表
其中mark mark字段为false,每访问过一个顶点,则mark字段置为true。
info为顶点值,pre为访问路径上该顶点的前驱顶点的序号,out指向该顶点的出边表。
实验四查找
一.目的与要求
通过本次实验,掌握查找表上的有关查找方法,并分析时间复杂度。
二.例题
[问题描述]
将折半查找算法写成完整的程序,并上机通过。
[输入]
有序表(12,23,28,35,37,39,50,60,78,90)及待查找记录23,58。
[输出]
输入23,表中存在待查找记录,则显示该记录在表中位置2,输入58显示该记录不存在。
[存储结构]
有序表采用顺序方式存储。
[算法的基本思想]
首先用待查找记录与查找区间中间位置记录比较,若相等则查找成功,返回该记录在表中的位置数,若小于中间位置记录,则修改区间上界为中间位置减1,若大于中间位置记录,则修改区间下界为中间位置加1,在新的区间内继续查找。
当查找区间下界大于上界,则该记录不存在。
[参考源程序]
#include"stdio.h"
typedef struct{
int a[30];
int length;
}sqtable;
sqtable st;
int b=0;
void createst(int k){
int i;
printf("Please input data:");
st.a[0]=-100;
for (i=1;(!b&&(i<=k));i++){
scanf("%d",&(st.a[i]));
if (st.a[i]<st.a[i-1]){
printf("Input data error.\n");
b=1;
}
}
if (!b){
st.length=k;
printf("The table is builted.\n");
}
}
void stfind(sqtable st,int y){
int f,l,h,m;
l=1;h=st.length;
f=1;
while ((l<=h)&&f){
m=(l+h)/2;
if (y==st.a[m]) f=0;
else if (y<st.a[m]) h=m-1;
else l=m+1;
}
if (!f) printf("Find %d in position %d.\n",y,m);
else printf("Not find %d.\n",y);
}
main(){
int n,x;
printf("\nPlease input n:");
scanf("%d",&n);
createst(n);
if (b==0) {
printf("Please input you want find value:");
scanf("%d",&x);
stfind(st,x);
}
}
三.实习题
1.编写程序实现下面运算:在二叉排序树中查找关键字为key的记录。
2.试将折半查找的算法改写成递归算法。
实验五内排序
一.目的与要求
通过本次实验,掌握线性表的排序方法,并分析时间复杂度。
二.例题
[问题描述]
将快速排序算法写成完整的程序上机通过,并统计递归深度。
[输入]
待排序记录个数n,各待排序记录值。
[输出]
n个记录由小到大排列的结果。
[存储结构]
待排序记录顺序存储。
[算法的基本思想]
快速排序算法每次任取一个记录的关键字为标准,将其余记录分为两组,将所有关键字小于或等于标准的记录都放在它的位置之前,将所有关键字大于标准的记录都放在它的位置之后。
对这两组再进行快速排序,直到完全有序。
每递归1次,递归深度加1。
[参考源程序]
#include<stdio.h>
typedef int node;
node afile[20];
node x;
int d,dl,n;
int l,r,i,j;
void q(int l,int r){
int p;
d++;
if(dl<d)
dl=d;
printf("dl=%d ",dl);
printf("d=%d\n",d);
if(l<r){
i=l; j=r;
x=afile[i];
while(i!=j){
while((afile[j]>x)&&(j>i))
j--;
if(i<j)
afile[i++]=afile[j];
while((afile[i]<x)&&(j>i))
i++;
if(i<j)
afile[j--]=afile[i];
}
afile[i]=x;
for(p=1;p<=n;p++)
printf("%d,",afile[p]);
printf("\n");
q(l,i-1);
q(i+1,r);
}
d--;
printf(" * *%d* *\n",d);
}
main()
{ int p;
printf("\nPlease input n:\n");
scanf("%d",&n);
printf("Please input a string:");
for(p=1;p<=n;p++)
scanf("%d",&(afile[p]));
d=0; dl=0;
l=1; r=n;
q(l,r);
for(p=1;p<=n;p++)
printf("%d,",afile[p]);
printf("\n");
printf("dl=%d\n",dl);
}
三.实习题
1.设计一个用链表表示的直接选择排序算法,并用程序实现。
算法说明:已知待排序初始序列用单链表存贮,头指针head指向第一个结点,从这个待排序列中找出最小结点,插入head之后,用r来指示。
r以前为已排序序列,r以后为未排序序列。
再从未排序序列中找出最小结点插入r的后面,让r指向这个结点。
反复执行这个过程,直到排好序。
2.对N个关键字取整数的记录进行整序,以使所有关键字为非负数的记录排在关键字为负数的记录之前,要求使用最少的附加空间,且算法的时间复杂度为O(N)。