数据结构课程设计说明书.docx
- 文档编号:4067610
- 上传时间:2022-11-27
- 格式:DOCX
- 页数:40
- 大小:89.16KB
数据结构课程设计说明书.docx
《数据结构课程设计说明书.docx》由会员分享,可在线阅读,更多相关《数据结构课程设计说明书.docx(40页珍藏版)》请在冰豆网上搜索。
数据结构课程设计说明书
*******************
实践教学
*******************
兰州理工大学
计算机与通信学院
2014年秋季学期
数据结构与算法课程设计
题目:
求素数问题、计算1的个数问题、
递归替换问题、图的基本操作与实现
专业班级:
软件工程13级1班
姓名:
学号:
指导教师:
成绩:
摘要
本设计主要是用C语言设计开发,所用IDE工具为codeblocks,四个问题均应用了不同的数据结构,有图的存储,有递归的操作等等,再设计过程中也应用了不同的算法如埃拉托色尼筛法,图的深度优先搜索和广度优先搜索。
第一个程序是用埃拉托色尼筛法求解素数问题。
用一个循环结构判断是否为素数,如果是素数则返回1,负责返回0。
第二个程序是递归结构计算1的个数问题,共分为两种情况,奇数情况和偶数情况。
第三个程序为递归替换仿编译问题,具体要求是递归替换问题。
编写程序,扩展C/C++源文件中的#include指令(以递归的方式)。
以文件名的内容替换形预编译命令“include”。
具体是用相应文件的内容来替换上面的代码“预编译”的命令,即在最后的结果查看文件中没有“#include”字样,其位置为相应文件的内容,考虑到有可能在我们要替换的文件中也可能会有预编译命令,所以要用递归的算法。
通过这个代码的编写可以帮我们更深层次的理解c语言编译的过程,同时也能够练习递归的运用。
第四个程序为图的一些基本操作,内容包括图的存储结构、图的深度优先遍历,广度优先遍历,图节点的度数等等。
关键词:
埃拉托色尼筛法素数问题递归替换连通图
克鲁斯卡尔算法数据结构图的遍历
一.求素数问题
1.问题描述
埃拉托色尼筛法(SieveofEratosthenes)是一种用来求所有小于N的素数的方法。
从建立一个整数2~N的表着手,寻找i˂
的整数,编程实现此算法,并讨论运算时间。
(1)
2.算法设计
用一个循环结构判断是否为素数,如果是素数则返回1,负责返回0。
intsushu(DataType&i)
{
intm;
if(i==1)
return0;
for(m=2;m
{
if(i%m==0)
return0;
}
return1;
}
3.源程序
#include
#include
#definemaxsize200
#defineFALSE0
typedefintDataType;
typedefstruct{
DataTypedata[maxsize];
intlength;
}Seqlist;//结点结构
intsushu(DataTypei)//判断是否为素数
{
intm;
if(i==1)
return0;
for(m=2;m
{
if(i%m==0)
return0;
}
return1;
}
intmain()
{
SeqlistL;
L.length=maxsize;
intm;
intj;
for(j=2;j<=L.length;j++)
{
L.data[j-1]=j;
printf("%d\t",L.data[j-1]);
}
printf("\n");
printf("inputm:
\n");
scanf("%d",&m);
if(m>L.length)returnFALSE;
printf("1至m之间的素数从小到大分别为:
\n");
inti,k=0;
for(i=1;i<=m;i++)
L.data[i-1]=i;
for(i=1;i<=m;i++)
if(sushu(L.data[i-1]))
{
k++;
printf("%d\t",L.data[i-1]);//符号“\t”的作用是横向制表。
}
printf("\n总共%d个。
\n",k);
return0;
}
4.运行结果
图1
.图2为1~m之间的素数
图2
3图3为m大于L.length时的图
图3
5.总结
1当m的值大于maxsize的值是发生越界问题,在输入m时要确保m的值要小于maxsize的值
2、算法的时间复杂度O(L.length-1)+O(m)。
二.计算1的个数问题
1.问题描述
编写递归程序,返回十进制数N的二进制表示中1的个数。
2.算法设计
采用递归结构
采用以下已知情况设计程序
若N是奇数,那么它的二进制中1的个数等于N/2的二进制中1的个数加1,N-1是偶数,比N少一个最低位的1,1的个数就是N/2的二进制中1的个数-1。
3.源程序
#include
intcount(intN)
{
intn;
if(N==1)n=1;
elseif((N+1)%2==0)n=count(N/2)+1;//奇数情况若N是奇数,那么它的二进制中1的个数等于N/2的二进制中1的个数加1,
elseif(N%2==0)n=count(N+1)-1;//偶数情况若N是奇数,N-1是偶数,比N少一个最低位的1,1的个数就是N/2的二进制中1的个数-1
returnn;
}
voidmain(){
intN;
printf("请输入数字:
");
scanf("%d",&N);
printf("二进制中1的个数:
%d\n",count(N));
}
4.运行结果
5.总结
通过本程序的设计了解了如何采用递归结构进行解决问题。
三.递归替换的问题
1.问题描述
编写程序,扩展C/C++源文件中的#include指令(以递归的方式)。
请以文件名的内容替换形如下面的代码行。
#include“filename”
2.算法设计
模拟C/C++预处理程序的功能,打开源文件后,先检查每一行的第一个字符是否是”#“,如果不是,则原样输出这一行;如果是,则处理预处理指令,先把”#“后紧跟的预处理指令解析出来,如果是include,则提取后面的文件名,打开文件,再递归调用这个预处理函数就行了
3.源程序
#include
#include
#include
#defineMAX100
typedefstruct//创建结构体,让文件的读写方便
{
chardata[MAX];//数据项
}char1;
int
print(charch[MAX],intn)//递归函数
{
FILE*fp,*fp1;
chars[MAX];//s,存储#后面的include
char1b[MAX];//b,文件中内容在内存中的存储位置
inti=0,k,d=0,j,flag;//switch参数,用于确认调用函数的参数
if((fp=fopen(ch,"rb+"))==NULL)
{
printf("文件打开失败!
\n");
exit(0);
}
while(!
feof(fp))
{
fread(&b[i],1,sizeof(char1),fp);
i++;
if(b[i-1].data[0]=='}')//结构体数组计数器
break;
}
k=i-1;//记录b大小,可以认为是对应文件的行数
fclose(fp);
if((fp1=fopen("辅助.c","ab+"))==NULL)
{
printf("文件打开失败!
\n");
exit(0);
}
d=0;//s数组存取计数器
for(i=0;i { if(b[i].data[0]=='#')//发现include,递归调用print { for(j=2;j<9;j++) { s[d]=b[i].data[j]; d++; } if((strcmp(s,"include"))==0) { flag=b[i].data[19]-'0'; switch(flag)//带选择的递归调用 { case1: fp=print("filename1.c",1);break; case2: fp=print("filename2.c",2);break; case3: fp=print("filename3.c",3);break; default: break; } } else//否则的话讲代码存入辅助文件 { printf("%s\n",b[i].data); fwrite(&b[i],1,sizeof(char1),fp); fputc('\r',fp); fputc('\n',fp); } } else//否则的话讲代码存入辅助文件 { printf("%s\n",b[i].data); fwrite(&b[i],1,sizeof(char1),fp1); fputc('\r',fp); fputc('\n',fp); } } close(fp1); return0; } 4.运行结果 5.总结 这个程序设计具体是用相应文件的内容来替换上面的代码“预编译”的命令,即在最后的结果查看文件中没有“#include”字样,其位置为相应文件的内容,考虑到有可能在我们要替换的文件中也可能会有预编译命令,所以要用递归的算法。 通过这个代码的编写可以帮我们更深层次的理解c语言编译的过程,同时也能够练习递归的运用。 四.图的基本操作与实现 1.问题描述 实现图的一些基本操作 (1)自选存储结构,输入含n个顶点(用字符表示顶点)和e条边的图G; (2)求每个顶点的度,输出结果; (3)指定任意顶点x为初始顶点,对图G作DFS遍历,输出DFS顶点序列(提示: 使用一个栈实现DFS); (4)指定任意顶点x为初始顶点,对图G作BFS遍历,输出BFS顶点序列(提示: 使用一个队列实现BFS); (5)输入顶点x,查找图G: 若存在含x的顶点,则删除该结点及与之相关连的边,并作DFS遍历(执行操作3);否则输出信息“无x”; (6)判断图G是否是连通图,输出信息“YES”/“NO”; (7)如果选用的存储结构是邻接矩阵,则用邻接矩阵的信息生成图G的邻接表,即复制图G,然再执行操作 (2);反之亦然。 2.算法设计 (1)自选存储结构创建一个图: 通过用户从键盘敲入的两个数值分别确定图的顶点数和边数,选择邻接矩阵存储结构将图的结点信息存储在一个顺序表中,图的边信息存储在一个二维数组中。 (2)求每个顶点的度: 1.邻接矩阵存储结构下求每个顶点的度: 利用图的邻接矩阵,每个顶点所在行和所在列的边的权值如果存在则该顶点的度+1,依次算出每个顶点的度,并且记录在一个数组中输出。 2.邻接表存储结构下求每个顶点的度: 定义一个邻接边指针循环指向顶点的邻接边单链表头结点,当结点不空时,该顶点的出度+1,邻接边弧头结点的入度+1,依次求出每个顶点的出度和入度之和就为该顶点的度。 (3)图的深度优先遍历: 采取邻接矩阵结构,指定任意顶点x为初始顶点 1.访问结点v并标记结点v已访问; 2.查找结点v的第一个邻接结点w; 3.若结点v的邻接结点w存在,则继续执行,否则算法结束; 4.若结点w尚未被访问,则递归访问结点w; 5.查找结点v的w邻接结点的下一个邻接结点w,转到步骤3。 (4)图的广度优先遍历: 采取邻接矩阵结构,指定任意顶点x为初始顶点,利用顺序循环队列以保持访问过的结点的顺序 1.首先访问初始结点v并标记结点v为已访问; 2.结点v入队列; 3.当队列非空时则继续执行,否则算法结束; 4.出队列取得队头结点u; 5.查找u的第一个邻接结点w; 6.若u的邻接结点w不存在则转到步骤3,否则循环执行下列步骤: 6.1若结点w尚未被访问,则访问结点w并标记结点w为已访问; 6.2结点w入队列; 6.3查找结点u的w邻接结点的下一个邻接结点w,转到步骤6。 (5)判断有向图的强连通性: 采取邻接表结构,在图中寻找一个包含所有顶点且首尾相连的环,若这样的环存在,则该图为强连通图,否则不为强连通图。 (6)用邻接矩阵的信息生成邻接表: 定义一个邻接表的边信息结构体,将邻接矩阵的边信息转换成邻接表的边信息存储到邻接边的单链表中。 3.源程序 源程序存放在八个文件中,文件SeqList.h是顺序表的结构体定义和操作函数,文件SeqCQueue.h是顺序循环队列的结构体定义和操作函数,文件AdjMGraph.h是邻接矩阵存储结构下图的结构体定义和操作函数,文件AdjMGraphCreate.h是邻接矩阵存储结构下图的创建函数,文件AdjLGraph.h是邻接表存储结构下图的结构体定义和操作函数,文件AdjLGraphCreate.h是邻接表存储结构下图的创建函数,文件AdjMGraphTraverse.h是邻接矩阵存储结构下图的深度优先遍历和广度优先遍历操作函数,文件图的基本操作与实现.c是主函数。 (1)/*文件SeqList.h*/ typedefstruct { DataTypelist[MaxSize]; intsize; }SeqList; voidListInitiate(SeqList*L) { L->size=0; } intListLength(SeqListL) { returnL.size; } intListInsert(SeqList*L,inti,DataTypex) { intj; if(L->size>=MaxSize) { printf("数组已满无法插入! \n"); return0; } elseif(i<0||i>L->size) { printf("参数不合法! \n"); return0; } else { for(j=L->size;j>i;i--)L->list[j]=L->list[j-1]; L->list[i]=x; L->size++; return1; } } intListDelete(SeqList*L,inti,DataType*x) { intj; if(L->size<=0) { printf("顺序表已空无数据元素可删! \n"); return0; } elseif(i<0||i>L->size-1) { printf("参数i不合法! \n"); return0; } else { *x=L->list[i]; for(j=i+1;j<=L->size-1;j++)L->list[j-1]=L->list[j]; L->size--; return1; } } intListGet(SeqListL,inti,DataType*x) { if(i<0||i>L.size-1) { printf("参数i不合法! \n"); return0; } else { *x=L.list[i]; return1; } } (2)/*文件SeqCQueue.h*/ typedefstruct { DataTypequeue[MaxQueueSize]; intrear; intfront; intcount; }SeqCQueue; voidQueueInitiate(SeqCQueue*Q) { Q->rear=0; Q->front=0; Q->count=0; } intQueueNotEmpty(SeqCQueueQ) { if(Q.count! =0)return1; elsereturn0; } intQueueAppend(SeqCQueue*Q,DataTypex) { if(Q->count>0&&Q->rear==Q->front) { printf("队列已满无法插入! "); return0; } else { Q->queue[Q->rear]=x; Q->rear=(Q->rear+1)%MaxQueueSize; Q->count++; return1; } } intQueueDelete(SeqCQueue*Q,DataType*d) { if(Q->count==0) { printf("队列已空无数据出队列! \n"); return0; } else { *d=Q->queue[Q->front]; Q->front=(Q->front+1)%MaxQueueSize; Q->count--; return1; } } intQueueGet(SeqCQueueQ,DataType*d) { if(Q.count==0) { printf("队列已空无数据出队列! \n"); return0; } else { *d=Q.queue[Q.front]; return1; } } (3)/*文件AdjMGraph.h*/ #include"SeqList.h" typedefstruct { SeqListVertices;//存放结点的顺序表 intedge[MaxVertices][MaxVertices];//存放边的邻接矩阵 intnumOfEdges;//边的条数 }AdjMGraph;//边的结构体定义 voidInitiate(AdjMGraph*G,intn)//初始化 { inti,j; for(i=0;i for(j=0;j { if(i==j) G->edge[i][j]=0; else G->edge[i][j]=MaxWeight; } G->numOfEdges=0;//边的条数置为0 ListInitiate(&G->Vertices);//顺序表初始化 } voidInsertVertex(AdjMGraph*G,DataTypevertex)//在图G中插入结点vertex { ListInsert(&G->Vertices,G->Vertices.size,vertex);//顺序表尾插入 } voidInsertEdge(AdjMGraph*G,intv1,intv2,intweight) //在图G中插入边 { if(v1<0||v1>G->Vertices.size||v2<0||v2>G->Vertices.size) { printf("参数v1或v2越界出错! \n"); exit (1); } G->edge[v1][v2]=weight; G->numOfEdges++; } voidDeleteEdge(AdjMGraph*G,intv1,intv2)//在图中删除边 { if(v1<0||v1>G->Vertices.size||v2<0||v2>G->Vertices.size||v1==v2) { printf("参数v1或v2越界出错! \n"); exit (1); } if(G->edge[v1][v2]==MaxWeight||v1==v2) { printf("该边不存在! \n"); exit(0); } G->edge[v1][v2]=MaxWeight; G->numOfEdges--; } voidDeleteVerten(AdjMGraph*G,intv)//删除结点v { intn=ListLength(G->Vertices),i,j; DataTypex; for(i=0;i { for(j=0;j if((i==v||j==v)&&G->edge[i][j]>0&&G->edge[i][j] G->numOfEdges--;//计算被删除边 } for(i=v;i { for(j=0;j G->edge[i][j]=G->edge[i+1][j]; } for(i=0;i { for(j=v;j G->edge[i][j]=G->edge[i][j+1]; } ListDelete(&G->Vertices,v,&x);//删除结点v } intGetFistVex(AdjMGraph*G,intv) //在图G中寻找序号为v的结点的第一个邻接结点 //如果这样的邻接结点存在,返回该邻接结点的序号;否则,返回-1 { intcol; if(v<0||v>G->Vertices.size) { printf("参数v1越界出错! \n"); exit (1); } for(col=0;col if(G->edge[v][col]>0&&G->edge[v][col] return-1; } intGetNextVex(AdjMGraph*G,intv1,intv2) //在图中寻找v1结点的邻接结点v2的下一个邻接结点 //如果这样的结点存在,返回该邻接结点的序号;否则,返回-1 //v1和v2都是相应结点的序号 { intcol; if(v1<0||v1>G->Vertices.size||v2<0||v2>G->Vertices.size) { printf("参数v1或v2越界出错! \n"); exit (1); } for(col=v2+1;col if(G->edge[v1][col]>0&&G->edge[v1][col] return-1; } //输出图G的邻接矩阵 void
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 数据结构 课程设计 说明书