算法与数据结构 课程设计.docx
《算法与数据结构 课程设计.docx》由会员分享,可在线阅读,更多相关《算法与数据结构 课程设计.docx(35页珍藏版)》请在冰豆网上搜索。
算法与数据结构课程设计
*******************
实践教学
*******************
兰州理工大学
计算机与通信学院
2012年春季学期
算法与数据结构课程设计
题目:
敢死队问题
专业班级:
姓名:
学号:
指导教师:
成绩:
_______________
目录
摘要1
前言2
正文3
1.采用类c语言定义相关的数据类型3
2.各模块的伪码算法6
3.函数的调用关系图10
4.调试分析11
5.测试结果11
6.源程序(带注释)13
总结22
参考文献23
致谢24
附件Ⅰ部分源程序代码25
摘要
有M个敢死队员要炸掉敌人的一碉堡,谁都不想去,排长决定用轮回数数的办法来决定哪个战士去执行任务。
如果前一个战士没完成任务,则要再派一个战士上去。
现给每个战士编一个号,大家围坐成一圈,随便从某一个战士开始计数,当数到5时,对应的战士就去执行任务,且此战士不再参加下一轮计数。
如果此战士没完成任务,再从下一个战士开始数数,被数到第5时,此战士接着去执行任务。
以此类推,直到任务完成为止。
通过该题目的设计过程,可以加深理解线性表及栈的逻辑结构、存储结构,掌握线性表及栈上基本运算的实现,进一步理解和熟练掌握课本中所学的各种数据结构,学会如何把学到的知识用于解决实际问题,培养学生的动手能力。
关键词:
敢死队;数据结构;线性表;循环队列;循环链表
算法设计:
以单循环链表为存储结构,包含三个模块:
1.主程序模块
2.构造链表并初始化
3.删除结点
前言
课程设计是综合性比较强和比较复杂的作业,通常需要比较宽的知识面,花费比较多的时间,具有比较高的能力以及要付出比较多的努力才能完成的作业。
我们充分认识到课程设计在教学过程中的重要性,通过课程设计可使我们更好的掌握和理解复杂的概念,促进理论知识学习,提高专业技能,培养思想素养和激发创新精神。
本课题运用C++语言进行开发,C++语言能够简单的进行编译一些程序,来实现对一些问题的解决。
它虽然比较简单的处理一些问题,但却有更高的效率。
经过这一个学期对《数据结构》的学习,我们都学到了不少东西,可能有些学的还不够理想,但无论如何这些知识都为我们的下一步学习打下了坚实的基础。
做这么一个课程设计,一方面是为了检查我们一个学期以来的学习成果,另一方面也是为了让我们进一步的掌握和运用它,同时也让我们认清自己的不足之处和薄弱环节,加以弥补和加强。
这次课程设计是对我们学习了C语言与C++课程的总结,同时也是对我们所学知识的运用和检验。
通过这次课设暴露出了我的诸多问题,这些问题充分体现了我在以前学习中的缺点和不足之处,使我明确了今后在学习中要克服的问题和需要加强的地方。
正文
采用类c语言定义相关的数据类型
(一)节点定义:
(1)typedefstructnode
{
intdata,DELETE;
structnode*next;
}LNode;/*定义结点类型
typedefstructKList/*定义数据结构体类型*/
{
ElemType*elem;/*存储空间基址*/
intlength;/*当前长度*/
intlistsize;/*当前分配的存储容量(以sizeof(ElemType)为单位)*/
}SqList;
typedefstruct{
intdata[QueueSize];
intfront;
intrear;
intcount;//计数器,记录队中元素总数
}CirQueue;
(2)对链表的操作函数
LNode*CREAT(intn)/*创建循环链表*/
{
LNode*s,*q,*T;
inti;
if(n!
=0)
{
T=q=(LNode*)malloc(sizeof(LNode));
q->data=1;/*生成第一个结点并使其data值为1*/
for(i=2;i<=n;i++)
{
s=(LNode*)malloc(sizeof(LNode));
q->next=s;
q->next->data=i;/*赋值*/
q=q->next;
}
q->next=T;
}
returnT;
}
intDELETE(LNode*T,intm)/*链表的删除*/
{
LNode*a;inti;
while(T->next!
=T)
{
for(i=1;iT=T->next;
a=T->next;
T->next=a->next;
free(a);
T=T->next;
}
printf("\n");
return(T->data);
}
对线性表的操作函数
typedefintElemType;
typedefstructKList/*定义数据结构体类型*/
{
ElemType*elem;/*存储空间基址*/
intlength;/*当前长度*/
intlistsize;/*当前分配的存储容量(以sizeof(ElemType)为单位)*/
}SqList;
intInitList_Sq(SqList&L)/*创建线性表函数*/
{
L.elem=(ElemType*)malloc(LIST_INIT_SIZE*sizeof(ElemType));
if(!
L.elem)
{
printf("存储分配失败");
returnERROR;}
else
{
L.length=0;/*空表长度为0*/
L.listsize=LIST_INIT_SIZE;
returnOK;/*初始存储容量*/
}
}
intListInsert_Sq(SqList&L)/*线性表再分配函数*/
{
/*SqListL;*/
int*newbase;
newbase=(ElemType*)realloc(L.elem,
(L.listsize+LISTINCCREMENT)*sizeof(ElemType));
/*为顺序表增加一个大小为存储LISTINCCREMENT个数据元素的空间*/
if(!
newbase)
{printf("存储分配失败");
returnERROR;}
else
{
L.elem=newbase;/*新基址*/
L.listsize+=LISTINCCREMENT;
/*增加存储容量*/
returnOK;
}
}
对队列的操作函数:
typedefstruct{
intdata[QueueSize];
intfront;//头指针
intrear;//尾指针
intcount;//计数器,记录队中元素总数
}CirQueue;
//置队列空
IntInitial(CirQueue*Q)
{//将顺序队列置空
Q->front=Q->rear=0;
Q->count=0;//计数器置0
}
//判队列空
intIsEmpty(CirQueue*Q)
{
returnQ->front==Q->rear;
}
//判队列满
intIsFull(CirQueue*Q)
{
returnQ->rear==QueueSize-1+Q->front;
}
//进队列
voidEnQueue(CirQueue*Q,intx)
{
if(IsFull(Q))
{
printf("队列上溢");//上溢,退出运行
exit
(1);
}
Q->count++;//队列元素个数加1
Q->data[Q->rear]=x;//新元素插入队尾
Q->rear=(Q->rear+1)%QueueSize;//循环意义下将尾指针加1
}
//出队列
intDeQueue(CirQueue*Q)
{
inttemp;
if(IsEmpty(Q))
{
printf("队列为空");//下溢,退出运行
exit
(1);
}
temp=Q->data[Q->front];
Q->count--;//队列元素个数减1
Q->front=(Q->front+1)%QueueSize;//循环意义下的头指针加1
returntemp;
}
各模块的伪码算法
算法描述:
IntInitial(CirQueue*Q)
{//将顺序队列置空
}
//判队列空
intIsEmpty(CirQueue*Q)
{
returnQ->front==Q->rear;
}
//判队列满
intIsFull(CirQueue*Q)
{
returnQ->rear==QueueSize-1+Q->front;
}
//进队列
voidEnQueue(CirQueue*Q,intx)
{
if(IsFull(Q))
{
}
}
//出队列
intDeQueue(CirQueue*Q)
{
inttemp;
if(IsEmpty(Q))
{
}
}
intmain()
{
printf("_____________________________________\n");
printf("|1.循环链表|\n");
printf("|2.线性表|\n");
printf("|3.循环队列|\n");
printf("|4.退出|\n");
printf("_____________________________________\n");
if(opt>4||opt<1)
{
}
switch(opt)
{
case1:
printf("您使用是循环链表储存结构\n\n");
if(num<1)
{
}
if(m>num||m<1)
{
}
else
{
if(z%num==0)
else
break;
case2:
printf("您使用的是线性表储存结构\n\n");
if(num<1)
{
}
InitList_Sq(L);
while(num>L.listsize)/*当顺序表当前分配的存储空间大小不足时进行再分配*/
for(i=0;iwhile(s>1)/*当所剩敢死队员总数为1时,总循环结束*/
{
for(i=0;iif(L.elem[i]!
=0)
{
if(count==5)/*报数循环*/
{
}
}
}
for(i=0;iif(L.elem[i]!
=0)
if((num-L.elem[i]+2)%num==0)
else
break;
case3:
printf("您使用的是循环队列储存结构\n\n");
CirQueues;
if(num<1)
{
}
for(start=1;start<=num;start++)//start为测试起点
{
for(i=1;i<=num;i++)
{
}
for(i=1;i{
}
while(count{
for(i=1;i<5;i++)
{
}
}
if(s.data[s.front]==1)
break;
}
break;
case4:
exit(0);
break;
}
}
函数的调用关系图
调试分析
调试中遇到的问题及对问题的解决方法
(1)本程序的运行环境是c++6.0
(2)①在设计生成循环单链表时,考虑到程序结果需要士兵的位序,故将每个结点的data值设置为他们在队列中的位置,方便返回。
②在删除单链表时,如果在报数时直接数到出列士兵则不方便链表的删除,可设置ifor(i=2;i<=M-1;i++)/*查找要删除结点的前一结点*/
{
lnode*q=newlnode;
q->num=i;
p->next=q;
p=q;
}
lnode*t=newlnode;
t->num=M;
p->next=t;
p=t;
t->next=l.cl;
③.在程序设计前,如果按原题所设,则需设队长为第一位,再分别测试从第几个开始才能符合条件。
现在改变思想,通过数学思想:
单循环链表本身是一个循环体,可先求出当从第一个出发的话,求出每隔m个出去一个最后是谁未出列,然后再设置它为链头,求出当他为队首时从第几个开始方能使其不出列。
(n-y+2)%n即可实现这功能!
本程序输入队伍人数n为任意的,最终输出记数的初始位置,首先输入一个报数上限m,当达到报数上限时,那名士兵出列执行任务,从下个人开始记数,再次循环,直到只剩一人,得到其在队伍中的位置,通过数学思想求得题目要求即队长为首的情况下需要记数初始位置。
(3)调试运行
(4)算法的时间复杂度和空间复杂度
时间复杂度为:
T(n)=O(mn);
空间复杂度为:
S(n)=O(f(n));
测试结果
进入用户主界面,选者实现结果的方法
以10个队员,死亡数字为5来运行,结果如下
选择第2项功能,运用线性表储存结构
选择第3项功能,运用循环队列来实现结果
源程序(带注释)
模块
(一)
//敢死队问题,使用单向循环链表
#include
usingnamespacestd;
typedefstructnode{
intnum;
node*next;
}lnode;//定义结点
typedefstruct{
lnode*cl;
}linklist;
voidmain()
{
intM;
inti;
intstart,count;
linklistl;
cout<<"enterthevalueofM:
";
cin>>M;
for(start=1;start<=M;start++)//start为测试起点
{
//初始化链表
lnode*p=newlnode;
l.cl=p;
l.cl->num=1;
for(i=2;i<=M-1;i++)
{
lnode*q=newlnode;
q->num=i;
p->next=q;
p=q;
}
lnode*t=newlnode;
t->num=M;
p->next=t;
p=t;
t->next=l.cl;
//找到起点
p=l.cl;
for(i=1;i{
p=p->next;
}
count=0;
while(count<=M-1)
{
for(i=1;i<5;i++)
{
t=p;
p=t->next;
}
t->next=p->next;
count++;
p=t->next;
}
if(p->num==1)
break;
}
cout<<"startfrom:
"<}
///敢死队问题,使用线性表
#defineLIST_INIT_SIZE1000
#defineLISTINCCREMENT100
#defineOK1
#defineERROR0
typedefintElemType;
typedefstructKList/*定义数据结构体类型*/
{
ElemType*elem;/*存储空间基址*/
intlength;/*当前长度*/
intlistsize;/*当前分配的存储容量(以sizeof(ElemType)为单位)*/
}SqList;
intInitList_Sq(SqList&L)/*创建线性表函数*/
{
L.elem=(ElemType*)malloc(LIST_INIT_SIZE*sizeof(ElemType));
if(!
L.elem)
{
printf("存储分配失败");
returnERROR;}
else
{
L.length=0;/*空表长度为0*/
L.listsize=LIST_INIT_SIZE;
returnOK;/*初始存储容量*/
}
}
intListInsert_Sq(SqList&L)/*线性表再分配函数*/
{
/*SqListL;*/
int*newbase;
newbase=(ElemType*)realloc(L.elem,
(L.listsize+LISTINCCREMENT)*sizeof(ElemType));
/*为顺序表增加一个大小为存储LISTINCCREMENT个数据元素的空间*/
if(!
newbase)
{printf("存储分配失败");
returnERROR;}
else
{
L.elem=newbase;/*新基址*/
L.listsize+=LISTINCCREMENT;
/*增加存储容量*/
returnOK;
}
}
////敢死队问题,使用循环队列
#include
usingnamespacestd;
#defineQueueSize100//假定预分配的队列空间最多为100个元素
//typedefintDataType;//假定队列元素的数据类型为字符
typedefstruct{
intdata[QueueSize];
intfront;//头指针
intrear;//尾指针
intcount;//计数器,记录队中元素总数
}CirQueue;
//置队列空
voidInitial(CirQueue*Q)
{//将顺序队列置空
Q->front=Q->rear=0;
Q->count=0;//计数器置0
}
//判队列空
intIsEmpty(CirQueue*Q)
{
returnQ->front==Q->rear;
}
//判队列满
intIsFull(CirQueue*Q)
{
returnQ->rear==QueueSize-1+Q->front;
}
//进队列
voidEnQueue(CirQueue*Q,intx)
{
if(IsFull(Q))
{
printf("队列上溢");//上溢,退出运行
exit
(1);
}
Q->count++;//队列元素个数加1
Q->data[Q->rear]=x;//新元素插入队尾
Q->rear=(Q->rear+1)%QueueSize;//循环意义下将尾指针加1
}
//出队列
intDeQueue(CirQueue*Q)
{
inttemp;
if(IsEmpty(Q))
{
printf("队列为空");//下溢,退出运行
exit
(1);
}
temp=Q->data[Q->front];
Q->count--;//队列元素个数减1
Q->front=(Q->front+1)%QueueSize;//循环意义下的头指针加1
returntemp;
}
主模块
intmain()
{
SqListL;
ints,i,m,count=0;/*声明变量*/
LNode*p;
intz,y;
intnum;
intopt;
abc:
printf("_____________________________________\n");
printf("|1.循环链表|\n");
printf("|2.线性表|\n");
printf("|3.循环队列|\n");
printf("|4.退出|\n");
printf("_____________________________________\n");
printf("请选择实现结果的方法:
(1~4)\n\n");
scanf("%d",&opt);
if(opt>4||opt<1)
{
printf("输入有误请重新输入\n");
gotoabc;
}
switch(opt)
{
case1:
system("cls");
printf("您使用是循环链表储存结构\n\n");
efg:
printf("请输入敢死队的人数:
\n");
scanf("%d",&num);
if(num<1)
{
printf("输入有误请重新输入\n");
gotoefg;
}
printf("请输入用来计数数字\n");
m:
scanf("%d",&m);
if(m>num||m<1)
{printf("输入有误请重新输入");
gotom;}
else
{
p=CREAT(num);