实验一 约瑟夫环问题

合集下载

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

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

题目二约瑟夫环问题设编号为1,2,3,……,n 的n(n>0)个人按顺时针方向围坐一圈,每个人持有一个正整数密码。

开始时任选一个正整数做为报数上限m ,从第一个人开始顺时针方向自1起顺序报数,起顺序报数,报到报到m 时停止报数,时停止报数,报报m 的人出列,的人出列,将他的密码作为将他的密码作为新的m 值,从他的下一个人开始重新从1报数。

报数。

如此下去,如此下去,如此下去,直到所有人全部出列直到所有人全部出列为止。

令n 最大值取30。

要求设计一个程序模拟此过程,求出出列编号序列。

struct node //结点结构{ int number; /* 人的序号人的序号*/ int cipher; /* 密码密码*/ struct node *next; /* 指向下一个节点的指针*/ }; 一、循环链表的结点类型定义/* 单链表的结点类型 */typedefstruct node{int number;int cipher;struct node *next;}list, *linklist;二、循环链表的初始化/* 函数功能:初始化n 个元素的循环链表参数;链表(linklist L),元素个数(int n )通过后插法对无头结点的链表初始化。

*/voidinit(linklist&L,int n){int key, i;cout<<"输入第1个人的密码为:";//输入第一个节点的密码。

cin>>key;L= new list;L->number = 1;L->cipher = key;L->next = L;for(i = 2; i<= n; i ++)//输入2—n 的节点密码。

{linklist p = new list;cout<<"输入第"<<i<<"个人的密码为:";cin>>key;p->cipher = key;p->number = i;p->next = L->next; //使用后插法插入。

约瑟夫环报数实验报告

约瑟夫环报数实验报告

一、实验目的1. 理解并掌握约瑟夫环问题的基本概念和解决方法。

2. 熟悉链表数据结构及其操作,提高编程能力。

3. 通过实验加深对数据结构和算法的理解,提高解决实际问题的能力。

二、实验原理约瑟夫环问题是一个经典的数学问题,描述了N个人围成一圈,从某个人开始报数,报到M的人出列,然后从下一个人开始重新报数,如此循环,直到所有人都出列为止。

本实验通过实现单向循环链表来模拟这个过程。

三、实验内容1. 单向循环链表实现:- 定义单向循环链表的节点结构体,包含数据域和指针域。

- 实现创建单向循环链表的函数,从键盘输入N和M,生成包含N个节点的单向循环链表。

- 实现遍历单向循环链表的函数,用于输出链表中的节点信息。

2. 约瑟夫环报数:- 实现报数函数,从链表的第一个人开始报数,报到M的人出列。

- 实现删除节点的函数,将出列的人从链表中删除。

- 实现重新开始报数的函数,从下一个人开始重新报数。

3. 输出结果:- 实现输出出列顺序的函数,将出列的人的编号按顺序输出。

四、实验步骤1. 定义单向循环链表的节点结构体:```ctypedef struct Node {int data; // 数据域struct Node next; // 指针域} Node;```2. 实现创建单向循环链表的函数:```cNode createList(int n) {Node head = NULL;Node tail = NULL;Node tmp = NULL;for (int i = 1; i <= n; i++) {tmp = (Node)malloc(sizeof(Node)); tmp->data = i;tmp->next = NULL;if (head == NULL) {head = tmp;tail = tmp;} else {tail->next = tmp;tail = tmp;}}tail->next = head; // 形成循环链表return tail; // 返回尾节点}```3. 实现遍历单向循环链表的函数:```cvoid printList(Node tail) {Node p = tail->next; // 从头节点开始遍历while (p != tail) {printf("%d ", p->data);p = p->next;}printf("\n");}```4. 实现报数函数:```cvoid josephus(int n, int m) {Node tail = createList(n); // 创建单向循环链表Node p = tail->next; // 从头节点开始报数Node q = NULL; // 记录出列节点的前一个节点 for (int i = 1; i <= n; i++) {for (int j = 1; j < m; j++) {q = p;p = p->next;}q->next = p->next; // 删除出列节点printf("%d ", p->data); // 输出出列节点编号free(p); // 释放出列节点内存p = q->next; // 从下一个人开始报数}printf("\n");}```5. 实现输出出列顺序的函数:```cvoid printOutSequence(int n, int m) {printf("出列顺序为:\n");josephus(n, m);}```五、实验结果与分析1. 实验结果:- 当N=7,M=3时,出列顺序为:6 1 4 7 2 3 5。

约瑟夫环实验报告

约瑟夫环实验报告

约瑟夫环问题实验报告一、实验内容本实验利用单向循环链表模拟约瑟夫环问题(编号为1,2,…,n的n个人按顺时针方向围坐一圈,没人持有一个密码(正整数)。

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

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

M的初值为20,n=7,7个人的密码依次为3,1,7,2,4,8,4,首先m值为6。

二、源程序#include"stdafx.h"#include<iostream>using namespace std;#include<conio.h>//getch();/*write: Han.JH*/static int people_number_count; typedef struct People_Node{int Password_Data,people_number;struct People_Node *next;}People_Node,*People_LinkList;void GreatList(People_LinkList &L){People_Node *s,*r; int flag=1;int Password;L=new People_Node;L->next=NULL;r=L;while(flag==1){cout<<"输入每个人的密码,以回车作间隔,'0'表示结束:";cin>>Password;//输入每个人的密码;if(Password!=0){s=new People_Node;s->Password_Data=Password;people_number_count++; //对人的编号s->people_number=people_number_count;r->next=s;r=s;}else{ r->next=L->next;flag=0;}}}void GetList(People_LinkList &L){People_Node *r;int m,k;int count=0;cout<<"输入报数上限值m:";cin>>m;r=L;cout<<"出列排序:";while(count!=people_number_count){ //则所有人以出列,结束循环for(k=1;k<=m-1;k++){r=r->next;}count++;m=r->next->Password_Data;cout<<"["<<r->next->people_number<<"]";r->next=r->next->next;}}void main(){People_LinkList L;void GreatList(People_LinkList &);void GetList(People_LinkList &);cout<<"++++++++++++约瑟夫环问题+++++++++++"<<endl;GreatList(L);GetList(L);cout<<"[--结束--]"<<endl;getch();}三、调试刚开始调试时出现了无法打开<iostream.h>头文件的错误,经过上网查询,#include<iostream.h>是C语言风格,但是在标准 C 里面,是不用#include <iostream.h>的,而要使用#include <iostream>把#include<iostream.h>改为:#include<iostream>using namespace std;后,问题解决。

约瑟夫环

约瑟夫环

实验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个人从开始顺时针报数.报m的人(m为正整数).令其出列。

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

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

求出列编号序列。

基本要求:需要基于线性表的基本操作来实现约瑟夫问题需要利用数组来实现线性表测试数据:输入:10,3输出:3 6 9 2 7 1 8 5 10 4选做内容:(1)使用单链表来实现之(2)使用循环链表来实现之实验中使用了数组以及链表的操作,来实现对约瑟夫环的解答。

一、先来讲一讲对数组的实现的思路:数组的实现是一种很常规的方法。

这里必须要设置一个临时变量t,在第一轮的循环中,t=0而且在这一轮中要出列的数字是(t+m-1)%i,举例来说:当n=10,m=3时,t=2,4,6,1,3,0,1,1,0,那么就可以知道最后剩下的是4了。

二、再来讲一讲链表的实现方式:在链表的改写中使用到了这几个函数:append(),next(),remove()和prve();这里实现的思路还是比较简单的。

当输入了n个数据后,使用append()函数连接起来,然后用一number来记录这个节点的代表次数。

北邮数据结构实验-约瑟夫环

北邮数据结构实验-约瑟夫环

北邮数据结构实验-约瑟夫环数据结构实验报告实验名称:实验1——约瑟夫环学生姓名:班级:班内序号:学号:日期:1.实验要求实验目的:通过利用循环链表实现约瑟夫问题的求解进行实现,掌握如下内容:1.熟悉C++语言的基本编程方法,掌握集成编译环境的调试方法2.学习指针、模板类、异常处理的使用3.掌握线性表的操作的实现方法4.学习使用线性表解决实际问题的能力实验内容:利用循环链表实现约瑟夫问题的求解。

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

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

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

2. 程序分析2.1 存储结构首先构建结点的结构体,包括结点的编号number和指向后继元素的指针*next。

然后构建循环链表储存每一个结点。

2.2 关键算法分析1、关键算法:插入:用尾插法构建循环链表,建立一个尾指针r用来保存最后一个结点的地址,插入每一个节点后,r指向新插入的结点。

用for循环来给每一个结点的number赋值。

插入的步骤:1.建立新指针s;2.在for循环中给s赋值;3.将r指针指向s;4.修改尾指针r=s5.在全部结点插入后,将终端结点指向第一个指针,r->next=front->next。

约瑟夫环算法实现:1.因为每次循环都有一个人出列,最后只剩一个人,因此要进行n-1次循环,用for循环实现。

2.同时定义一个指针p=front->next,每次循环front和p均后移m-1个,使p指向每次循环的第m个人,front指向第m-1个人。

并输出出列的人的number,即p->number。

3.让front->next=p->next,删除p。

4.继续进行循环2、代码详细分析:约瑟夫环算法步骤:①定义一个指针p=front->next,每次循环front和p均后移m-1个,使p指向每次循环的第m个人,front指向第m-1个人。

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

数据结构实验一  约瑟夫环问题实验报告电子版
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;
//如果链表剩了一个元素

实验一、约瑟夫问题

实验一、约瑟夫问题

实验一:约瑟夫问题求解一、问题描述1、实验题目:约瑟夫(Josephus)问题的一种描述是:编号为1,2,……,n的n个人按顺时针方向围坐一圈,每人持有一个密码(正整数)。

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

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

2、基本要求:试设计一个程序,按出列顺序印出个人编号。

3、测试数据:m的初值为20;n=7,7个人的密码依次为:3,1,7,2,4,8,4。

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

二、需求分析1、本程序用来求出含有密码的约瑟夫问题,可以输出所有人的出列顺序。

2 、程序运行后显示提示信息,提示用户输入一圈的人数n,接着输入每个人的密码,最后提示输入初始密码。

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

三、概要设计1、设计思路n个人围成一圈,每个人的手中都有一个密码,这个密码决定了下一次报数的上限。

游戏规则:①给定一个初始密码②循环报数,报到密码值的人要出列,依次类推,直到所有的人都出列本程序要求输入的内容:n个人的密码及初始密码;本程序要求输出的内容:n个人出列的顺序。

2、数据结构为了实现上述功能,可以采用链式存储结构。

采用链式存储结构,定义了一个存储个人信息的结构体,及两个自定义函数,分别用于创建链表和约瑟夫出列操作。

①链表抽象数据类型的定义: #define SLNODE struct slnodeADT SLNODE{数据对象:D={ i a |i a ∈SLNODE, i=1,2,3.... }数据关系:R=φ}ADT SLNODE;②自定义函数:void create_SLnode(SLNODE *p,int n)//创建队列{ 创建链表,为N 个人分配密码 }void Josef(SLNODE *p,int n)//进行约瑟夫操作{输入初始密码m;for(){ 将出列的结点删除,并输出出列序号;}}③本程序的保护模块:结构体模块主程序模块自定义函数模块调用关系:3、程序设计主要算法的流程图:create_SLnode( )算法流程图Josef( )算法流程图四、详细设计1、元素类型、结点的类型及指针#define SLNODE struct slnodeSLNODE//每个结点的结构体{int num;//num代表序号int code;//code代表密码SLNODE *next;};2、自定义函数:void create_SLnode(SLNODE *p,int n)//创建队列,并将其尾指针指向第一个序号{SLNODE *r,*s;s=p;int i,m;cout<<"请给这"<<n<<"个人分配密码:"<<endl;for(i=0;i<n;i++){cout<<"请给第"<<i+1<<"个人输入密码:"<<endl;cin>>m;r=(SLNODE *)malloc(sizeof(SLNODE));r->code=m;r->num=i+1;r->next=s->next;s->next=r;s=s->next;}p=p->next;s->next=p;}void Josef(SLNODE *p,int n)//进行约瑟夫操作{p=p->next;int m;int i,j;SLNODE *r;cout<<"请输入初始密码:"<<endl;cin>>m;cout<<"依次出列的序号为:"<<endl;for(i=0;i<n-1;i++)p=p->next;for(i=0;i<n-2;i++){for(j=0;j<m-1;j++)p=p->next;cout<<(p->next)->num<<endl;m=(p->next)->code;r=p->next;p->next=r->next;}if(m%2==0)cout<<p->num<<endl<<(p->next)->num<<endl;elsecout<<(p->next)->num<<endl<<p->num<<endl;}3、主函数:int main(){SLNODE *p;int n;cout<<"请输入一圈的人数:"<<endl;cin>>n;p=(SLNODE *)malloc(sizeof(SLNODE));p->next=NULL;create_SLnode(p,n);Josef(p,n);return 0;}4、函数的调用关系:主函数main()调用自定义函数void create_SLnode(SLNODE *p,int n);/*创建队列*/与void Josef(SLNODE *p,int n);/*进行约瑟夫操作*/。

(完整word版)C语言约瑟夫环问题

(完整word版)C语言约瑟夫环问题

实验一:约瑟夫环问题一.实验目的:要求设计一个程序模拟约瑟夫环问题过程,求出出列编号序列。

二.实验内容:约瑟夫环问题:设编号为1,2,3,……,n的n(n>0)个人按顺时针方向围坐一圈,每个人持有一个正整数密码.开始时任选一个正整数做为报数上限m,从第一个人开始顺时针方向自1起顺序报数,报到m是停止报数,报m的人出列,将他的密码作为新的m值,从他的下一个人开始重新从1报数。

如此下去,直到所有人全部出列为止。

令n最大值取30。

要求设计一个程序模拟此过程,求出出列编号序列。

三.实验过程:用一个不带头结点的循环链表来处理Josephu 问题:先构成一个有n个结点的单循环链表,然后由k结点起从1开始计数,计到m时,对应结点从链表中删除,把被删除结点的密码作为新的m值,然后再从被删除结点的下一个结点又从1开始计数,直到最后一个结点从链表中删除算法结束。

#include〈stdio.h>#include<stdlib。

h〉#define MAX_NODE_NUM 30#define TRUE 1#define FALSE 0typedef struct NodeType{ int number;int password;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(”初始循环的密码为:”);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);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,i=1;NodeType *pPrv, *pCur,*pDel;pPrv=pCur=*ppHead;while(pPrv—〉next!=*ppHead)pPrv=pPrv->next;while(iFlag){for(iCounter=1;iCounter〈iCipher;iCounter++){pPrv=pCur;pCur=pCur->next;}if(pPrv==pCur)iFlag=0;pDel=pCur;pPrv-〉next=pCur-〉next;pCur=pCur-〉next;iCipher=pDel—〉password;printf("第%d个退出的是序列号为%d的人,其密码为:%d\n",i, pDel—>number,pDel-〉password);free(pDel);++i;}*ppHead=NULL;}static void PrntList(const NodeType *pHead){const NodeType *pCur=pHead;if (EmptyList(pHead))return;do{printf("第%d 个人,密码:%d\n”,pCur->number,pCur->password);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("错误,内存不足!\n”);exit(—1);}pNew—>number=iId;pNew-〉password=iCipher;pNew—>next=NULL;return pNew;}static unsigned EmptyList(const NodeType *pHead){if(!pHead){printf(”列表为空!\n”);return TRUE;}return FALSE;}。

数据结构__约瑟夫环问题__实习报告

数据结构__约瑟夫环问题__实习报告

实验报告实验一线性表的基本操作及其应用一、实验目的1、复习C语言程序设计中的知识。

2、熟悉线性表的逻辑结构。

3、熟悉线性表的基本运算在两种存储结构上的实现,其中以熟悉链表的操作为侧重点。

二、实验内容本次实验提供2个题目,如果实现第一个题目有困难,可做第二个题目题目一:约瑟夫环[问题描述]约瑟夫(Joseph)问题的一种描述是:编号为1,2,…,n的n个人按顺时针方向围坐一圈,每人可有代表本人的序号。

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

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

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

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

[测试数据]由学生任意指定。

如:m的初值为5;n的值为7;序号:3,1,7,2,4,8,4;(报告上要求写出多批数据测试结果)[实现提示]程序运行后首先要求用户输入初始报数m,人数n,(设n≤30)。

然后输入各人的序号。

[选作内容]向上述程序中添加在顺序结构上实现的部分实验题目一:约瑟夫环一.需求分析1.利用单向循环链表存储结构模拟此过程,按照出列的顺序印出各人的编号。

2.演示程序以用户和计算机的对话方式执行,即在计算机上显示“提示信息”之后,由用户在键盘上输入演示程序中规定的运算命令;相应的输入数据(滤去输入中的非法字符)和运算结构显示在其后。

3.程序执行的命令包括:1)输入报数上限值;2)输入人数以及所持密码;3)输出出列顺序;4)结束2)测试数据4.由学生任意指定。

如:m的初值为5;n的值为7;序号:3,1,7,2,4,8,4;二.概要设计为实现上述程序功能,需建立单向循环链表以存储此结构。

为此,需要一个抽象数据结构类型。

1.链表结点的抽象数据类型定义为:ADT2.本程序包含三个模块:3)主程序模块;4)循环链表的创建模块——实现创建循环链表;5)出列操作的模块——实现最终的出列操作;各模块之间的调用关系如下:出列操作的模块<——主程序模块——>循环链表的创建模块三.详细设计1.元素类型,结点类型和指针类型struct Lnode{int password;struct Lnode *next;};typedef struct Lnode *LinkList;2. 子函数1,创建循环链表int Creatlist_L(LinkList &head,int n)程序的实现:int Creatlist_L(LinkList &head,int n){//利用引用调用得到头指针head;int i;LinkList p,q;printf("请依次输入各位密码:");for(i=1;i<=n;i++){if(i==1){//申请一个空间,将头指针head和指针p均指向第一个结点;head=p=(LinkList)malloc(sizeof(struct Lnode));if(p==0) return 0; //分配存储空间失败}else{q=(LinkList)malloc(sizeof(struct Lnode));if(q==0) return 0;p->next=q;//通过next将下一个结点和前一个结点连起来;p=q;}scanf("%d",&(p->password));//一次输入对应的密码;}p->next=head;//构成循环链表,并返回链表的头指针return 0;}void DeleteNode(LinkList head,int m,int n){LinkList p,q;int j,i;p=head;for(j=1;j<n;j++){//先出列前n-1个人,并依次释放其结点的空间;for(i=1;i<m;i++,p=p->next);//寻找第m个人;printf("%d ",p->password);p->password=p->next->password;//将后一个结点的数据全部赋值于当前p所指的结点q=p->next;p->next=p->next->next;//p指向其下一个的下个一结点,重新开始寻找;free(q);}printf("%d",p->password);//最后一个人出列,并释放其结点所占空间;free(p);} }scanf("%d",&(p->password));//一次输入对应的密码;}p->next=head;//构成循环链表,并返回链表的头指针return 0;}3.主函数的实现,对两个子函数的调用void main(){int n,m;LinkList List;printf("输入人数:");scanf("%d",&n);printf("输入值m:");scanf("%d",&m);Creatlist_L(List,n);DeleteNode(List,m,n);printf("\n");}4.函数的调用关系图反映了演示程序的层次结构:main——>Creatlist;main——>DeleteNode;四调试分析1.由于对引用调用理解的不透侧,导致刚开始修改了很长时间。

约瑟夫环问题及注释

约瑟夫环问题及注释

约瑟夫环问题及程序问题描述:编号是1,2,……n的n个人按照顺时针方向围坐一圈。

现在从第s个人开始顺序报数,数到第m的人出列,然后从出列的下一个人重新开始报数,数到第m的人又出列,……如此反复,直到所有的人都出列为止。

解决思路:(1)首先利用线性表的一些运算如创建空线性表、插入元素等构造Josephus表。

(2)从Josephus表中的第s个结点开始寻找、输出和删除表中的第m个结点,然后再从该结点的下一个结点开始寻找、输出和删除表中的第m个结点,重复此过程,直到表中的所有元素都删除。

算法基本思想:用整数i来代替n i,将初始序列改写成一个整数的序列:1,2,3,……,n,并把它们存储在一个palist所指向的顺序表中,当s<=n时,第s个人放在palist->elem[s-1]之中,因此第一个报数出列的应该是下标为s-1+m-1对n取模后的元素,如果这个下标为i,出列工作只要将palist->elem[i]从顺序表中删除,然后对palist->elem[0],palist->elem[1],……,palist->elem[n-2]从下标i开始重复上述过程。

程序清单:#include<stdio.h>#include<stdlib.h>#define FALSE 0#define TRUE 1typedef int DataType;struct SeqList{int MAXNUM;int n;DataType *elem;};typedef struct SeqList *PSeqList;PSeqList createNullList_seq(int m){PSeqList palist=(PSeqList)malloc(sizeof(struct SeqList));if(palist!=NULL){palist->elem=(DataType *)malloc(sizeof(DataType)*m);if(palist->elem){palist->MAXNUM=m;palist->n=0;return palist;}elsefree(palist);}printf("Out of space!!\n");return NULL;}int isNullList_seq(PSeqList palist){return(palist->n==0);}int locate_seq(PSeqList palist,DataType x){int q;for(q=0;q<palist->n;q++)if(palist->elem[q]==x)return(q);return -1;}int insertPre_seq(PSeqList palist,int p,DataType x){int q;if(palist->n>=palist->MAXNUM){printf("Overflow!\n");return 0;}if(isNullList_seq(palist)){palist->elem[0]=x;palist->n=1;return 1;}if(p<0||p>palist->n){printf("Not exist!\n");return 0;}for(q=palist->n-1;q>=p;q--)palist->elem[q+1]=palist->elem[q];palist->elem[p]=x;palist->n=palist->n+1;return 1;}int deleteP_seq(PSeqList palist,int p){int q;if(p<0||p>palist->n-1){printf("Not exist!\n");return 0;}for(q=p;q<palist->n-1;q++)palist->elem[q]=palist->elem[q+1];palist->n=palist->n-1;return 1;}void josephus_seq(PSeqList palist,int s,int m){int s1,i,w;s1=s-1;for(i=palist->n;i>0;i--){s1=(s1+m-1)%i;w=palist->elem[s1];printf("Out element %d\n",w);deleteP_seq(palist,s1);}}main(){PSeqList jos_alist;int i;int n,s,m;printf("\n please input the values(<100) of n=");scanf("%d",&n);printf("please input the values of s=");scanf("%d",&s);printf("please input the values of n=");scanf("%d",&m);jos_alist=createNullList_seq(n);if(jos_alist!=NULL){for(i=0;i<n;i++)insertPre_seq(jos_alist,i,i+1);josephus_seq(jos_alist,s,m);free(jos_alist->elem);free(jos_alist);}}运行结果:#include<stdio.h>#include<stdlib.h>#define FALSE 0#define TRUE 1typedef int DataType;//定义datatype为int型struct SeqList //定义链表结构体{int MAXNUM; //报数的最大值int n; //链表中结点个数DataType *elem; //一个指向数组的指针};typedef struct SeqList *PSeqList;PSeqList createNullList_seq(int m) //创建空表{PSeqList palist=(PSeqList)malloc(sizeof(struct SeqList));//定义结构体指针if(palist!=NULL){palist->elem=(DataType *)malloc(sizeof(DataType)*m);//给elme开空间if(palist->elem){palist->MAXNUM=m;palist->n=0;return palist;}elsefree(palist);}printf("Out of space!!\n");return NULL;}int isNullList_seq(PSeqList palist)//判断链表是否为空{return(palist->n==0);}int locate_seq(PSeqList palist,DataType x)//返回x节点的位置{int q;for(q=0;q<palist->n;q++)if(palist->elem[q]==x)return(q);return -1;}int insertPre_seq(PSeqList palist,int p,DataType x)//插入x,到位置p上{int q;if(palist->n>=palist->MAXNUM){printf("Overflow!\n");return 0;}if(isNullList_seq(palist)){palist->elem[0]=x;palist->n=1;return 1;}if(p<0||p>palist->n){printf("Not exist!\n");return 0;}for(q=palist->n-1;q>=p;q--)palist->elem[q+1]=palist->elem[q];palist->elem[p]=x;palist->n=palist->n+1;return 1;}int deleteP_seq(PSeqList palist,int p){int q;if(p<0||p>palist->n-1){printf("Not exist!\n");return 0;}for(q=p;q<palist->n-1;q++)palist->elem[q]=palist->elem[q+1];//让p后面的每一个节点前移一位palist->n=palist->n-1;return 1;}void josephus_seq(PSeqList palist,int s,int m)//最重要的函数,按顺序输出出队的号{int s1,i,w;s1=s-1;for(i=palist->n;i>0;i--){s1=(s1+m-1)%i;//这个关系式,可以得出要出队的人的位置w=palist->elem[s1];printf("Out element %d,,s1=%d,,i=%d,,m=%d\n",w,s1,i,m);deleteP_seq(palist,s1);//删除s1节点}}main(){PSeqList jos_alist;int i;int n,s,m;printf("\n please input the values(<100) of n=");scanf("%d",&n);printf("please input the values of s=");scanf("%d",&s);printf("please input the values of m=");scanf("%d",&m);jos_alist=createNullList_seq(n);if(jos_alist!=NULL){for(i=0;i<n;i++)insertPre_seq(jos_alist,i,i+1);josephus_seq(jos_alist,s,m);free(jos_alist->elem);free(jos_alist);}}。

北邮数据结构实验一_约瑟夫问题_实验报告

北邮数据结构实验一_约瑟夫问题_实验报告

数据结构实验报告实验名称:实验一——线性表学生姓名:班级:班内序号:学号:日期:1.实验要求实验目的熟悉C++语言的基本编程方法,掌握集成编译环境的调试方法学习指针、模板类、异常处理的使用掌握线性表的操作的实现方法学习使用线性表解决实际问题的能力实验内容利用循环链表实现约瑟夫问题的求解。

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

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

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

2. 程序分析2.1 存储结构采用单循环链表实现约瑟夫问题的求解单循环链表存储结构示意图2.2 关键算法分析基本思想:首先,应该确定构造链表时所用的插入方法。

当数到m的那个人就出列,也即删除这个节点,同时建立这个节点的前节点与后节点的联系。

由于是循环计数,所以才采用循环列表方式。

其次还要考虑输入值异常的情况。

之后,就是关于出列节点的逻辑判断。

依次找到待删结点的直接前驱,便于删除结点后修改它的直接后继,如此循环直到最后一个人出列。

关键算法:1.最后一个数据指向头指针,形成循环链表head=new Node; //确定头结点p=head;for(i=1;i<=n-1;i++) //赋初值{p->data=i;p->next=new Node; //为下一个新建内存p=p->next;}p->data=n; //最后一个单独处理p->next=head; //指向头,形成循环链表p=head;2.输入值异常的情况cout<<"请输入环内总人数n:";cin>>n;if (n<1) //考虑n输入错误的情况{cout<<"n值输入错误"<<endl;}cout<<"请输入起始人号码:";cin>>k;if (k<1||k>n) //考虑k输入异常的情况{cout<<"k值输入错误"<<endl;}cout<<"请输入m值:";cin>>m;if (m<1) //考虑m输入异常的情况{cout<<"m值输入错误"<<endl;}3.在约瑟夫环中实现逐个出环并找出最后一个出环的序号while(p!=p->next){for(i=1;i<m-1;i++) //查找q的节点p=p->next;q=p->next;cout<<"第"<<s<<"个出环的人编号是:"<<q->data<<endl;p->next=q->next;p=p->next;delete q; //释放q的空间s++;}cout<<"最后环内留下的人编号是:"<<p->data<<endl;delete p;算法步骤:①从第一个结点开始,查找第i-1个元素,设为p指向该结点;②设q指向第i个元素:q = p->next;,输出q元素的数据;③摘链,即将q元素从链表中摘除:p->next = q->next;p=p->next;delete q;3. 程序运行结果1、测试主函数流程:流程图如图所示2、程序运行结果3、输入错误运行结果4. 总结在调试程序过程中,虽然没有编译错误,但是运行结果总是和准确值差1,最后发现是把i=1写成i=0,才造成的错误,改过之后就没有问题了。

数据结构实验--约瑟夫环问题

数据结构实验--约瑟夫环问题

线性表及其应用班级:软件101 姓名:xxx 学号:xxxxxxx 完成日期:2011-11-18 题目:编制一个求解约瑟夫环问题的程序一、需求分析//该题目的功能等需求、测试数据以及预期的输出结果等。

问题描述:编号为1,2,…,n的n个人按顺时针方向围坐一圈。

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

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

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

(1):在本实验中,要求利用单向循环链表存储结构来完成,以便有效地掌握线性表相关知识及其应用。

(2):在程序运行后,首先指定一个初始报数的上限值m=20,然后输入各人的密码,假设n<=10;(3):编译执行后得到结果并进行检查核对。

(4):测试数据为:初始密码2,各成员密码分别为:2、7、1、8、、2、8、5 ;结束条件:输入0二、概要设计//数据结构的大概设计;程序模块的设计以及大概算法等。

为了实现上述程序功能,应以循环链表存储结构来表示;需要抽象数据类型有:(1):线性链表存储结构的定义struct JosephNode{int number;//编号int password;//密码struct JosephNode *next;};(2):数据结构类型的定义typedef struct JosephNode *JosephCircle;JosephCircle Init(void);JosephCircle CountOff(JosephCircle joseph , int& number , int& password); typedef struct JosephNode *PJoseph;三:详细设计//结构在程序设计语言中的表示;各函数的完整说明;所需函数的概要代码;函数调用关系等。

约瑟夫环(Joseph)实验报告

约瑟夫环(Joseph)实验报告

一.需求分析1.约瑟夫环(Joseph)问题的一种描述是:设有编号1,2,3。

n(n>0)的N个人围成一个圈,每个人持有一个密码(正整数)。

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

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

2.演示程序以用户和计算机的对话方式执行,即在计算机终端上显示“提示信息”之后,有用户在键盘上输入演示程序中规定的运算命令,相应的输入数据和运算结果显示在其后。

3.测试数据(1)m=20, n=7, 7个人的密码依次为:3,1,7,2,4,8,4结果:6,1,4,7,2,3,5二、概要设计本程序是多文件程序,构成的函数有int main() 主函数,输出出队序列int initsuiji() 随机数产生初始化int suiji(int x,int y) 随机数产生函数int InitList(SqList &L) 初始化顺序表int ListInsert(SqList &L,int i,ElemType e) 在顺序表中插入元素int ListDelete(SqList &L,int i,ElemType &e) 删除顺序表中的元素int shunxu(int number) 顺序存储算法JosephuNode *Creat_Node(int numbers) 创建单循环链表void Josephu(JosephuNode *head,int Password) 添加元素信息int lianbiao(int number) 链表算法其中,void main()是最主要的函数,分别执行两种算法,并在执行的同时按照出列顺序输出元素信息(编号,密码),并在结尾输出两种算法执行所用的时间长短。

三、详细设计#include<stdio.h>#include<malloc.h>typedef struct node{int num,code;struct node *next;}Lnode, *LinkList;Lnode *Create_L(LinkList L,int n){int i,key;Lnode *p,*s;p = L;for(i = 1;i <= n;i ++){printf("输入第%d人",i);printf(" 密码:");scanf("%d",&key);s = (Lnode *)malloc(sizeof(Lnode));p->next = s;p = s;p->num = i;p->code = key;}p->next = L->next;p = L;L = L->next;free(p);return L;}void Output_L(LinkList L,int m, int n) {int i,j,key;Lnode *p,*s;key = m;do{p = L;j = 1;if(key == 1){i = p->num;key = p->code;printf("第%d人",i);s = p->next;while(s->next != L)s = s->next;s->next = p->next;L = p->next;free(p);n --;}else{while(j < key){s = p;p = p->next;j ++;}i = p->num;key = p->code;printf("第%d人",i);s->next = p->next;L = p->next;free(p);n --;}}while(n > 0);}int main(){int n,m;Lnode *L;L = (Lnode *)malloc(sizeof(Lnode));printf("输入参加的人数:");scanf("%d",&n);if(n < 0){printf("输入数据不合理,请重新输入。

约瑟夫环问题 实验报告完整版

约瑟夫环问题 实验报告完整版
}
(2)约瑟夫环报数的算法在运行为循环方式,报数者除非本身已经出去,否则继续顺序报数,其报数循环的代码为
void Joseph(NODE *p,int number,int n)
{
int;=number; i++)
{
for(j=1; j<n-1; j++)
(2)基本要求
建立模型,确定存储结构。
对任意n个人,密码为m,实现约瑟夫环问题。
出圈的顺序可以依次输出,也可以用一个数组存储。
(3)思考:
采用顺序存储结构如何实现约瑟夫环问题?
如果每个人持有的密码不同,应如何实现约瑟夫环问题?
2.数据结构设计
由于约瑟夫环问题本身具有循环性质,考虑采用循环链表,为了统一对表中任意结点的操作,循环链表不带头结点。将循环链表的结点定义为如下结构类型:
5.运行测试与分析
(1)输出提示,如图1.2所示。
(2)根据提示,输入圈内人数n和每个人持有的密码m如图1.3所示。
(3)输出结果如图1.4所示
分析
6.实验收获及思考
通过该实验,我进一步增强了对于链表的理解,也对链表的操作和实现更为熟悉,熟练掌握了如何实现置空表、求表的长度、取结点、定位运算、插入运算、删除运算、建立不带头结点的单链表(头插入法建表)、建立带头结点的单链表(尾插入法建表),输出带头结点的单链表等操作。同时,锻炼了实际操作时的动手能力。
{
p=p->next;
}
q=p->next;
p->next=q->next;
p=p->next;
printf("第%3d个出圈的人是:%3d\n",i,q->value);

约瑟夫环实习报告

约瑟夫环实习报告

实习报告:约瑟夫环实验一、实习背景约瑟夫环问题是一个经典的计算机科学和数学问题,起源于古罗马时期的历史故事。

问题描述了n个人围成一个圆圈,从第一个人开始报数,每数到m个人就将其删除,然后从下一个人重新开始报数,直到圈中只剩下一个人。

本实习报告旨在通过实现约瑟夫环算法,深入理解其原理和应用,并分析不同算法实现的时间和空间复杂度。

二、实习内容1. 算法实现本次实习实现了两种约瑟夫环算法的实现:迭代法和递归法。

迭代法使用循环结构模拟圆圈的过程,每轮删除指定数量的节点,直到只剩下一个节点。

递归法则利用递归函数模拟这个过程,每次递归调用删除指定数量的节点,直到只剩下一个节点。

2. 算法分析在算法分析方面,我们主要从时间复杂度和空间复杂度两个方面进行考虑。

对于迭代法,时间复杂度主要取决于删除节点的次数,每次删除操作的时间复杂度为O(1),因此总的时间复杂度为O(n)。

空间复杂度主要取决于程序的存储空间,由于使用了循环结构,空间复杂度为O(n)。

对于递归法,每次递归调用都会创建一个新的栈帧,因此空间复杂度主要取决于递归深度。

在最坏情况下,递归深度为n-1,因此空间复杂度为O(n)。

时间复杂度同样为O(n),因为每次递归调用都需要进行删除操作。

3. 实验结果我们使用Python语言实现了约瑟夫环算法,并使用Python的time模块测量了不同算法实现的时间。

实验结果显示,在n较小的情况下,迭代法和递归法的运行时间相差不大。

但随着n的增大,迭代法的运行时间逐渐优于递归法。

这是因为递归法在每次递归调用时都会创建新的栈帧,随着递归深度的增加,栈帧的创建和销毁会占用较多的时间。

三、实习心得通过本次实习,我对约瑟夫环问题有了更深入的理解。

在实现算法的过程中,我学会了如何使用循环结构和递归函数模拟圆圈的过程。

在分析算法的过程中,我学会了如何计算时间复杂度和空间复杂度,并能够根据实际情况选择合适的算法。

同时,我也认识到算法优化的重要性。

用顺序表解决约瑟夫环问题

用顺序表解决约瑟夫环问题

⽤顺序表解决约瑟夫环问题⼀、实验题⽬:约瑟夫环问题:设编号为1,2,3,……,n的n(n>0)个⼈按顺时针⽅向围坐⼀圈,m为任意⼀个正整数。

从第⼀个⼈开始顺时针⽅向⾃1起顺序报数,报到m时停⽌并且报m的⼈出列,再从他的下⼀个⼈开始重新从1报数,报到m时停⽌并且报m的⼈出列。

如此下去,直到所有⼈全部出列为⽌。

要求设计⼀个程序模拟此过程,对任意给定的m和n,求出出列编号序列。

实验要求:⽤顺序表实现。

⼆、设计分析:⾸先创建了⼀个顺序表,并且⽤数组存每个⼈的编号,出列的时候将此编号置为0,代表此位置的⼈已经出列,循环查询编号不为0的元素,并⽤变量j记下当前是第⼏个⼈,当j==m的时候,代表此位置是第m个⼈,输出并将编号置为0,⽤k记录出列⼈的下⼀位的索引,并将数组长度-1,再进⾏新⼀轮的循环,直到所有⼈都出列。

三、程序代码:#include<iostream>#include<cstdlib>using namespace std;const int MaxSize=100;typedef struct Node{int data[MaxSize];int length;}List;void CreateList(List *&L,int n){L=(List *)malloc(sizeof(List*));for(int i=1;i<=n;i++){L->data[i]=i;}L->length=n;}void DispList(List *&L,int m){int len=L->length;int j=0,k=1;while(L->length){for(int i=1;i<=len;i++){if(L->data[k]){j++;}if(j==m){cout<<L->data[k]<<" ";L->data[k]=0;L->length--;j=0;k=(k+1)%(len+1)?(k+1)%(len+1):1;break;}k=(k+1)%(len+1)?(k+1)%(len+1):1;}}}int main(){int m,n;cin>>m>>n;List *L;CreateList(L,n);DispList(L,m);return 0;}。

数据结构实验报告一-约瑟夫环问题

数据结构实验报告一-约瑟夫环问题

实验1约瑟夫环问题1.需求分析(1)输入的形式和输入值的范围:每一次输入的值为两个正整数,中间用逗号隔开。

若分别设为n,m,则输入格式为:“n,m”。

不对非法输入做处理,即假设输入都是合法的。

(2)输出的形式:输出格式1:在字符界面上输出这n个数的输出序列输出格式2:将这n个数的输出序列写入到文件中(3)程序所能达到的功能:对于输入的约瑟夫环长度n和间隔m,输出约瑟夫环的出列顺序。

(4)测试数据:包括正确的输入及其输出结果和含有错误的输入及其输出结果。

正确:输入:10,3输出:3 6 9 2 7 1 8 5 10 4输入:41,3输出:3 6 9 12 15 18 21 24 27 30 33 36 39 1 5 10 14 19 23 28 32 37 41 7 13 20 2634 40 8 17 29 38 11 25 2 22 4 35 16 31错误:输入:10 3输出:6 8 7 1 3 4 2 9 5 102.概要设计(1)抽象数据类型的定义:为实现上述程序的功能,可以用整数存储用户的输入。

并将用户输入的值存储于线性表中。

线性表ADT定义如下:ADT list数据对象:整形数据关系:线性关系,即<ai,ai+1>(0≤a<n)。

基本操作:bool remove(int &elem)//移除一个元素,被移除的元素赋给elem//如果操作成功,返回true,否则返回falsebool isEmpty()//判断数组的元素是否清空,空返回true,否则返回falsebool setPos(int place)//设置当前元素的位置,设置成功返回true,否则返回falseint getLength()//获取数组的实际长度(2)算法的基本思想:约瑟夫环问题中的数据是人所在的位置,而这种数据是存在“第一元素、最后元素”,并且存在“唯一的前驱和后继的”,符合线性表的特点。

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

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

最新实验一约瑟夫问题实验报告实验目的:探究约瑟夫问题(Josephus Problem)的数学规律及其在不同参数下的表现,验证相关算法的效率和准确性。

实验背景:约瑟夫问题是一个著名的理论问题,源自于罗马时代的一个传说。

问题可以描述为:n个人围成一圈,从第一个人开始报数,每数到第m个人,该人出圈,然后从下一个人重新开始报数,如此循环,直到所有人出圈。

本实验旨在通过编程模拟这一过程,并分析结果。

实验方法:1. 采用编程语言(如Python)编写约瑟夫问题的模拟程序。

2. 设定不同的n和m值,运行程序,记录每个人的出圈顺序及最后剩下的人的位置。

3. 分析不同n和m值下的出圈顺序规律。

4. 对比不同算法(如递归法、迭代法)的运行时间,评估效率。

实验步骤:1. 初始化参数:确定模拟的总人数n和报数间隔m。

2. 创建一个循环队列模拟人们围成的圈。

3. 通过循环和条件判断模拟报数和出圈过程。

4. 记录每次出圈的人的编号和最终剩下的人的位置。

5. 改变n和m的值,重复步骤1至4,收集多组数据。

6. 分析数据,寻找出圈规律。

7. 对模拟过程进行计时,比较不同算法的运行时间。

实验结果:1. 通过大量实验数据,发现当n和m的值较小时,可以直观看出出圈顺序的规律。

2. 随着n和m值的增大,出圈顺序变得更加复杂,但依然存在一定的规律性。

3. 实验中使用的迭代法在处理大规模数据时,相比递归法具有更高的效率,递归法在深度较大时可能会导致栈溢出。

4. 通过图表展示了不同n和m值下,最后剩下的人的位置的概率分布。

实验结论:1. 约瑟夫问题的出圈顺序并非完全随机,存在一定的数学规律。

2. 迭代法在解决大规模约瑟夫问题时更为高效和稳定。

3. 本实验为进一步研究约瑟夫问题提供了实验数据和算法优化方向。

建议:对于未来的研究,可以尝试将约瑟夫问题推广到更多变种,如双向报数、不同方向报数等,以及探索其在实际问题中的应用,如网络协议设计、资源分配等。

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

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

数据结构实验报告—约瑟夫问题求解《计算机软件技术基础》实验报告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值,输出出列序列。

实验报告1约瑟夫环

实验报告1约瑟夫环

《数据结构》实验报告班级:姓名:学号:日期:08-10-20题目:约瑟夫环一、上机实验的问题和要求:问题描述:编号为1到n的n个人围成一圈,每人带一个密码c,以m为报数上限。

然后从第一个人开始顺时针自1开始报数,报到m的人出列,将其密码作为新的m值,从他的下一个人开始,同样顺时针自1开始报数,依次循环下去,直到所有的人都出列!要求得到依次出列的那些人的编号序列!基本要求:用C代码实现此活动,要求使用一定的算法进行操作,并最终通过程序运算出最后的结果!二、程序设计的基本思想,原理和算法描述:(包括程序的模块结构,数据结构,输入/输出设计,符号名说明等)基本思想:利用不带头结点单向循环链表模拟该活动,在实现了一切动作之后,运用一定的算法得到最终的结果。

程序的模块结构:定义了相关的结构体之后,主要有以下几大模块:1.建立由头指针指示的有n个结点的不带头结点的单向循环链表crt_CLinkList(H,n);2.寻找、输出、删除H单循环链表的第m个结点locfor(H,m);3.最后通过main函数体处理参数的输入与显示,并调用以上两函数,最终解决问题。

主要数据结构:单链的循环链表,即线性表的链式存储结构。

算法的伪码描述:结构体定义如下:typedef struct Lnode /*定义单链表*/{int number; /*编号*/int cipher; /*密码*/struct Lnode *next; /*指针*/}Lnode,*CLinklist; /*重定向命名*/CLinklist H; /*H为全局单链表*/算法的实现详见源程序。

输入/输出设计本程序并未采用任何二进制文件出入的方式,这点说明将在最后总结提到。

至于函数的出入口问题,在源程序及注释中将得到详细说明,这里不再赘述。

三、源程序及注释:(说明函数功能、入口及出口参数,其他)#include <stdio.h> /* 头文件*/#include <stdlib.h>#include <alloc.h>typedef struct Lnode /*定义单链表*/{int number; /*编号*/int cipher; /*密码*/struct Lnode *next; /*指针*/}Lnode,*CLinklist; /*重定向命名*/CLinklist H; /*H为全局单链表*/struct Lnode *crt_CLinkList(CLinklist H,int m) /*创建一个不带头结点的单向循环链表*/{ /*其中,H为全局单链表,m为链表结点总数*/ int i; /*循环记数用*/struct Lnode *ptr1; /*用于索引*/if((ptr1=(struct Lnode *)malloc(sizeof(struct Lnode)))==NULL) /*一旦动态内存分配失败,报错退出!*/ {perror("malloc");return ptr1;}H=ptr1; /*形成单个结点的单循环链表*/ptr1->next=H;for(i=1;i<m;i++) /*形成m个结点的不带头结点的单循环链表*/ {if((ptr1->next=(struct Lnode *)malloc(sizeof(struct Lnode)))==NULL){perror("malloc");ptr1->next=H;return H;}ptr1=ptr1->next; /*其中H指头,ptr指尾*/ptr1->next=H;}return H; /*返回成功新建的单链表H*/}void locfor(CLinklist H,int m) /*寻找输出删除链表H中的第m个结点*/{ /*H为全局链表,m为要查找删除的结点位置*/ int i; /*循环计数*/struct Lnode *ptr;for(i=1;i<=5;i++) /*考虑图形界面的美观问题*/printf("number\tcipher\t");i=1; /*初始化*/while(H->next!=H) /*只剩单个结点时停止循环,进行最后输出!*/ {if(m==1) /*考虑进行自身删除的情况,即m=1*/{for(ptr=H->next;ptr->next!=H;ptr=ptr->next);/*正因为是自身删除才要费大劲寻找其父结点*/printf("%-6d\t",H->number); /*找到后,先输出*/printf("%-6d\t",H->cipher);m=H->cipher; /*确定下一次寻找的m值*/ptr->next=H->next; *删除结点,即自身结点*/ptr=ptr->next;free(H); /*因为对于链表中的结点,每个之前都分配了内存,所以free是必要的*/H=ptr; /*不同于以下普通结点的删除,自身删除还要还原H*/i=1; /*i重置,以方便下一次的循环操作*/}else if(i==m-1) /*因为从自身开始即为1号,因为m-1,而不是m*/{ptr=H->next; /*结点的删除操作同于上面的情况!*/printf("%-6d\t",ptr->number);printf("%-6d\t",ptr->cipher);m=ptr->cipher;H->next=ptr->next;H=H->next;free(ptr);i=1;}else{H=H->next; /*若未找到,则继续遍历!*/i++;}}printf("%-6d\t",H->number); /*对于单个结点的单循环链表,进行最终的输出操作!*/ printf("%-6d",H->cipher);free(H); /*完成所有任务并释放所有内存占用!*/}void main() /*主函数接口*/{ /*调用所有函数,进行实验模拟,并得出实验结果!*/ int i,j,n=30,m,k;struct Lnode *ptr;randomize(); /*因为下面调用了random函数,故此处的初始化很有必要!*/ printf("Now the experiment will begin.You have two choices!\n");/*数据输入可以电脑随机,也可以自行输入*/printf("If you want to enter the datas all by yourself,please enter 1.\n");/*自行输入(方便检测程序问题)*/ printf("If you want to get the datas by the computer,please enter 0.\n"); /*电脑随机产生数据*/printf("Now your choice:"); /*用户选择*/scanf("%d",&j);while(j!=0&&j!=1) /*考虑程序的完善性,对于误输入的提示并报警!*/ {printf("\nYou enter is unillage!Please try again!\n");printf("Now your choice:"); /*重新输入*/scanf("%d",&j);}H=crt_CLinkList(H,n); /*初始化链表*/if(j==0) /*电脑随机充入数据*/for(i=1;i<=30;i++){H->number=i;H->cipher=rand(); /*随机函数*/H=H->next;}else /*此时选择实验者输入数据!*/{for(i=1;i<=30;i++){H->number=i;printf("Now number %d,please enter the cipher:",i);scanf("%d",&k);H->cipher=k;H=H->next;}}m=rand(); /*默认情况下,m随机产生*/printf("Do you want to enter the number m?Enter 1 to set or others cancel!\n");/*当然,如果想自已输,可以进行覆盖*/scanf("%d",&k);if(k==1) /*自行输入m值*/{printf("Please enter the number m:");scanf("%d",&m);}system("cls"); /*考虑屏幕大小,进行分屏显示*/printf("All followed are your datas!\n"); /*界面友善*/for(i=1;i<=5;i++)printf("number\tcipher\t");for(i=0;i<30;i++) /*显示所有处理前数据*/{printf("%-6d\t",H->number);printf("%-6d\t",H->cipher);H=H->next;}printf("And the number m is :%d\n",m);printf("\nAfter the program,the result is:\n");locfor(H,m); /*对所有数据进行实验处理,直至所有结点处理完!*/ getchar();printf("\nPress any key return!"); /*TC环境下,方便查看结果!*/getchar();}四、用户使用说明与测试运行结果:1.运行程序后,首先弹出界面,截图如右:理性化的选择:如果打1,则所有的cipher均由用户输入,这样方便对特殊数据进行程序测试!如果打0,那么所有的数据均由电脑产生!那如果打其他的呢?考虑到误输入,加了一个循环,以提高程序的健壮性!2.首先自行输入数据进行测试。

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

实验一约瑟夫环问题
约瑟夫环问题:
设编号为1,2,3,……,n的n(n>0)个人按顺时针方向围坐一圈,每个人持有一个正整数密码。

开始时任选一个正整数做为报数上限m,从第一个人开始顺时针方向自1起顺序报数,报到m是停止报数,报m的人出列,将他的密码作为新的m值,从他的下一个人开始重新从1报数。

如此下去,直到所有人全部出列为止。

令n最大值取30。

要求设计一个程序模拟此过程,求出出列编号序列。

实现:
用一个不带头结点的单向循环链表表示上述约瑟夫环,结点结构可定义为:
typedef sturct node Array { int no; /*编号*/
int key; /*密码域*/
struct node *next; /*指针域*/
} jNode;
注意:
不带头结点的单向循环链表判空条件的处理。

#include<stdio.h>
#include<stdlib.h>
typedef struct Joseph
{
int num;
int key;
struct Joseph *next;
} Joseph1;
Joseph1 *CreatList(int n)
{
Joseph1 *R,*p,*q;
int i,k;
R=p=(Joseph1*)malloc(sizeof(Joseph1));
p->next=NULL;
for(i=0;i<n-1;i++){
q=(Joseph1*)malloc(sizeof(Joseph1));
p->num=i+1;
scanf("%d",&k);
if(k<=0)
{
printf("输入信息有误!");
exit(0);
}
p->key=k;
p->next=q;
p=q;
}
q->num=n;
scanf("%d",&k);
if(k<=0)
{
printf("输入信息有误!");
exit(0);
}
q->key=k;
q->next=R;
R=q;
return(R);
}
void DeleList(int n,Joseph1 *P,int m)
{
Joseph1 *q,*t;
q=P;
int i,j;
for(i=1;i<n;i++)
{
for(j=1;j<m;j++)
q=q->next;
t=q->next;
q->next=t->next;
m=t->key;
printf("删除的第%d个数是:",i);
printf("%d\n",t->num);
free(t);
}
printf("删除的最后一个数是:%d\n",q->num);
free(q);
}
void main()
{
int m,n;
Joseph1 *P;
printf("请输入参加的人数: ");
scanf("%d",&n);
if(n<=0|)
{
printf("输入信息有误!");
exit(0);
}
printf("请输入初始密码: ");
scanf("%d",&m);
if(m<=0)
{
printf("输入信息有误!");
exit(0);
}
printf("请输入每个人的密码: ");
P=CreatList(n);
DeleList(n,P,m);
}。

相关文档
最新文档