数据结构实验报告—约瑟夫问题求解

合集下载

约瑟夫问题

约瑟夫问题

一问题描述1 题目内容:约瑟夫(Joseph)问题的一种描述是:编号为1,2,..., n的n 个人按顺时针方向围坐一圈, 每人持有一个密码(正整数)。

一开始选任一个正整数作为报数上限值m,从第一个人开始按顺时针方向自1开始顺序报数,报到m时停止报数。

报m的人出列,将它的密码作为新的m值。

试设计一个程序求出出列顺序。

2 基本要求:利用单项循环链表存储结构模拟此过程,按照出列的顺序印出各人的编号。

3 测试数据:m的初值为20;n=7,7个人的密码依次为:3,1,7,2,4,8,4(正确的出列顺序应为6,1,4,7,2,3,5)。

二需求分析程序运行后,首先要求用户指定初始报数上限值,然后读取个人的密码。

输入数据:建立输入处理输入数据,输入m的初值,n ,输入每个人的密码,建立单循环链表。

输出形式:建立一个输出函数,将正确的输出序列三概要设计利用单项循环链表存储结构模拟此过程1 循环链表的抽象数据类型循环链表是单链表的一种变化形式,把单链表的最后一个节点的next指针指向第一个节点,整个链表就形成了一个环。

2 循环链表的基本操作(仅列出用在本程序的)creat(n)操作结果:构造一个长度为n的无头节点的循环链表,并返回指向最后一个节点的指针find(m,s)初始条件:循环链表存在操作结果:找到当前元素(即s)后面第m个元素print(&m,&n,&s)初始条件:循环链表存在操作结果:从s中删除约舍夫问题中下一个被删除的元素,并将此元素显示在屏幕上3 本程序包括4个模块:主程序模块;创建循环链表模块;找节点模块;删节点模块;各模块调用关系如下图所示:4 约舍夫问题的伪码算法void main( ){输入参与的人数;输入第一个密码;创建无头节点的循环链表;输出第一个出列元素;输出剩余出列元素;}四详细设计1 实现概要设计的数据类型typedef struct LNode{int data;int num;struct LNode *next;}LNode,*linklist; //无头节点的循环链表的节点类型2 每个子函数的算法linklist creat(int n){/*构造一个长度为n的无头节点的循环链表,并返回指向最后一个节点的指针*/linklist head,s; //head为头节点标记s为链表中节点int i;s=head=(linklist)malloc(sizeof(LNode)); //创建头节点for(i=1;i<n;i++) //建立循环链表{s->data=i;printf("num%d: ",i);scanf("%d",&(s->num));/*输入第i个人的密码*/while(s->num<=0){/*如果输入的s->num小于等于0,要求重新输入*/ printf("请重新输入\nnum%d: ",i);scanf("%d",&s->num);}s->next=(linklist)malloc(sizeof(LNode)); //开辟下一个节点s=s->next;}s->data=i;printf("num%d: ",i);scanf("%d",&(s->num));s->next=head;return(s);}linklist find(int m,linklist s) //找到当前元素后面第m个元素{int i;for(i=0;i<m-1;i++)s=s->next;return(s); //返回找到元素的指针}void print(into &mint &n,linklist &s){linklist p;s=find(m,s); //找到待删除的元素printf("%d ",s->next->data);/*输出找到的元素*/m=s->next->num;/*将此元素从链表中删除,并释放此节点*/ p=s->next;s->next=s->next->next;free(p);--n; //约舍夫环中节点数少一}3 主程序算法void main( ){/*解决约舍夫问题的主函数*/int n,m; //n为约舍夫环内初始人数m为初始密码printf("type in n :");scanf("%d",&n);/*输入n*/while(n<=0){/*如果输入的n小于等于0,要求重新输入*/printf("please type n in again \ntype in n :");scanf("%d",&n);}printf("type in m :");scanf("%d",&m);/*输入m*/while(m<0){/*如果输入的m小于0,要求重新输入*/printf("please type m in again \ntype in m :");scanf("%d",&m);}linklist s;s=creat(n);/*创建无头节点的循环链表,返回指向最后一个元素的指针*/printf("the sequence is ");print(m,n,s);//输出第一个出列的元素while(n){print(m,n,s);//输出剩余出列的元素}printf("\n");}4 函数调用关系图五调试分析调试过程中出现过如下问题:1 开始编程序时没考虑输入错误的问题,导致输入错误后程序出错2 编程序时删除节点子程序结束条件出错3 对开辟的节点用完后没有释放六使用说明程序运行后按提示输入n和m的值,在输入约舍夫环中每个人的密码,运行即可得到出列顺序七测试结果进入程序后要求输入n的值然后输入m的值再输入每个人的密码最后得到出列顺序八附录(源程序)这里附上两种源程序,本质上相同,只是第一个程序按老师要求写为很多子函数形式,第二个是我已开始编的,一个大函数。

数据结构实验报告

数据结构实验报告

姓名:学号:班级:2010年12月15日实验一线性表的应用【实验目的】1、熟练掌握线性表的基本操作在顺序存储和链式存储上的实现。

、;2、以线性表的各种操作(建立、插入、删除、遍历等)的实现为重点;3、掌握线性表的动态分配顺序存储结构的定义和基本操作的实现;4、通过本章实验帮助学生加深对C语言的使用(特别是函数的参数调用、指针类型的应用和链表的建立等各种基本操作)。

【实验内容】约瑟夫问题的实现:n只猴子要选猴王,所有的猴子按1,2,…,n编号围坐一圈,从第一号开始按1,2…,m报数,凡报到m号的猴子退出圈外,如此次循环报数,知道圈内剩下一只猴子时,这个猴子就是猴王。

编写一个程序实现上述过程,n和m由键盘输入。

【实验要求】1、要求用顺序表和链表分别实现约瑟夫问题。

2、独立完成,严禁抄袭。

3、上的实验报告有如下部分组成:①实验名称②实验目的③实验内容:问题描述:数据描述:算法描述:程序清单:测试数据算法:#include <stdio.h>#include <stdlib.h>typedef struct LPeople{int num;struct LPeople *next;}peo;void Joseph(int n,int m) //用循环链表实现{int i,j;peo *p,*q,*head;head=p=q=(peo *)malloc(sizeof(peo));p->num=0;p->next=head;for(i=1;i<n;i++){p=(peo *)malloc(sizeof(peo));p->num=i;q->next=p;p->next=head;}q=p;p=p->next;i=0;j=1;while(i<n){if(j%m==0){q->next=p->next;p=q->next;printf("%4d",j%n);i++;}else{q=p;p=p->next;}j++;}printf("\n");}void main(){int n,m; /*人的个数*/printf("Please Enter n amd m(n>m):\n");scanf("%d%d",&n,&m);Joseph(n,m);}实验二树和图的应用【实验目的】1.熟练掌握数的基本概念、二叉树的基本操作及在链式存储结构上的实现。

约瑟夫环问题实验报告

约瑟夫环问题实验报告

约瑟夫问题实验报告背景约瑟夫问题(Josephus Problem)据说著名犹太历史学家Josephus有过以下的故事:在罗马人占领乔塔帕特后,39 个犹太人与Josephus及他的朋友躲到一个洞中,39个犹太人决定宁愿死也不要被敌人到,于是决定了一个自杀方式,41个人排成一个圆圈,由第1个人开始报数,每报数到第3人该人就必须自杀,然后再由下一个重新报数,直到所有人都自杀身亡为止。

然而Josephus 和他的朋友并不想遵从,Josephus要他的朋友先假装遵从,他将朋友与自己安排在第16个与第31个位置,于是逃过了这场死亡游戏。

原题:用户输入M,N值,N个人围成一个环,从0号人开始数,数到M,那个人就退出游戏,直到最后一个人求最后一个剩下的人是几号?问题描述设编号为1-n的n(n>0)个人按顺时针方向围成一圈.首先第1个人从1开始顺时针报数.报m的人(m 为正整数).令其出列。

然后再从他的下一个人开始,重新从1顺时针报数,报m的人,再令其出列。

如此下去,直到圈中所有人出列为止。

求出列编号序列。

一.需求分析:(1)基本要求需要基于线性表的基本操作来实现约瑟夫问题需要利用循环链表来实现线性表(2)输入输出格式输入格式:n,m(n,m均为正整数,)输出格式1:在字符界面上输出这n个数的输出序列(3)测试用例(举例)输入:8,4输出:4 8 5 2 1 3 7 6二.概要设计(1)抽象数据类型:数据对象:n个整数数据关系:除第一个和最后一个n外,其余每个整数都有两个元素与该元素相邻。

基本操作:查找,初始化,删除,创建链表循环链表的存储结构:(2).算法的基本思想循环链表基本思想:先把n个整数存入循环链表中,设置第m个数出列,从第一个开始查找,找到第m个时,输出第m个数,并删掉第m个节点,再从下一个数开始查找,重复上一步骤,直到链表为空,结束。

(3).程序的流程程序由三个模块组成:1.输入模块:完成两个正整数的输入,存入变量n和m中2.处理模块:找到第m个数3.输出模块:按找到的顺序把n个数输出到屏幕上三.详细设计首先,设计实现约瑟夫环问题的存储结构。

实验一:约瑟夫问题

实验一:约瑟夫问题

实验一:约瑟夫问题问题描述:用数组和链表存储方式实现约瑟夫问题。

约瑟夫问题:n个人围成一个圆圈,首先第1个人从1开始一个人一个人顺时针报数,报到第m个人,令其出列。

然后再从下一个人开始,从1顺时针报数,报到第m个人,再令其出列,…,如此下去,直到圆圈中只剩一个人为止。

此人即为优胜者。

基本要求:用顺序存储和链式存储方式实现。

试验报告内容:1.问题描述:设有n个人围坐在圆桌周围,现从某个位置m(1≤m≤n)上的人开始报数,报数到k 的人就站出来。

下一个人,即原来的第k+1个位置上的人,又从1开始报数,再报数到k的人站出来。

依此重复下去,直到全部的人都站出来为止。

2. 算法描述:可以先建一个单向循环链表;而整个“约瑟夫环”问题的过程,最终是把这个链表删空为止。

但在删时不能顺着删,而是按该问题的方案来删。

3.源程序#include <stdio.h>#include <stdlib.h>#define MAX_NODE_NUM 100#define TRUE 1U#define FALSE 0Utypedef struct NodeType{int id; /* 编号 */int cipher; /* 密码 */struct NodeType *next;} NodeType;/* 创建单向循环链表 */static void CreaList(NodeType **, const int);/* 运行 "约瑟夫环 "问题 */static void StatGame(NodeType **, int);/* 打印循环链表 */static void PrntList(const NodeType *);/* 得到一个结点 */static NodeType *GetNode(const int, const int);/* 测试链表是否为空, 空为TRUE,非空为FALSE */static unsigned EmptyList(const NodeType *);int main(void){int n, m;NodeType *pHead = NULL;while (1){printf( "请输入人数n(最多%d个): ", MAX_NODE_NUM); scanf( "%d ", &n);printf( "和初始密码m: ");scanf( "%d ", &m);if (n > MAX_NODE_NUM){printf( "人数太多,请重新输入!\n ");continue;}elsebreak;}CreaList(&pHead, n);printf( "\n------------ 循环链表原始打印 -------------\n "); PrntList(pHead);printf( "\n-------------- 出队情况打印 ---------------\n "); StatGame(&pHead, m);printf( "\n\ "约瑟夫环\ "问题完成!\n ");return 0;}static void CreaList(NodeType **ppHead, const int n){int i, iCipher;NodeType *pNew, *pCur;for (i = 1; i <= n; i++){printf( "输入第%d个人的密码: ", i);scanf( "%d ", &iCipher);pNew = GetNode(i, iCipher);if (*ppHead == NULL){*ppHead = pCur = pNew;pCur-> next = *ppHead;}else{pNew-> next = pCur-> next;pCur-> next = pNew;pCur = pNew;}}printf( "完成单向循环链表的创建!\n ");}static void StatGame(NodeType **ppHead, int iCipher){int iCounter, iFlag = 1;NodeType *pPrv, *pCur, *pDel;pPrv = pCur = *ppHead;/* 将pPrv初始为指向尾结点,为删除作好准备 */while (pPrv-> next != *ppHead)pPrv = pPrv-> next;while (iFlag) /* 开始搞了! */{/* 这里是记数,无非是移动iCipher-1趟指针! */for (iCounter = 1; iCounter < iCipher; iCounter++) {pPrv = pCur;pCur = pCur-> next;}if (pPrv == pCur) /* 是否为最后一个结点了 */iFlag = 0;pDel = pCur; /* 删除pCur指向的结点,即有人出列 */pPrv-> next = pCur-> next;pCur = pCur-> next;iCipher = pDel-> cipher;printf( "第%d个人出列, 密码: %d\n ",pDel-> id, /* 这个编号标识出列的顺序 */pDel-> cipher);free(pDel);}*ppHead = NULL; /* 没人了!为了安全就给个空值 */}static void PrntList(const NodeType *pHead){const NodeType *pCur = pHead;if (EmptyList(pHead))return;do{printf( "第%d个人, 密码: %d\n ", pCur-> id,pCur-> cipher); pCur = pCur-> next;} while (pCur != pHead);}static NodeType *GetNode(const int iId, const int iCipher){NodeType *pNew;pNew = (NodeType *)malloc(sizeof(NodeType));if (!pNew){printf( "Error, the memory is not enough!\n ");exit(-1);}pNew-> id = iId;pNew-> cipher = iCipher;pNew-> next = NULL;return pNew;}static unsigned EmptyList(const NodeType *pHead){if (!pHead){printf( "The list is empty!\n ");return TRUE;}return FALSE;}4.实验测试数据(要求有多组):第一组测试结果人数n为7, 初始密码m为20第1个人, 密码: 3第2个人, 密码: 1第3个人, 密码: 7第4个人, 密码: 2第5个人, 密码: 4第6个人, 密码: 8第7个人, 密码: 4-------------- 出队情况打印 ---------------第6个人出列, 密码: 8第1个人出列, 密码: 3第4个人出列, 密码: 2第7个人出列, 密码: 4第2个人出列, 密码: 1第3个人出列, 密码: 7第5个人出列, 密码: 4第二组测试结果人数n为8, 初始密码m为15第1个人, 密码: 5第2个人, 密码: 4第3个人, 密码: 3第4个人, 密码: 2第5个人, 密码: 9第6个人, 密码: 1第7个人, 密码: 7第8个人, 密码: 8-------------- 出队情况打印 ---------------第7个人出列, 密码: 7第6个人出列, 密码: 1第8个人出列, 密码: 8第3个人出列, 密码: 3第1个人出列, 密码: 5第4个人出列, 密码: 2第2个人出列, 密码: 4第5个人出列, 密码: 95.总结:1. 通过本次上机实践,对链表存储结构有了更深的理解和把握.2. 通过本次上机实践,应用链表的知识解决和分析问题的能力有了新的提高.3. 通过上机实践,掌握了用高级语言实现算法的基本步骤和方法.(最前面加班级、学号、姓名)。

数据结构实验一 约瑟夫环问题实验报告电子版

数据结构实验一  约瑟夫环问题实验报告电子版
pri = head ;
for(i = 1;i<length;i++){
tmp = (Node *)malloc(sizeof(Node));
tmp->number = num[i];
tmp->pass = pas[i];
pri->next = tmp;
pri = tmp;
pri->next = head;
for(i=0;i<time;i++){ //找到要删除的结点
tmp = tmp->next;
}
printf("%d ",tmp->number);
timeห้องสมุดไป่ตู้= tmp->pass - 1;
deleteFromList(&head,tmp);//删除结点
tmp = tmp->next;//从下一个结点又开始计算
initList(head);
createFromTail(head,num,pas,sizeof(num)/sizeof(num[0]));
p = head;
printf("\n约瑟夫计数前,每个数和他的密码:\n");
for(i = 0;i<sizeof(num)/sizeof(num[0]);i++){
}
}
// 从链表中删除
void deleteFromList(List *head,Node *tmp)
{
Node *tmp1;
Node *tmp2;
tmp1 = *head;
tmp2 = tmp1;
//如果链表剩了一个元素

实验一约瑟夫问题实验报告

实验一约瑟夫问题实验报告

北京邮电大学电信工程学院数据结构实验报告实验名称:实验一——约瑟夫问题学生姓名: ***班级: 20132111**班内序号: **学号: 201321****日期: 2014年1月4日1.实验要求实验题目:利用循环链表实现约瑟夫问题的求解。

约瑟夫问题如下:已知n个人(n>=1)围坐一圆桌周围,从1开始顺序编号。

从序号为1的人开始报数,顺时针数到m的那个人出列;他的下一个人又从1开始报数,数到m的那个人又出列;依此规则重复下去,直到所有人全部出列。

请问最后一个出列的人的编号。

实验目的:熟悉C++语言的基本编程方法,掌握集成编译环境的调试方法学习指针、模板类、异常处理的使用掌握线性表的操作的实现方法学习使用线性表解决实际问题的能力2. 程序分析2.1 存储结构采用单循环链表实现约瑟夫问题的求解单循环链表示意图2.2关键算法分析1、关键算法首先通过尾插法建立单循环链表,若只有一个人,即只删除该人即可,若多于一人,—则每查到m个人时删除该节点,并将循环链表连接好,共循环n-1次,每次删除均返回被删数值。

2、代码详细分析:1).指针结构、类的声明struct Node //创立节点{int number;Node *next;};class Joseph //建立Joseph类{private:int n;int m;Node *front ; //front头指针public:Joseph(int nn, int mm); //构造函数~Joseph(); //析构函数void Delete(); //删除函数};2).单循环链表的建立Joseph::Joseph(int nn, int mm) //构造函数,建立循环链表{n=nn;m=mm;Node *p,*rear; //建立两个指针.尾插法,p2始终指向为节点for(int i=1; i<=n; i++){p=new Node;p->number=i;if(i==1) //建立空链表{front=p;rear=p;}else{rear->next=p;rear=p;}}rear->next=front; //尾指向头,循环完成}算法:—①设两个指针p,rear, rear为尾节点,p为新增加的节点②若是空链表,则front=p; rear=p;③否则用尾插法,即p 在rear的后面,将p给rear;rear->next=p; rear=p;④头结点赋给rear的指针域,完成循环循环次数为n, 时间复杂度为O(n)3). 输入值异常的情况cout<<"请输入环内总人数n:";cin>>n;if (n<1) //考虑n输入错误的情况{cout<<"n值输入错误"<<endl;}cout<<"请输入m值:";cin>>m;if (m<1) //考虑m输入异常的情况{cout<<"m值输入错误"<<endl;}4).寻找一定间隔的人,并将其删除void Joseph::Delete() //删除人员的函数{Node *p1,*p2,*p;int count; //用来计数p1=front; //头结点给p1if(m==1)cout<<"最后一个人的编号为"<<n<<endl;else{cout<<"每次被删除的人为"<<endl;for(int i=1; i<=n-1; i++) //共删除n-1个人,循环n-1次{count=1;while(count<m){p2=p1; //p2始终为编号为1的那个人p1=p1->next; //p1向后移count++;}cout<<p1->number<<"\t"; //输出被删除的编号p=p1;p2->next=p1->next;p1=p1->next; //p1后移,防止删除后指针悬挂delete p;—}cout<<endl;cout<<"最后一个人的编号为"<<p1->number<<endl;front=p1;} }…………③图1 删除结点示意图算法⑤设p1、p2均指向第一个节点;⑥查找第m个节点,p1=p1—>next; p2始终指向第一个节点⑦摘链,将p指向待删除的p1,即将p1元素从链表中摘除:⑧输出p1的数值⑨释放p元素:delete p;循环次数为m(n-1), 时间复杂度为O(n)5)析构函数Joseph::~Joseph() //析构函数{delete front;front=NULL;}6)主函数void main(){int n,m;cout<<"请输入总人数n=";cin>>n;cout<<"请输入间隔m=";cin>>m;Joseph joseph(n,m);joseph.Delete();}3. 程序运行结果测试主函数流程:开始等待用户输入输入值是否有效是查找删除节点循环次数是否大于n-1次是输出最后一个数值结束流程图示意图1、测试条件:n数量级无限制2、测试结论4. 总结由于是第一次做数据结构的实验,而上学期的C++也因长时间没有碰过而稍显手生,在码程序的过程中遇到了很多问题,但通过翻看教材已基本解决。

数据结构与算法(Python版):用队列(Queue)处理约瑟夫问题

数据结构与算法(Python版):用队列(Queue)处理约瑟夫问题

数据结构与算法(Python版):⽤队列(Queue)处理约瑟夫问题在古罗马时期,犹太⼈背叛了罗马⼈,落到困境,约瑟夫和同⾏的⼀共39个犹太⼈只能够⾃杀殉国,但是犹太教义规定不能⾃杀,因此只能够让别⼈将⾃⼰杀害。

他们所有39个⼈坐成⼀圈,报数1—7,报到7则由⾝旁的⼈将⾃⼰杀死。

结果约瑟夫灵机⼀动,给⾃⼰安排了⼀个位置,最后活了下来,那么约瑟夫给⾃⼰安排的是哪⼀个位置呢?在这个题⽬当中,我们如果使⽤队列,不仅可以处理任意⼈数坐成⼀圈,还可以将报数的值任意修改,最后都可以找到那⼀个不被杀死的⼈的位置。

我们可以将所有⼈都放进⼀个⼤的队列⾥,每报⼀次数字,那么就把队列头部的⼈放到队列的尾部,直到报数报到⼀组数字的最后⼀个,⽐如1——7当中的7。

这个时候就将队列头的这个⼈删除(也就是杀死),不断执⾏这个过程,直到整个队列当中的⼈数只有⼀个,则跳出循环返回最后活着的那个⼈的名字。

⾸先定义队列(Queue)类的结构:class Queue():def__init__(self):# 初始化⼀个空的列表self.__list=[]# 往队列⾥插⼊元素def enqueue(self,item):self.__list.append(item)# 弹出队列⾥的元素def dequeue(self):return self.__list.pop(0)# 弹出队列⾥最先进⼊的元素# 判断队列是否为空def is_empty(self):return self.__list == []# 计算队列的⼤⼩def size(self):return len(self.__list)使⽤队列类来初始化⼀个对象,sim_queue,然后编写刚才我们分析之后的程序:def hot_potato(namelist,num):sim_queue = Queue()for name in namelist:sim_queue.enqueue(name) # 把拿到的名字全部都放到队列⾥while sim_queue.size() > 1:for i in range(num):sim_queue.enqueue(sim_queue.dequeue())# 每执⾏完⼀次,就将队列的头拿出来弹出,相当于⼟⾖传递给这个⼈,然后这个⼈就死了last_person=sim_queue.dequeue()return last_personprint("开始执⾏约瑟夫问题")print(hot_potato(["bob","NAni","Ao li Gei!","HeHe","Mike","Suvennia"],4))输出:开始执⾏约瑟夫问题Ao li Gei!得解,因此Ao li Gei!这个⼈不会被杀死。

数据结构约瑟夫环问题

数据结构约瑟夫环问题

数据结构实验报告题目:约瑟夫环问题一.设计内容[问题描述]约瑟夫环问题的一种描述是:编号为1, 2, 3,…,n的n个人按顺时针方向围坐一圈,每人手持一个密码(正整数)。

一开始任选一个整数作为报数上限值,从第一人开始顺时针自 1 开始顺序报数,报到m 时停止报数。

报m 的人出列, 将它的密码作为新的m 值,从他在顺时针方向上的下一个人开始重新从 1 报数, 如此下去直到所有人全部出列为止。

试设计程序实现之。

[基本要求] 利用循环链表存储结构模拟此过程,按照出列的顺序打印各人的编号。

[ 实验提示] 程序运行后首先要求用户指定初始报数上限值。

然后读取各人的密码。

设n<=30 。

程序执行后,要求用户在计算机终端上显示“提示信息”后,用键盘输入“提示信息”中规定的命令,以“回车符”为结束标志。

相应的输入数据和运算结果显示在其后。

二、设计目的1. 达到熟练掌握C++ 语言的基本知识和技能;2. 能够利用所学的基本知识和技能,解决简单的面向对象程序设计问题。

3. 把课本上的知识应用到实际生活中,达到学以致用的目的。

三、系统分析与设计(确定程序功能模块)1、为实现上述程序的功能,应以有序链表表示集合。

基本操作:InitList(&L)操作结果:构造一个空的有序表L。

DestroyList(&L)初始条件:有序表L 已存在。

操作结果:销毁有序表L。

ListEmpty(L)初始条件:有序表L 已存在。

操作结果:若L为空表,则返回TRUE,否则返回FALSE。

ListLength(L)初始条件:有序表L 已存在。

操作结果:返回L 中数据元素个数。

GetElem(L,i)初始条件:有序表L已存在,并且K i< ListLength(L)。

操作结果:返回L 中第i 个数据元素。

LocatePos(L,e)初始条件:有序表L已存在,e和有序表中元素同类型的值。

操作结果:若L中存在和e相同的元素,则返回位置;否则返回0。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

《计算机软件技术基础》实验报告 I —数据结构实验一、约瑟夫斯问题求解一、问题描述1.实验题目:编号 1,2,....,n的n个人顺时针围坐一圈,每人持有一个密码(正整数)。

开始选择一个正整数作为报数上限m,从第一个人开始顺时针自 1 报数,报到m的人出列,将他的密码作为新的m值,从他在顺时针方向下一个人开始重新从 1 报数,直至所有人全部出列。

2. 基本要求:利用单向循环链表存储结构模拟此过程,按照出列的顺序印出个人的编号。

3. 测试数据: n=7,7 个人的密码依次为:3,1,7,2,4,8,4.m初值为6(正确的出列顺序应为 6,1,4,77,2,3)。

二、需求分析1. 本程序所能达到的基本可能:该程序基于循环链表来解决约瑟夫问题。

用循环链表来模拟n 个人围坐一圈,用链表中的每一个结点代表一个人和他所代表的密码。

在输入初始密码后m,对该链表进行遍历,直到第 m个结点,令该结点的密码值作为新的密码值,后删除该结点。

重复上述过程,直至所有的结点被释放空间出列。

2. 输入输出形式及输入值范围:程序运行后提示用户输入总人数。

输入人数 n 后,程序显示提示信息,提示用户输入第i个人的密码,在输入达到预定次数后自动跳出该循环。

程序显示提示信息,提示用户输入初始密码,密码须为正整数且不大于总人数。

3.输出形式提示用户输入初始密码,程序执行结束后会输出相应的出列结点的顺序,亦即其编号。

用户输入完毕后,程序自动运行输出运行结果。

4.测试数据要求:测试数据 n=7,7 个人的密码依次为:3, 1, 7, 2, 4, 8, 4。

m初值为 6(正确的出列顺序应为6, 1, 4,7, 2, 3, 5)。

三、概要设计为了实现上述功能,应用循环链表来模拟该过程,用结构体来存放其相应的编号和密码信息,因此需要循环链表结构体这个抽象数据类型。

1.循环链表结构体抽象数据类型定义:ADT Node{数据对象: D={ai,bi,ci|ai∈ int,bi ∈ int,ci∈(Node*),i=1,2...,n,n ≥0}:数据关系: R=?基本操作:CreatList(int n)// Order(int m,node *l)}ADT node;构建循环单链表;// 输出函数,输出出列顺序并删除链表中的结点;2.ADT 的 C 语言形式说明:typedef struct Node{int num;//结点的数据域,存放编号;int word; //结点的数据域,存放密码;struct Node *next; //结点的指针域,存放指向下一结点的指针;}Node;Node *CreatList( )// 建立循环单项链表;void Order(Node *h) //输出出列顺序并删除结点;3.主程序流程及其模块调用关系:1) . 主程序流程:先提示用户输入相关数据:总人数,运行循环链表结构体模块,输入每个人持有的密码值,创建出新链表,运行输出函数模块,再输入初始密码m值,输出出列序列。

(创建循环单链表模块:实现链表的抽象数据类型删除链表结点输出序列模块:实现输出出列顺序)2) . 模块调用关系:主函数模块创建循环链表结体模块构删除链表结点输出序列模块四、详细设计1.元素类型、结点类型和结点指针类型:typedef struct Node//定义一个结构体,包含了每个人的序号和密码{int word;int num;struct Node *next;}Node;2、创建单向循环链表类型:Node *CreatList()//尾插法创建一个单向循环链表{Node *p,*s;Node *h;//定义头指针h=(Node*)malloc(sizeof(Node));//申请动态存储空间p=h;h->next=NULL;//初始化链表printf("第 1 个人的密码是:");scanf("%d",&h->word);h->num=1;//给头指针赋值for(i=0;i<n-1;i++){s=(Node*)malloc(sizeof(Node));if(h->next==NULL) h->next=s;else p->next=s;p=s;printf("第 %d个人的密码是:",i+2);scanf("%d",&s->word);s->num=i+2;}p->next=h;return h;}3.删除链表结点输出函数模块:void Order(Node *h)//输出结果{Node *p;p=h;Node *d;while(p->next!=p){if(m<2){p=p->next;}else{for(i=1;i<m-1;i++) //查找第m个结点{p=p->next;}}d=p->next;m=d->word;printf("%d--",d->num);p->next=d->next; //删除结点p=p->next;free(d);}printf("%d\n",p->num);}4. 主函数:void main(){printf("试验名称:约瑟夫斯问题求解\n");printf("学号: \n");printf("姓名: xx\n");printf("=========================================================\n");time_t rawtime1;struct tm * timeinfo1;time (&rawtime1);timeinfo1 = localtime (&rawtime1); //时间函数;printf ("程序运行开始, 当前日期和时间: %s", asctime(timeinfo1));printf("请输入总人数:");scanf("%d",&n);h=CreatList();printf("请输入初始密码:");scanf("%d",&m);if(m>n){printf("初始密码不得大于总人数,请重新输入。

");scanf("%d",&m);Order(h);}else{Order(h);}time_t rawtime2;struct tm * timeinfo2;time (&rawtime2);timeinfo2 = localtime (&rawtime2);printf ("程序运行结束,当前日期和时间: %s", asctime(timeinfo2));while(1);}5.函数调用关系:主函数调用Node *CreatList()创建循环单向链表以及调用void Order(Node *h)进行删除结点及输出序列功能。

输出出列序列输出以后,函数调用结束。

五、调试分析1. 程序中将每个人的编号以及密码信息放在链表节点中的数据域,使密码和序号一一对应。

主函数中,只需要调用链表的操作来实现循环单向链表的创建以及删除结点和输出操作。

2.算法的时空分析:由于链表采用的都是单向循环链表,而链表中按结点访问的时间性能O( n), n 是链表中结点的个数。

所以,CreatList()以及Order(Node*h)算法的时间复杂度都是O( n)。

输入数据后界面:八、遇到的问题和解决方法:1. 起初程序编写好后显示0 error,但不能正常运行,显示如图出现随机数是因为头指针的数据域没有赋值。

增加了对头指针数据域赋值语句后随机数消失。

3.在调试的开始发现输出顺序有错误,经调试发现是因为查找第m个结点时所用的for循环是从i=1 到 i<m-1 的,但第二个人密码为1,没有考虑m<2的情况,于是输出出错。

改正方式是增加一个m<2的特殊情况。

经运行,输出成功。

九、实验收获和感想:约瑟夫问题是我们学习了软件工程原理与应用这门课后第一次上机编写程序,在以前接触c语言的时候,我们是没有学过链表的,因此,以前也没有编写过循环链表的程序。

本学期的软件工程原理与应用开课后,我才真正深入学习和理解了链表结构,通过此次编程对所学知识有了具体的运用,使我对链表结构有了更清晰的了解,从茫然到能正确运用,感觉收获非常大。

约瑟夫问题虽说是链表问题中相对来说最简单的一个问题,但我刚开始时却是充满了茫然,编出来的程序处处报错。

起初,并没有真正理解建立链表的算法,我单纯仿着课本上的代码照搬上去,不会正确的运用,结果自然是大量的错误。

于是我放下急于求成的心态,认真看书,认真查资料,终于成功地写出了这个约瑟夫问题的程序。

当它最终0 error 通过且运行正常时,我的心中充满了激动和满足感,看着自己的作品,很有成就感。

编写完整的程序最考验人的耐心和细心,每一个微不足道的小错误都会导致很长时间的排错。

这次的计算机实践使我在运用中理解了循环链表这部分的知识,为后面的学习和接下来的计算机实践打好了基础,奠定了基石。

十、附录源程序文件清单:#include<stdio.h>#include<malloc.h>#include <time.h>#define NULL 0typedef struct Node// 定义一个结构体,包含了每个人的序号和密码{int word;int num;struct Node *next;}Node;int i,n,m;Node *h;Node *CreatList()// 尾插法创建一个单向循环链表{Node *p,*s;Node *h;// 定义头指针h=(Node*)malloc(sizeof(Node));// 申请动态存储空间p=h;h->next=NULL;// 初始化链表printf(" 第 1 个人的密码是:");scanf("%d",&h->word);h->num=1;// 给头指针赋值for(i=0;i<n-1;i++){s=(Node*)malloc(sizeof(Node));if(h->next==NULL)h->next=s;else p->next=s;p=s;printf(" 第 %d 个人的密码是:",i+2);scanf("%d",&s->word);s->num=i+2;}p->next=h;return h;}void Order(Node *h)// 输出结果{Node *p;p=h;Node *d;while(p->next!=p){if(m<2){p=p->next;}else{for(i=1;i<m-1;i++)// 查找第 m 个结点{p=p->next;}}m=d->word;printf("%d--",d->num);p->next=d->next;// 删除结点p=p->next;free(d);}printf("%d\n",p->num);}void main(){printf(" 试验名称:约瑟夫斯问题求解\n");printf(" 学号: \n");printf(" 姓名: xx\n");printf("=========================================================\n");time_t rawtime1;struct tm * timeinfo1;time (&rawtime1);timeinfo1 = localtime (&rawtime1);// 时间函数;printf (" 程序运行开始,当前日期和时间 : %s", asctime(timeinfo1));printf(" 请输入总人数: ");scanf("%d",&n);h=CreatList();printf(" 请输入初始密码:");scanf("%d",&m);if(m>n){printf(" 初始密码不得大于总人数,请重新输入。

相关文档
最新文档