数据结构与算法说明书.docx
《数据结构与算法说明书.docx》由会员分享,可在线阅读,更多相关《数据结构与算法说明书.docx(30页珍藏版)》请在冰豆网上搜索。
![数据结构与算法说明书.docx](https://file1.bdocx.com/fileroot1/2023-2/22/646c2901-6171-4b5d-83a4-da5888538c2a/646c2901-6171-4b5d-83a4-da5888538c2a1.gif)
数据结构与算法说明书
数据结构与算法课程设计
题目:
求素数问题
猴子吃桃问题
跳马问题
排序重构问题。
目录
目录2
摘要4
一.求素数问题5
1.数据结构设计5
2.算法设计5
3.调试分析6
4.测试结果6
5.源程序(带注释)6
二.构造可以使n个城市连接的最小生成树8
1.数据结构设计9
2.算法设计9
3.调试分析10
4.测试结果11
5.源程序(带注释)12
三.猴子吃桃问题19
.数据结构设计19
2.算法设计19
3.调试分析21
4.测试结果21
5.源程序(带注释)22
4.排序重构问题24
1.数据结构设计24
2.算法设计24
3、流程图如下:
25
4、调试分析25
5、测试结果25
6、源程序(带注释)26
总结30
参考文献31
致谢31
摘要
此报告是关于四个问题的设计:
求素数问题、猴子吃桃子问题、跳马问题、哈夫曼的编/译码系统。
1.求素数问题。
埃拉托色尼筛法(SieveofEratosthenes)是一种用来求所有小于N的素数的方法。
从建立一个整数2~N的表着手,寻找i˂
的整数,编程实现此算法,并讨论运算时间。
(1)
2.猴子吃桃子问题。
有一群猴子摘了一堆桃子,他们每天都吃当前桃子的一半且再多吃一个,到了第10天就只余下一个桃子。
用多种方法实现求出原来这群猴子共摘了多少个桃子。
要求:
1)采用数组数据结构实现上述求解;2)采用链式数据结构实现上述求解;3)采用递归实现上述求解。
(2)
3.跳马问题。
要求在64个国际象棋格子,任意位置放一个马,如何不重复地把格子走完。
(3)
4.排序重构问题。
令A为一个由N个已特殊排序数组成的数列:
A1,A2,…,AN,其中A1=0。
令B为N(N-1)/2个数(定义为Dij=Ai-Aj(i>j))组成的数列。
例如,A=0,1,5,8,那么D=1,3,4,5,7,8。
请完成:
a)编写程序,根据A构造D;
编写程序,构造与D相对应的某一个数列A,注意A不是唯一的。
。
1)编译的语言:
C语言
2)编译环境:
VisualC++6.0
关键词:
递归,链表,栈和队列,猴子吃桃,跳马,排序重构
C语言数据结构顺序表链表数组
一.求素数问题
埃拉托色尼筛法(SieveofEratosthenes)是一种用来求所有小于N的素数的方法。
从建立一个整数2~N的表着手,寻找i˂
的整数,编程实现此算法,并讨论运算时间。
(1)
1.数据结构设计
定义一个线性表顺序存储结构,用来求所有小于N的素数
typedefintDataType;//数据类型
typedefstruct{
DataTypedata[maxsize];定义一个一维数组
intlength;//线性表中实际元素的个数
}Seqlist;
2.算法设计
用一个循环结构判断是否为素数,如果是素数则返回1,负责返回0。
intsushu(DataType&i)
{
intm;
if(i==1)
return0;//不是素数
for(m=2;m
{
if(i%m==0)
return0;//不是素数
}
return1;//判断为素数,返回为1
}
3.调试分析
断一个数是否为素数的问题,例如数字I,求解其2-i-1求余数,若为0,则不是素数,相反为素数。
时间复杂度的分析:
算法的时间复杂度O(L.length-1)+O(m)。
4.测试结果
图1数问题截图
程序运行结果如图所示,当输入素数5时,显示出1-5之间的素数2,3,5.
5.源程序(带注释)
#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;
}
intm;intj;inti=0;intk=0;
intmain(){
SeqlistL;
L.length=maxsize;
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");
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;}
二.构造可以使n个城市连接的最小生成树
问题描述:
给定一个地区的n个城市间的距离网,用Prim算法或Kruskal算法建立最小生成树,并计算得到的最小生成树的代价。
(4)
要求:
1)城市间的距离网采用邻接矩阵表示,邻接矩阵的存储结构定义采用课本中给出的定义,若两个城市之间不存在道路,则将相应边的权值设为自己定义的无穷大值.要求在屏幕上显示得到的最小生成树中包括了哪些城市间的道路,并显示得到的最小生成树的代价。
2)表示城市间距离网的邻接矩阵(要求至少6个城市,10条边);
3)最小生成树中包括的边及其权值,并显示得到的最小生成树的代价。
1.数据结构设计
定义一个线性表顺序存储结构,用来求所有小于N的素数
typedefintDataType;//数据类型
typedefstruct{
DataTypedata[maxsize];定义一个一维数组
intlength;//线性表中实际元素的个数
}Seqlist;
2.算法设计
克鲁斯卡尔算法的基本思想是:
假设连通网=(V,{E}),则令最小生成树的初始状态为只有n顶点而无边的非连通图T=(V,{}),图中每个顶点自成一个连通分量。
在E中选择代价最小的边,若该边依附的顶点落在T中不同的连通分量上,则将此边加入到T中,否则舍去此边而选择下一条代价最小的边。
依此类推,直至T中所有顶点都在同一个连通分量上为止。
voidKruskal(graph*g){
intans=0,i,j,k=0;/*ans用来记录生成最小树的权总值*/
intindex;
intcount=0;/*记录打印边的条数*/
for(i=0;i<(g->n);i++)/*初始化数组pre[x],rank[x]*/
set(i);
for(i=0;i<(g->n);i++)
{
for(j=i+1;j<(g->n);j++)
{
p[++k].str=i;
p[k].end=j;
p[k].dis=g->adj[i][j];/*先把所有城市之间的路段看成边*/
}
}
for(i=0;i{
index=i;
for(j=i+1;j<=k;j++)
if(p[j].dis
index=j;
temp=p[index];
p[index]=p[i];
p[i]=temp;
}
for(i=0;iif(find(p[i].str)!
=find(p[i].end))
/*如果这两点连接在一起不构成一个回路,则执行下面操作*/
{
printf("\t第%d条路段为:
%d--%d,权值为%d\n",++count,p[i].str,p[i].end,p[i].dis);
/*将这条边的起点、终点打印出来*/
ans+=p[i].dis;/*说明这条路段要用*/
Union(p[i].str,p[i].end);
}
}
printf("\t遍历所有城市得到最小生成树的代价为:
%d\n\n",ans);
}
3.调试分析
程序执行从主函数main()开始,首先在运行界面上显示菜单,调用菜单函menu(),根据switch函数选择调用的函数,其中选择1,调用create()函数,用来创建城市之间距离的图,选择2,调用display()函数,用来显示最小生成树,而函数本身也存在函数的调用,在display()函数中调用Kruskal()函数,该函数式用克鲁斯卡尔算法求最小生成树,而Kruskal()函数中又调用三个函数set(),find(),Union(),它们作用是检验当一条边添加进去,是否会产生回路。
算法的时间复杂度为O(
)
4.测试结果
示例如下:
图2,示例的图图3,对应的最小生成树
运行截图:
图4邻接矩阵
图5最小生成树
5.源程序(带注释)
#include
#include
#include
#definemax20//城市间边数
#defineMAX_LNT10//城市数
#defineINF32627//两个城市间无直接路径,用大数32627表示
typedefstructnode/*构造一个结构体,两个城市可以看成起点和终点,之间的道路可以看成一个边*/
{
intstr;/*起点*/
intend;/*终点*/
intdis;/*距离*/
}node;
nodep[max],temp;/*p记录城市信息*/
typedefstruct{//邻接矩阵存储图结构
intvexs[MAX_LNT];//数组用于存储城市数
intadj[max+1][max+1];//图的邻接矩阵表示
intn,e;//n代表城市数,e代表城市间边数
}graph;
intpre[100],rank[100];/*用于判断是否构成回路*/
//intarcs[MAX_LNT][MAX_LNT];/*n表示城市个数,arcs[][]记录城市间权值*/
intmenu()/*菜单函数*/
{
intm;
printf("求最小生成树\n");
printf("________________________________\n\n");
printf("1输入城市之间的信息\n");
printf("2遍历所有城市生成最小生成树\n");
printf("3退出\n");
printf("________________________________\n\n");
printf("请输入所选功能1-3:
\n");
//system("colorE");/*改变界面颜色的*/
scanf("%d",&m);
returnm;
}
voidcreate(graph*g)/*输入城市信息*/
{
inti,j,k;
printf("输入城市数为:
");
scanf("%d",&(g->n));
printf("\n");
printf("输入个城市间边数为:
");
scanf("%d",&(g->e));
printf("输入城市的各个顶点为:
");
for(i=0;i<(g->n);i++)
scanf("%d",&(g->vexs[i]));//顶点存入数组vexs[]
printf("输入%d条边,建立邻接矩阵",(g->e));
printf("\n");
for(i=0;i<(g->n);i++)//初始化邻接矩阵
{
for(j=0;j<(g->n);j++)
{
if(i==j)
g->adj[i][j]=0;
else
g->adj[i][j]=INF;
}
}
printf("请输入具有邻接关系的两个顶点在矩阵中所在的行与列及权值:
\n");
for(k=0;k<(g->e);k++)//有g->e条边,即有g->e个权值
{
scanf("%d,%d",&i,&j);
scanf("%d",&g->adj[i][j]);
}
for(i=0;i<(g->n);i++)
for(j=0;j<(g->n);j++)
g->adj[j][i]=g->adj[i][j];
printf("图的邻接矩阵如下\n");
for(i=0;i<(g->n);i++)//输出邻接矩阵g
{
for(j=0;j<(g->n);j++)
if(g->adj[i][j]==INF)
printf("\t%3s","∞");
else
printf("\t%3d",g->adj[i][j]);
printf("\n");
}
}
/*下面三个函数作用是检验当一条边添加进去,是否会产生回路*/
voidset(intx)/*初始化*/
{
pre[x]=x;
rank[x]=0;
}
intfind(intx)/*找到这个点的祖先*/
{
if(x!
=pre[x])
pre[x]=find(pre[x]);
returnpre[x];
}
voidUnion(intx,inty)/*将这两个添加到一个集合里去*/
{
x=find(x);
y=find(y);
if(rank[x]>=rank[y])
{
pre[y]=x;
rank[x]++;
}
elsepre[y]=x;
}
voidKruskal(graph*g)
{
intans=0,i,j,k=0;/*ans用来记录生成最小树的权总值*/
intindex;
intcount=0;/*记录打印边的条数*/
for(i=0;i<(g->n);i++)/*初始化数组pre[x],rank[x]*/
set(i);
for(i=0;i<(g->n);i++)
{
for(j=i+1;j<(g->n);j++)
{
p[++k].str=i;
p[k].end=j;
p[k].dis=g->adj[i][j];/*先把所有城市之间的路段看成一个边*/
}
}
for(i=0;i{
index=i;
for(j=i+1;j<=k;j++)
if(p[j].dis
index=j;
temp=p[index];
p[index]=p[i];
p[i]=temp;
}
for(i=0;i{
if(find(p[i].str)!
=find(p[i].end))/*如果这两点连接在一起不构成一个回路,则执行下面操作*/
{
printf("\t第%d条路段为:
%d--%d,权值为%d\n",++count,p[i].str,p[i].end,p[i].dis);/*将这条边的起点、终点打印出来*/
ans+=p[i].dis;/*说明这条路段要用*/
Union(p[i].str,p[i].end);
}
}
printf("\t遍历所有城市得到最小生成树的代价为:
%d\n\n",ans);
}
voiddisplay(graph*g)/*显示生成的最小生成树*/
{
if((g->n)==0)
{
printf("这里没有城市之间的信息\n");
return;
}
printf("遍历所有城市得到最小生成树为:
\n\n\n");
Kruskal(g);
}
intmain()/*主函数*/
{
graph*g=(graph*)malloc(sizeof(graph));//这是给graph类变量*g分配一定的内存空间,分配的空间大小等于结构体graph的大小
while
(1)
{
switch(menu())
{
case1:
create(g);break;/*输入城市信息*/
case2:
display(g);break;/*显示生成的最小生成树*/
case3:
exit(0);
}
}
return0;}
三.猴子吃桃问题
有一群猴子摘了一堆桃子,他们每天都吃当前桃子的一半且再多吃一个,到了第10天就只余下一个桃子。
用多种方法实现求出原来这群猴子共摘了多少个桃子。
1) 采用数组数据结构实现上述求解
2) 采用链数据结构实现上述求解
3) 采用递归实现上述求解
.数据结构设计
1数组结构设计
把猴子吃桃的天数倒过来看,以天数座位数组的下表i,剩下桃子的个数a[i]的递推公式为a[i]=(a[i-1]+1)*2。
a[i]实际代表了倒数第i天剩下的桃子的个数。
首先建立一个以天数为下标,以剩余桃子数为元素的数组,规定此数组的通项公式为a[i]=(a[i-1]+1)*2,最后输出第一天的桃子数。
2链式存储结构
建立一个链表,根据每天桃子数与后一天桃子数的关系:
n=2*n+2,依次将每天的桃子数存入链表中,最后输出第一天的桃子数。
首先建立一个空的链表,产生一个头结点,并且将头结点的地址赋给某一参数,然后把每天的桃子数从链表的第一个结点插入链表。
最后,第一天的桃子数被最后一个插入链表,成为链表的第一个值,将其赋值给另一个参数并输出,就可以得到第一天的桃子数。
3递归算法
递归算法的设计,利用公式n=2*n+2,定义一个函数ya3,并不断调用算法ya31,求出第一天的桃子数。
2.算法设计
数组数据结构实现:
voidya1()
{
inta[11]={0,0,0,0,0,0,0,0,0,0,0};
a[10]=1;//构造数组
for(inti=10;i>1;i--)
a[i-1]=(a[i]+1)*2;//数组的通项公式
cout<<"共摘了"<}
链式存储结构算法:
voidya2()
{
intx;//链式数据结构实现;
intk=1;
ya*p;
p=newya;
p->data=1;
for(inti=10;i>1;i--)
{
x=(p->data+1)*2;
ya*t;
t=newya;
t->data=x;
t->link=p;
p=t;
}
cout<<"共摘了"<data<<"个桃子。
"<}
递归算法:
intya31(intn)//递归实现;
{
if(n==1)
return1;
b=2*(ya31(n-1)+1);
returnb;
}
voidya3()
{
intx=1;
x=ya31(10);//反复调用ya31方法实现递归算法
cout<<"共摘了"<"<}
3.调试分析
本次设过程中也遇到了一些问题,如递归调用次数出错导致结果错误,数组解决方法是数组创建时,数组下标、元素不明确。
这些问题都通过查阅资料、询问同学解决。
4.测试结果
运行结果:
图6运行截图
5.源程序(带注释)
数组数据结构实现:
voidya1()
{
inta[11]={0,0,0,0,0,0,0,0,0,0,0};
a[10]=1;//构造数组
for(inti=10;i>1;i--)
a[i-1]=(a[i]+1)*2;//数组的通项公式
cout<<"共摘了"<}
链式存储结构算法:
voidya2()
{
intx;//链式数据结构实现;
intk=1;
ya*p;
p=newya;
p->data=1;
for(inti=10;i>1;i--)
{
x=(p->data+1)*2;
ya*t;
t=newya;
t->data=x;
t->link=p;
p=t;
}
cout<<"共摘了"<data<<"个桃子。
"<}
递归算法:
intya31(intn)//递归实现;
{
if(n==1)
return1;
b=2*(ya31(n-1)+1);
returnb;
}
voidya3()
{
intx=1;
x=ya31(10);//反复调用ya31方法实现递归算法
cout<<"共摘了"<"<}
4.排序重构问题
令A为一个由N个已特殊排序数组成的数列:
A1,A2,…,AN,其中A1=0。
令B为N(N-1)/2个数(定义为Dij=Ai-Aj(i>j))组成的数列。
例如,A=0,1,5,8,那么D=1,3,4,5,7,8。
请完成:
编写程序,根据A构造D;
编写程序,构造与D相对应的某一个数列A,注意A不是唯一的。
具体要求是由题目给出的一个顺序序列按照题目给定的相关计算方法得到新的序列,然后对计算方法进行逆推得到新的顺序序列,由于计算方法我们得到的序列并不唯一
1.数据结构设计
数据结构:
结构体。
typedefstruct
{
intdata[MAX];//一维数组
intflag[MAX];//表示判断的变量
intsize;