利用链表解决约瑟夫问题

合集下载

C语言单向循环链表实现实现约瑟夫环

C语言单向循环链表实现实现约瑟夫环

C语言实现约瑟夫环问题------单向循环链表实现问题描述:有n个人围成一圈进行报数游戏,从第一个人开始报到m的人出圈,接下来有从下一个人开始,。

一次这样往复,直到最后一个人也出圈,求他们的出圈顺序?(例如8个人,凡报3的人出圈,则他们出圈顺序是3 ,6, 1,,5 ,2 ,8,4 ,7)#include<stdio.h>#include<stdlib.h>typedef struct node{int value;struct node *next;}NODE;//*********************建立循环链表(尾插法建立)***********//NODE *createlink(int number){NODE *head=NULL,*p=NULL,*q=NULL;int i=1;head=(struct node*)malloc(sizeof(struct node)); //***建立第一个节点***//head->value=i;p=head;for(i=2;i<=number;i++) //***建立剩下的number-1节点****//{q=(struct node*)malloc(sizeof(struct node));if(q==0) return 0;p->next=q;p=q;p->value=i;}p->next=head;return head;}//*****************建立约瑟夫环********************// void jose(NODE *p,int number,int n){int i,j,g=0;NODE *q=NULL;for(i=1;i<=number;i++){for(j=1;j<n-1;j++){p=p->next;}q=p->next; //***q用来记录要删除的节点*****//p->next=q->next; //****删去q节点******//p=p->next;printf("第%3d个出圈号是:%3d\n",i,q->value);free(q);}printf("\n");// p->next=NULL; 此表达式不能出现在此处,最后一个节点删除后就不存在了}//***********************主函数*************************//int main( ){int number=0;int n=0;printf("请输入总人数number和出拳编号n:\n");scanf("%d",&number);scanf("%d",&n);NODE *head=NULL;head=createlink(number);jose(head,number,n);system("PAUSE");return 1;}。

约瑟夫问题

约瑟夫问题

一问题描述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的值再输入每个人的密码最后得到出列顺序八附录(源程序)这里附上两种源程序,本质上相同,只是第一个程序按老师要求写为很多子函数形式,第二个是我已开始编的,一个大函数。

C++单链表实现约瑟夫环

C++单链表实现约瑟夫环

#include <iostream.h>#include <stdlib.h>struct Member//定义结构体{int number;int password;Member *next;};class Joseph{public:Member *frist;//头指针int size;Joseph(void);~Joseph(void);int Size(void) const;//返回长度Member *Index(int i);//定位void Create(int i);//构造循环单链表int Delete(int i);//删除结点并返回number的值};Joseph::Joseph(){//frist=new Member;Member *p=new Member;frist=p;size=0;}Member *Joseph::Index(int i){if(i==0)return frist;Member *p=frist->next;int j=1;while(j<i){p=p->next;j++;}return p;}int Joseph::Size(void)const{return size;}void Joseph::Create(int i){for(int j=1;j<=i;j++){Member *p=Index(j-1);Member *q=new Member;q->number=j;p->next=q;size++;};//Member *p=Index(i);//p->next=frist;}Joseph::~Joseph(void){Member *p,*q;p=frist;while(size!=0){q=p;p=p->next;delete q;size--;}size=0;frist=NULL;}int Joseph::Delete(int i){Member *s,*p=Index(i-1);s=p->next;p->next=p->next->next;int x=s->number;cout<<x<<" ";int y=s->password;delete s;size--;return y;}void main(void){Joseph jos;int i;cout<<"Please input number of people :"<<endl;cin>>i;jos.Create(i);int frist;//设初始值cout<<"Please input the frist number :"<<endl;cin>>frist;for(int k=1;k<=i;k++)//用循环输入每个人的密码{cout<<"please input No."<<k<<"`s password:"<<endl;Member *b=jos.Index(k);cin>>b->password;}cout<<"The final is :"<<endl;int l=frist%i;if (l==0) l=i;for(int b=i-1;b>0;b--){frist=jos.Delete(l);l=(frist+l-1)%b;int e=jos.Size();if(l==0)l=e;}jos.Delete(l);cout<<endl;}。

约瑟夫环实验报告

约瑟夫环实验报告

约瑟夫环问题实验报告一、实验内容本实验利用单向循环链表模拟约瑟夫环问题(编号为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;后,问题解决。

约瑟夫环问题

约瑟夫环问题

约瑟夫环问题问题描述:有n个⼈,编号分别从0到n-1排列,这n个⼈围成⼀圈,现在从编号为0的⼈开始报数,当报到数字m的⼈,离开圈⼦,然后接着下⼀个⼈从0开始报数,依次类推,问最后只剩下⼀个⼈时,编号是多少?分析:这就是著名的约瑟夫环问题,关于来历不再说明,这⾥直接分析解法。

解法⼀:蛮⼒法。

我曾将在⼤⼀学c语⾔的时候,⽤蛮⼒法实现过,就是采⽤标记变量的⽅法即可。

解法⼀:循环链表法。

从问题的本质⼊⼿,既然是围成⼀个圈,并且要删除节点,显然符合循环链表的数据结构,因此可以采⽤循环链表实现。

解法三:递推法。

这是⼀种创新的解法,采⽤数学建模的⽅法去做。

具体如下:⾸先定义⼀个关于n和m的⽅程f(n,m),表⽰每次在n个编号0,1,...,n-1中每次删除的报数为m后剩下的数字,在这n个数字中,第⼀个被删除的数字是(m-1)%n,为了简单,把(m-1)%n记作k,那么删除k之后剩下的数字为0,1,2,...,k-1,k+1,...,n-1并且下⼀次删除的数字从k+1开始计数,这就相当于剩下的序列中k+1排在最前⾯,进⽽形成k+1,..,n-1,0,1,2,...,k-1这样的序列,这个序列最后剩下的数字应该和原序列相同,由于我们改变了次序,不能简单的记作f(n-1,m),我们可以记作g(n-1,m),那么就会有f(n,m)=g(n-1,m).下⼀步,我们把这n-2个数字的序列k+1,..,n-1,0,1,2,...,k-1做⼀个映射,映射的结果是形成⼀个从0到n-2的序列。

k+1对0,k+2对1,......,n-1对n-k-2,0对n-k-1,1对n-k,....,k-1对n-2这样我们可以把这个映射定义为p,则p(x)=(x-k-1)%n,它表⽰如果映射前的数字是x,映射后为(x-k-1)%n,从⽽这个映射的反映射问为p-1(x)=(x+k+1)%n由于映射之后的序列和原始序列具有相同的形式,都是从0开始的序列,所以可以⽤函数f来表⽰,即为f(n-1,m),根据映射规则有:g(n-1,m)=p-1[f(n-n,m)]=[f(n-1,m)+k+1]%n,最后把之前的k=(m-1)%n带⼊式⼦就会有f(n,m)=g(n-1,m)=[f(n-1,m)+m]%n.这样我们就可以得出⼀个递推公式,当n=1时,f(n,m)=0;当n>1时,f(n,m)=[f(n-1,m)+m]%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. 通过上机实践,掌握了用高级语言实现算法的基本步骤和方法.(最前面加班级、学号、姓名)。

约瑟夫问题的链式求解法

约瑟夫问题的链式求解法

实验一约瑟夫问题求解一、实验目的1、掌握上机调试线性表的基本方法;2、掌握线性表的基本操作:插入、删除、查找等运算在顺序存储结构和链式存储结构上的运算。

3、掌握约瑟夫问题求解算法二、实验内容1、认真阅读和掌握本实验的参考程序,并上机运行本程序,可尝试完善删除、查找等运算。

2、参考第二章课件中对瑟夫问题求解算法的描述,选择一种存储结构实现该问题的求解。

三、注意事项:1、在磁盘上创建一个目录,专门用于存储数据结构实验的程序,可通过U盘或邮箱长期保存程序。

2、实验报告要求:(1)算法的完整代码;(2)程序运行结果及分析;(3)实验总结。

四、参考程序1、顺序表的插入(1)程序代码#include "stdio.h"#include "stdlib.h"typedef struct SeqList{int data[100];int length; /* 表长*/}SeqList , *PSeqList;PSeqList creaeNullList_seq()/* 创建空线性表*/{PSeqList palist=(PSeqList)malloc(sizeof(struct SeqList));if(palist!=NULL){palist->length=0;return(palist);}printf("Out of space!!\n");return NULL;}int isNullList_seq(PSeqList palist)/* 判断是否空线性表*/{return (palist->length==0);}int insertPre_seq(PSeqList palist,int p,int x){int q;if(palist->length>=100){printf("overflow!\n");return(0);}if(p<0 || p>palist->length){printf("Not exist!\n");return(0);}if(isNullList_seq(palist)){palist->data[0]=x;palist->length=1;return(1);}for(q=palist->length-1;q>=p;q--)palist->data[q+1]=palist->data[q] ;palist->data[p]=x;palist->length= palist->length+1;return(1);}void main(){int i;PSeqList list;list=creaeNullList_seq(); /* 创建空线性表*/printf("插入前的顺序表为:\n ");for(i=0;i<=9;i++){insertPre_seq(list,i,i*i);printf(" %d " , list->data[i]);}insertPre_seq(list,5,55);/*在下标为5的元素之前插入元素55*/ printf("\n\n插入后的顺序表为:\n ");for(i=0;i<list->length;i++)printf(" %d " , list->data[i]);printf("\n\n");}(2)运行结果2、约瑟夫问题顺序表的实现int josephus_ SeqList (PSeqList josephus_seq, int s, int m){ /*求解约瑟夫问题的出列元素序列入口参数:已经存放数据的顺序表,起始位置s,数m , 出口参数:1表示成功,0表示表中没有元素*/int s1,i,w;if ( ! josephus_seq->length){ printf(“表中无元素”);return (0); }s1=s - 1; /*data数组中下标从0开始*/printf(“输出约瑟夫序列:”);for( i= josephus_seq->length; i>0; i --;){ s1=(s1+m-1)% i; /*找到出列元素的下标*/w= josephus_seq->data[s1];printf(“%d\t”, w)Delete_SeqList(josephus_seq,s1); /*删除出列元素*/} /*for */return(1); /*成功返回*/}3、约瑟夫问题链表的实现int josephus_ LinkList (LinkList josephus_Link, int s, int m){ /*求约瑟夫问题的出列元素序列,入口参数:已经存放数据的链表头指针的地址,起始位置s,数m ,出口参数:1表示成功,0表示表中没有元素*/LinkList p,pre; /*p指向当前结点,pre指向其前驱结点*/int count;if ( ! josephus_Link){ printf(“表中无元素”);return (0);}/*找第s个元素*/p= josephus_Link;for(count=1;count<s;count++) /*查找第s个结点,用p作为第s个结点的指针*/p=p->next;printf(“输出约瑟夫序列:”);while ( p!=p->next) /*输出n-1个元素个结点*/{ for(count=1;count<m;count++){ pre=p;p=p->next;} /*for*/printf(“%d\t”, p->data);pre->next=p->next;free(p);p=pre->next;}/*while*/printf(“%d\t”,p->data); /*输出最后一个元素个结点*/free(p);return 1;}2.约瑟夫问题的求解(1)程序代码#include"stdio.h"#include"stdlib.h"typedef struct node{int data;struct node *next;}lnode,*linklist;linklist Init_josephus(void){linklist head;head=(linklist)malloc(sizeof(lnode));if(!head){printf("Apply place is faliure!\n\n");return NULL;}head->next=NULL;return head;}void Create_josephus(linklist JOS){linklist p,q,H;int x;p=H=JOS;printf("please enter elements:\n");scanf("%d",&x);p->data=x;scanf("%d",&x);while(x!=-1){q=(linklist)malloc(sizeof(lnode));q->data=x;q->next=p->next;p->next=q;p=q;scanf("%d",&x);}p->next=H;p=H;printf("\n");while(p->next!=H){printf("%3d",p->data);p=p->next;}printf("%3d",p->data);printf("\n");}int josephus_linklist(linklist josephus_link,int s,int m){linklist p,pre;int count;if(!josephus_link){printf("There are not have elements in the list!\n");return 0;}p=josephus_link;for(count=1;count<s;count++)p=p->next;printf("The list of josephus is :\n");while(p!=p->next){for(count=1;count<m;count++){pre=p;p=p->next;}printf("%d\t",p->data);pre->next=p->next;free(p);p=pre->next;}printf("%d\t",p->data);free(p);printf("\n");return 1;}main(){int i,j;lnode *Josephus;Josephus=Init_josephus();Create_josephus(Josephus);printf("please enter the first elements number and steps:\n");scanf("%d%d",&i,&j);josephus_linklist(Josephus,i,j);return 2;}(2)程序运行结果(3)实验总结这次实验用的是链式存储结构来解决约瑟夫问题,第一遍编写的程序中,指针使用的有点混乱,头结点不知该如何处理,指针问题解决后,在运行的过程中,头结点的问题一直解决不了即创建的表有问题还没有解决,表的创建中数据的输出里一个很大的数,原因就是头结点中的值域为空;后来将两个结构体类型的指针同时指向头指针,才将问题顺利解决。

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

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

北京邮电大学电信工程学院数据结构实验报告实验名称:实验一——约瑟夫问题学生姓名: ***班级: 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++也因长时间没有碰过而稍显手生,在码程序的过程中遇到了很多问题,但通过翻看教材已基本解决。

约瑟夫环数据结构实验报告

约瑟夫环数据结构实验报告

约瑟夫环数据结构实验报告约瑟夫环数据结构实验报告引言约瑟夫环是一种经典的数学问题,它涉及到一个有趣的数据结构。

本次实验旨在通过实现约瑟夫环数据结构,深入理解该问题,并探索其在实际应用中的潜力。

本报告将介绍实验的设计和实现过程,并分析实验结果。

实验设计在本次实验中,我们选择使用链表来实现约瑟夫环数据结构。

链表是一种非常灵活的数据结构,适合用于解决约瑟夫环问题。

我们设计了一个Josephus类,其中包含了创建环、添加元素、删除元素等操作。

实验实现1. 创建环在Josephus类中,我们首先需要创建一个循环链表。

我们使用一个头节点来表示环的起始位置。

在创建环的过程中,我们可以选择指定环的长度和起始位置。

2. 添加元素在创建环之后,我们可以通过添加元素来向约瑟夫环中插入数据。

我们可以选择在环的任意位置插入元素,并且可以动态地调整环的长度。

3. 删除元素根据约瑟夫环的规则,每次删除一个元素后,下一个元素将成为新的起始位置。

我们可以通过删除元素的操作来模拟约瑟夫环的运行过程。

在删除元素时,我们需要考虑环的长度和当前位置。

实验结果通过实验,我们得出了以下结论:1. 约瑟夫环数据结构可以有效地模拟约瑟夫环问题。

通过创建环、添加元素和删除元素的操作,我们可以模拟出约瑟夫环的运行过程,并得到最后剩下的元素。

2. 约瑟夫环数据结构具有一定的应用潜力。

除了解决约瑟夫环问题,该数据结构还可以用于其他类似的问题,如任务调度、进程管理等。

3. 约瑟夫环数据结构的时间复杂度较低。

由于约瑟夫环的特殊性质,我们可以通过简单的链表操作来实现该数据结构,使得其时间复杂度较低。

结论本次实验通过实现约瑟夫环数据结构,深入理解了该问题,并探索了其在实际应用中的潜力。

通过创建环、添加元素和删除元素的操作,我们可以模拟出约瑟夫环的运行过程,并得到最后剩下的元素。

约瑟夫环数据结构具有一定的应用潜力,并且具有较低的时间复杂度。

通过本次实验,我们对数据结构的设计和实现有了更深入的理解,并为将来的研究和应用奠定了基础。

约瑟夫问题实验报告

约瑟夫问题实验报告

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

2. 学习使用循环链表解决线性问题。

3. 提高编程能力和算法设计能力。

二、实验原理约瑟夫问题(Josephus Problem)是一个著名的数学问题,也称为约瑟夫环问题。

问题描述为:N个人围成一圈,从第一个人开始按顺时针方向报数,每数到M的人出列,然后从下一个人开始继续报数,直到所有人都出列。

我们需要找到一种方法,计算出每个人出列的顺序。

三、实验内容1. 创建一个循环链表,模拟N个人围成一圈。

2. 编写一个函数,实现报数和出列操作。

3. 输出每个人出列的顺序。

四、实验步骤1. 定义一个循环链表节点结构体,包含编号和指向下一个节点的指针。

2. 创建一个循环链表,包含N个节点,节点的编号依次为1到N。

3. 编写一个函数`kill(int m, int n)`,实现报数和出列操作:- 初始化一个指针指向第一个节点。

- 从第一个节点开始,按照报数上限M进行报数,每数到M的人出列。

- 更新指针,指向下一个节点,继续报数。

- 重复上述步骤,直到所有节点都被删除。

4. 输出每个人出列的顺序。

五、实验代码```c#include <stdio.h>#include <stdlib.h>// 定义循环链表节点结构体typedef struct Node {int number; // 节点编号struct Node next; // 指向下一个节点的指针} Node;// 创建循环链表Node create(int n) {Node head = NULL, tail = NULL, temp = NULL; for (int i = 1; i <= n; i++) {temp = (Node)malloc(sizeof(Node));temp->number = i;temp->next = NULL;if (head == NULL) {head = temp;tail = temp;} else {tail->next = temp;tail = temp;}}tail->next = head; // 形成循环链表return head;}// 输出循环链表void printList(Node head) {Node temp = head;do {printf("%d ", temp->number);temp = temp->next;} while (temp != head);printf("\n");}// 解决约瑟夫问题void josephus(int m, int n) {Node head = create(n);Node temp = head, pre = NULL;for (int i = 1; i <= n; i++) {for (int j = 1; j < m; j++) {pre = temp;temp = temp->next;}printf("%d ", temp->number);pre->next = temp->next; // 删除节点 free(temp);temp = pre->next;}printf("\n");}int main() {int m, n;printf("请输入报数上限M: ");scanf("%d", &m);printf("请输入人数N: ");scanf("%d", &n);printf("初始站队为: ");josephus(m, n);return 0;}```六、实验结果与分析通过运行实验代码,可以得到每个人出列的顺序。

C语言的循环链表和约瑟夫环

C语言的循环链表和约瑟夫环

C语言的循环链表和约瑟夫环C语言的循环链表和约瑟夫环约瑟夫问题)是一个数学的应用问题,对于学习C语言四非常挺有帮助的,下面是店铺为大家搜集整理出来的有关于C语言的循环链表和约瑟夫环,一起了解下吧!循环链表的实现单链表只有向后结点,当单链表的尾链表不指向NULL,而是指向头结点时候,形成了一个环,成为单循环链表,简称循环链表。

当它是空表,向后结点就只想了自己,这也是它与单链表的主要差异,判断node->next是否等于head。

代码实现分为四部分:1. 初始化2. 插入3. 删除4. 定位寻找代码实现:1 2 3 4 5 6 7 8 9 1 0 1 1 1 2 1 3 1void ListInit(Node *pNode){int item;Node *temp,*target;cout<<"输入0完成初始化"<<endl; cin="">>item;if(!item)return ;if(!(pNode)){ //当空表的时候,head==NULLpNode = new Node ;if(!(pNode))exit(0);//未成功申请pNode->data = item;pNode->next = pNode;}else{//for(target = pNode;target->next!=pNode;target = target->next);4 15 16 17 18 19 2 0 2 1 2 2 2 3 2 4 2 5 2 6 2 7 2 8 2 9 3 0 3 1 3 2 3 3 3 4 3 5 3temp = new Node;if(!(temp))exit(0);temp->data = item;temp->next = pNode;target->next = temp;}}}void ListInsert(Node *pNode,int i){ //参数是首节点和插入位置Node *temp;Node *target;int item;cout<<"输入您要插入的值:"<<endl; cin="">>item;if(i==1){temp = new Node;if(!temp)exit(0);temp->data = item;for(target=pNode;target->next != pNode;target = target->next);temp->next = pNode;target->next = temp;pNode = temp;}else{target = pNode;for (int j=1;j<i-1;++j) target="target-">next;temp = new Node;if(!temp)exit(0);temp->data = item;temp->next = target->next;target->next = temp;}}void ListDelete(Node *pNode,int i){Node *target,*temp;if(i==1){for(target=pNode;target->next!=pNode;target=target ->next);temp = pNode;//保存一下要删除的首节点 ,一会便于释放6 37 38 39 4 0 4 1 4 2 4 3 4 4 4 5 4 6 4 7 4 8 4 9 5 0 5 1 5 2 5 3 5 4 5 5 5 6 5 7 5pNode = pNode->next;target->next = pNode;temp;}else{target = pNode;for(int j=1;j<i-1;++j) target="target-">next;temp = target->next;//要释放的nodetarget->next = target->next->next;temp;}}int ListSearch(Node *pNode,int elem){ //查询并返回结点所在的位置Node *target;int i=1;for(target = pNode;target->data!=elem && target->next!= pNode;++i)target = target->next;if(target->next == pNode && target->data!=elem)return 0;else return i;}</i-1;++j)></i-1;++j)></endl;></endl;>5 96 0 6 1 6 2 6 3 6 4 6 5 6 6 67 68 69 7 0 7 1 7 2 7 3 7 4 7 5 7 6 7 7 7 8 7 9 8约瑟夫问题约瑟夫环(约瑟夫问题)是一个数学的'应用问题:已知n个人(以编号1,2,3…n分别表示)围坐在一张圆桌周围。

约瑟夫问题C代码

约瑟夫问题C代码

约瑟夫问题C代码 1/*Joseph Problem2 *利⽤单循环链表解决约瑟夫问题。

3 *问题描述:将n个数链接成⼀个环,从第m个开始,每次从1计数到s时4 * 将s删除。

从下⼀个开始再次从1计数⾄s时删除s。

直到全5 * 部删除为⽌。

6 * */7 #include<stdio.h>8 #include<stdlib.h>910 typedef struct Node{11int data;12struct Node* next;13 }Node;14 typedef struct Node* LinkList;1516void CreateJosephLoop(LinkList *L,int number){17//创建Joseph环,在头结点中放⼊了元素1.18 *L = (LinkList)malloc(sizeof(struct Node));19if(!(*L)){20 printf("Error:malloc:0!\n");21 exit(1);22 }23 (*L)->next = (*L);24 (*L)->data = 1;25int i;26 LinkList new;27 LinkList tail = *L;28for(i = 1; i < number; i++){29new = (LinkList)malloc(sizeof(struct Node));30if(!new){31 printf("Error:malloc:1+i");32 exit(1);33 }34new->data = i+1;35new->next = tail->next;36 tail->next = new;37 tail = new;38 }39 }40void JosephProblem(int loopSize,int from,int stepBy){41//loopSize:Joseph环的⼤⼩42//form:从from开始43//stepBy:每次计数到stepBy时删除stepBy所指向的元素44 LinkList L;45 CreateJosephLoop(&L,loopSize);46int seekStart = 1;47while(seekStart < from){48 L = L->next;49 seekStart += 1;50 }51while(L->data != L->next->data){52int i = 1;53 LinkList temp;54for(i = 1;i < stepBy - 1; ){55 L = L->next;56 i++;57 }58 temp = L->next;59 printf("%d-->",temp->data);60 L->next = L->next->next;61 L = L->next;62free(temp);63 }64 printf("%d\n",L->data);65 }66int main(){67 JosephProblem(10,3,4);68 JosephProblem(41,1,3); 69return0;70 }。

《数据结构》上机实验报告—约瑟夫环问题

《数据结构》上机实验报告—约瑟夫环问题
福州大学数计学院
《数据结构》上机实验报告
专业和班级:信息计算科学与应用数学6班
学号
姓名
成绩
实验名称
线性表结构及其应用
实验内容
约瑟夫环问题







【实验目的】
利用单向循环链表解决约瑟夫环问题,提高综合设计能力。
【基本要求】
利用单向循环链表存储结构模拟此过程,按归口炪列的顺序印出各人的编号.



i=1;
while(i<=n)

printf(”请输入第%d个人的密码:”,i);
scanf("%d",&pwd);
if(pwd〈= 0)continue;
Insert(L,pwd, i);
i++;

i = 1;
p = L-〉next;
while(L->next!= L)

q = p;
p = p->next;
【结果截图】





解决约瑟夫环问题有三个算法:
一个是在顺序表上实现,另一个是在单向循环链表上实现,第三个则是利用循环队列的方式来实现。
说明:实验名称为教学大纲中各章的实验项目名称,实验内容为具体章节的实验内容名称






【问题描述】
约瑟夫问题:编号为1,2,。。n的n个人按顺时针方向围坐一圈,每人持有一个密码(正整数)。一开始任选一个正整数作为报数上限值m,从第一个人开始按顺时针方向自1开始顺序报数,报到m时停止报数。报m的人出列,将他的密码作为新的m值,从他在顺时针方向上的下一个人开始重新从1报数,如此下去,直至所有人全部出列为止.试设计一个程序求出出列顺序.

数据结构实验报告约瑟夫环

数据结构实验报告约瑟夫环

数据结构实验报告约瑟夫环约瑟夫环是一个经典的问题,涉及到数据结构中的循环链表。

在本次数据结构实验中,我们将学习如何使用循环链表来解决约瑟夫环问题。

约瑟夫环问题最早出现在古代,传说中的犹太历史学家约瑟夫斯·弗拉维奥(Josephus Flavius)在围攻耶路撒冷时,为了避免被罗马人俘虏,与其他39名犹太人躲进一个洞穴中。

他们决定宁愿自杀,也不愿被敌人俘虏。

于是,他们排成一个圆圈,从第一个人开始,每次数到第七个人,就将他杀死。

最后剩下的人将获得自由。

在这个问题中,我们需要实现一个循环链表,其中每个节点表示一个人。

我们可以使用一个整数来表示每个人的编号。

首先,我们需要创建一个循环链表,并将所有人的编号依次添加到链表中。

接下来,我们需要使用一个循环来模拟每次数到第七个人的过程。

我们可以使用一个指针来指向当前节点,然后将指针移动到下一个节点,直到数到第七个人为止。

一旦数到第七个人,我们就将该节点从链表中删除,并记录下该节点的编号。

然后,我们继续从下一个节点开始数数,直到只剩下一个节点为止。

在实现这个算法时,我们可以使用一个循环链表的数据结构来表示约瑟夫环。

循环链表是一种特殊的链表,其中最后一个节点的指针指向第一个节点。

这样,我们就可以实现循环遍历链表的功能。

在实验中,我们可以使用C语言来实现循环链表和约瑟夫环算法。

首先,我们需要定义一个节点结构体,其中包含一个整数字段用于存储编号,以及一个指针字段用于指向下一个节点。

然后,我们可以实现创建链表、添加节点、删除节点等基本操作。

接下来,我们可以编写一个函数来实现约瑟夫环算法。

该函数接受两个参数,分别是参与游戏的人数和每次数到第几个人。

在函数内部,我们可以创建一个循环链表,并将所有人的编号添加到链表中。

然后,我们可以使用一个循环来模拟每次数到第几个人的过程,直到只剩下一个节点为止。

在每次数到第几个人时,我们可以删除该节点,并记录下其编号。

最后,我们可以返回最后剩下的节点的编号。

约瑟夫环问题的两种解法(详解)

约瑟夫环问题的两种解法(详解)

约瑟夫环问题的两种解法(详解)约瑟夫环问题的两种解法(详解)题⽬:Josephus有过的故事:39 个犹太⼈与Josephus及他的朋友躲到⼀个洞中,39个犹太⼈决定宁愿死也不要被敌⼈抓。

于是决定了⾃杀⽅式,41个⼈排成⼀个圆圈,由第1个⼈开始报数,每报数到第3⼈该⼈就必须⾃杀。

然后下⼀个重新报数,直到所有⼈都⾃杀⾝亡为⽌。

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

对于这个题⽬⼤概两种解法:⼀、使⽤循环链表模拟全过程⼆、公式法我们假设这41个⼈编号是从0开始,从1开始报数,第3个⼈⾃杀。

1、最开始我们有这么多⼈:[ 0 1 2 3 4 5 ... 37 38 39 40 ]2、第⼀次⾃杀,则是(3-1)%41=2 这个⼈⾃杀,则剩下:[ 0 1 3 4 5 ... 37 38 39 40 ]3、然后就是从编号为3%41=3的⼈开始从1报数,那么3号就相当于头,既然是头为什么不把它置为0,这样从它开始就⼜是与第1,2步⼀样的步骤了,只是⼈数少了⼀个,这样不就是递归了就可以得到递归公式。

想法有了就开始做:4、把第2步中剩下的⼈编号减去3映射为:[ -3 -2 0 1 2 ... 34 35 36 37 ]5、出现负数了,这样不利于我们计算,既然是环形,37后⾯报数的应该是-3,-2,那么把他们加上⼀个总数(相当于加上360度,得到的还是它)[ 38 39 0 1 2 3 ... 34 35 36 37 ]6、这样就是⼀个总数为40个⼈,报数到3杀⼀个⼈的游戏。

这次⾃杀的是第5步中的(3-1)%40=2号,但是我们想要的是第2步中的编号(也就是最初的编号)那最初的是多少?对应回去是5;这个5是如何得到的呢?是(2+3)%41得到的。

⼤家可以把第5步中所有元素对应到第2步都是正确的。

7、接下来是[ 35 36 37 38 0 1 2... 31 32 33 34 ]⾃杀的是(3-1)%39=2,先对应到第5步中是(2+3)%40=5,对应到第2步是(5+3)%41=8。

约瑟夫环问题详解

约瑟夫环问题详解

约瑟夫环问题详解很久以前,有个叫Josephus的⽼头脑袋被门挤了,提出了这样⼀个奇葩的问题:已知n个⼈(以编号1,2,3...n分别表⽰)围坐在⼀张圆桌周围。

从编号为k的⼈开始报数,数到m的那个⼈出列;他的下⼀个⼈⼜从1开始报数,数到m的那个⼈⼜出列;依此规律重复下去,直到圆桌周围的⼈全部出列这就是著名的约瑟夫环问题,这个问题曾经风靡⼀时,今天我们就来探讨⼀下这个问题。

这个算法并不难,都是纯模拟就能实现的。

思路⼀:⽤两个数组,mark[10000]和num[10000],mark这个数组⽤来标记是否出队,num这个⽤来存值,然后每次到循环节点的时候就判断mark是否为0(未出队),为0则输出num[i],并标记mark[i]=1,直到所有的num都出队。

附上C++代码:#include<iostream>#include<cstring>#include<cstdio>#include<cstdlib>#include<cctype>#include<cmath>#include<algorithm>using namespace std;char num[1000];bool mark[1000];int main(){while(true){memset(mark,0,sizeof(mark));int n;int k,m;int i,j;int del=k-1;cin>>n>>k>>m;for(i=0;i<n;++i){cin>>num[i];}int cnt=n;for(i=cnt;i>1;--i){for(int j=1;j<=m;){del=(del+1)%n;if(mark[del]==0)j++;}cout<<num[del]<<" ";mark[del]=1;}for(i=0;i<n;++i){if(mark[i]==0)break;}cout<<endl<<"The final winner is:"<<num[i]<<endl;}return 0;}思路⼆:⽤⼀个数组就可,每次到了循环节点了就将num[i]输出,然后将后⾯的值往前移动⼀位,直到所有的节点出列。

约瑟夫问题实验报告

约瑟夫问题实验报告

约瑟夫问题实验报告(文章一):约瑟夫问题数据结构实验报告中南民族大学管理学院学生实验报告实验项目: 约瑟夫问题课程名称:数据结构年级:专业:信息管理与信息系统指导教师:实验地点:管理学院综合实验室完成日期:小组成员:学年度第(一)、实验目的(1)掌握线性表表示和实现;(2)学会定义抽象数据类型;(3)学会分析问题,设计适当的解决方案;(二)、实验内容【问题描述】:编号为1,2,…,n 的n 个人按顺时针方向围坐一圈,每人持有一个密码(正整数)。

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

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

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

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

【测试数据】:m 的初值为20;密码:3,1,7,2,4,8,4(正确的结果应为6,1,4,7,2,3,5)。

(三)、实验步骤(一)需求分析对于这个程序来说,首先要确定构造链表时所用的方法。

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

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

程序存储结构利用单循环链表存储结构存储约瑟夫数据(即n个人的编码等),模拟约瑟夫的显示过程,按照出列的顺序显示个人的标号。

编号为1,2,?,n 的n 个人按顺时针方向围坐一圈,每人持有一个密码(正整数)。

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

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

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

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

Josephu约瑟夫问题java实现(环形链表)

Josephu约瑟夫问题java实现(环形链表)

Josephu约瑟夫问题java实现(环形链表)5.4.1约瑟夫问题Josephu(约瑟夫、约瑟夫环) 问题为:设编号为 1,2,… n 的 n 个⼈围坐⼀圈,约定编号为 k(1<=k<=n)的⼈从 1 开始报数,数 到 m 的那个⼈出列,它的下⼀位⼜从 1 开始报数,数到 m 的那个⼈⼜出列,依次类推,直到所有⼈出列为⽌,由 此产⽣⼀个出队编号的序列。

5.4.2解决思路⽤⼀个不带头结点的循环链表来处理 Josephu 问题:先构成⼀个有 n 个结点的单循环链表,然后由 k 结点起从 1 开 始计数,计到 m 时,对应结点从链表中删除,然后再从被删除结点的下⼀个结点⼜从 1 开始计数,直到最后⼀个 尚硅⾕ Java 数据结构和算法 更多 Java –⼤数据 –前端 –python ⼈⼯智能 -区块链资料下载,可访问百度:尚硅⾕官⽹ 第 55页 结点从链表中删除算法结束。

代码实现//约瑟夫问题-环形链表public class Josepfu {public static void main(String[] args) {CircleSingleLinkedList circleSingleLinkedList = new CircleSingleLinkedList();circleSingleLinkedList.addBoy(5);// 加⼊ 5 个⼩孩节点circleSingleLinkedList.showBoy();circleSingleLinkedList.countBoy(1, 2, 5);}}//环形链表class CircleSingleLinkedList{//指向链表的第⼀个节点private Boy first = null;//添加num个⼩孩节点public void addBoy(int num){if (num<1)throw new RuntimeException("输⼊值错误");Boy curBoy = null;for(int i=1;i<=num;i++){Boy boy = new Boy(i);if (i==1){first = boy;first.setNext(first);//形成环curBoy = first;}else{boy.setNext(first);curBoy.setNext(boy);curBoy = boy;}}}// 根据⽤户的输⼊,计算出⼩孩出圈的顺序/**** @param startNo* 表⽰从第⼏个⼩孩开始数数* @param countNum* 表⽰数⼏下* @param nums* 表⽰最初有多少⼩孩在圈中*/public void countBoy(int startNo, int countNum, int nums) {if (nums<1||countNum<1||first==null||startNo<1||startNo>nums)throw new RuntimeException("参数有误,从新输⼊!!");//创建辅助指针,指向环形链表的最后⼀个节点Boy helper = first;while (helper.getNext()!=first){helper = helper.getNext();}//移动helper和first,使从第startNo个⼩孩开始数for (int i=0;i<(startNo-1);i++){helper = helper.getNext();first = first.getNext();}//开始数数,出圈while (helper!=first){//报数for (int i=0;i<(countNum-1);i++){helper = helper.getNext();first = first.getNext();}System.out.println("⼩孩"+ first.getNo() +"出队列:" );first = first.getNext();helper.setNext(first);}System.out.println("最后的⼩孩:"+ first.getNo());}//遍历环形链表public void showBoy(){if (first==null)throw new RuntimeException("链表为空");System.out.println("⼩孩的编号: "+first.getNo());//first⽆法移动,创建中介节点遍历链表Boy curBoy = first.getNext();//当中介节点再⼀次回到first时,表⽰链表遍历完成while (curBoy!=first){System.out.println("⼩孩的编号: "+curBoy.getNo()); curBoy = curBoy.getNext();}}}//创建boy类表⽰⼀个节点class Boy{private int no;private Boy next;public Boy(int no) {this.no = no;}public int getNo() {return no;}public void setNo(int no) {this.no = no;}public Boy getNext() {return next;}public void setNext(Boy next) {this.next = next;}}。

约瑟夫问题

约瑟夫问题

用循环队列解决约瑟夫问题
#include <iostream.h> void Fmade(int x, int y, int z); void main() { int a, b, c; //t i, j, k; //t aa[41], b[41]; cout<<"请输入总人数:"; 请输入总人数: 请输入总人数 cin>>a; cout<<endl<<"请输入开始位子:"; 请输入开始位子: 请输入开始位子 cin>>b; cout<<endl<<"请输入步长:"; 请输入步长: 请输入步长 cin>>c; Fmade(a, b, c); }
void Fmade(int x, int y, int z) { int i, j=0, k=0; int aa[41], bb[41]; int start; aa[0]=0; for(i=1; i<=x; i++) { aa=i; } start=y; while(j < x) { while(start <= x) { if(aa[start] !=0) { k++; }
问题分析与算法设计
41个人围成一圈,因而启发我们用一个循环的链来表 个人围成一圈, 个人围成一圈 可以使用结构数组来构成一个循环链。 示。可以使用结构数组来构成一个循环链。结构中有两个 成员,其一为指向下一个人的指针,以构成环形的链; 成员,其一为指向下一个人的指针,以构成环形的链;其 二为该人是否自杀的标记, 表示还活着。 二为该人是否自杀的标记,为1表示还活着。从第一个人 表示还活着 开始对还未自杀的人进行计数,每数到3时 开始对还未自杀的人进行计数,每数到 时,将结构中的 标记改为0,表示该人已自杀了。这样循环计数直到有2个 标记改为 ,表示该人已自杀了。这样循环计数直到有 个 人还活着为止。 人还活着为止。

约瑟夫环问题的两种解法(循环链表和公式法)

约瑟夫环问题的两种解法(循环链表和公式法)

约瑟夫环问题的两种解法(循环链表和公式法)问题描述这⾥是数据结构课堂上的描述:N people form a circle, eliminate a person every k people, who is the final survior?Label each person with 0, 1, 2, ..., n - 1, denote(表⽰,指代) J(n, k) the labels of surviors when there are n people.(J(n, k)表⽰了当有 n 个⼈时幸存者的标号)First eliminate the person labeled k - 1, relabel the rest, starting with 0 for the one originally labeled k.0 1 2 3 ... k-2 k-1 k k+1 ... n-1... k-2 0 1 ...Dynamic programmingJ(n, k) = J(J(n - 1, k) + k) % n, if n > 1,J(1, k) = 0⽤中⽂的⽅式简单翻译⼀下就是 (吐槽:为啥课上不直接⽤中⽂呢?淦!) 有 n 个⼈围成⼀圈,从第⼀个⼈开始,从 1 开始报数,报 k 的⼈就将被杀死,然后从下⼀个⼈开始重新从 1 开始报数,往后还是报 k 的⼈被杀掉,杀到最后只剩⼀个⼈时,其⼈就为幸存者。

(上⾯的英⽂是从 0 开始的,是因为我们写程序时使⽤了数组,所以下标从 0 开始)解决⽅案循环链表⽅法算法思路很简单,我们这⾥使⽤了循环链表模拟了这个过程:节点 1 指向节点 2,节点 2 指向节点 3,...,然后节点 N 再指向节点 1,这样就形成了⼀个圆环。

如图所⽰,n 取 12,k 取 3,从 1 开始报数,然后依次删除 3, 6, 9, 12:#include<stdio.h>#include<stdlib.h>typedef struct Node // 节点存放⼀个数据和指向下⼀个节点的指针{int data;struct Node *next;} *NList; // NList为指向 Node 节点的指针// 创建⼀个节点数为 n 的循环链表NList createList(int n){// 先创建⼀个节点NList p, tmp, head;p = (NList)malloc(sizeof(struct Node));head = p; // 保存头节点p->data = 1; // 第⼀个节点for (int i = 2; i <=n ; i++){tmp = (NList)malloc(sizeof(struct Node));tmp->data = i;p->next = tmp;p = tmp;}p->next = head; // 最后⼀个节点指回开头return head;}// 从编号为 1 的⼈开始报数,报到 k 的⼈出列,被杀掉void processList(NList head, int k){if (!head) return;NList p = head;NList tmp;while (p->next != p){for (int i = 0; i < k - 1; i++){tmp = p;p = p->next;}printf("%d 号被杀死\n", p->data);tmp->next = p->next;free(p);p = NULL; // 防⽌产⽣野指针,下同p = tmp->next;}printf("幸存者为 %d 号", p->data);free(p);p = NULL;}int main(){NList head = createList(11);processList(head, 3);return 0;}测试结果:易知,这个算法的时间复杂度为O(nk),显然,这不是⼀个好的算法。

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

山西大学计算机与信息技术学院
实验报告
姓名学号专业班级
课程名称数据结构实验日期2015.5.13
成绩指导教师批改日期实验名称
一、实验目的:
利用链表解决约瑟夫问题。

二、实验内容:
1、概要设计
使用CreateList函数创建一个线性链表,其中链表长度由输入数据指定,输入数据由自然数按顺序组成,其对应密码由时间随机给出。

使用Length函数计算线性表长度。

使用Locate函数顺序遍历线性链表并返回当前结点对应的密码。

由Delete函数删除链表中指定结点。

在主函数中依次调用,并根据数据关系,在主函数中写出如下函数体便可。

LinkList L;
int x,k,j;
printf("Please enter an integer to be SQList length ----\n ");
CreateList(L);
k=Length(L);
printf("Please enter an random number m ---- \n");
scanf("%d",&x);
while(k>0){
while(x>k)x=x-k;
j=Locate(L,x);
Delete(L,x);
x=j-k+x;
k=k-1;
if(x<=0)x=x+k;
2、详细设计
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
#include <time.h>
const int MAX_N=100;
typedef struct LNode{
int data;
int password;
LNode *next;
}LNode, *LinkList;
int Length(LinkList L){
LNode *p=L; int j=0;
if(!p) {printf("No head node!\n"); return 0;}
while(p->next){p=p->next;j++;}
return j;
}
void CreateList(LinkList &L){
L=(LinkList)malloc(sizeof(LNode));
L->next=NULL;
srand((unsigned)time(NULL));
LNode *p=L, *s;
int j;
int x =1;
scanf("%d",&j);
while(x!=j){
s=(LinkList)malloc(sizeof(LNode));
if(!s) {printf("OVERFLOW!\n"); return;}
s->data=x;
s->password= rand()%j+1;
s->next=p->next;
p->next=s;
p=s; //设尾指针
x=x+1;
}
p=L->next;
printf("SQList element and password----- \n" );
while(p){printf("element:%3d password:%3d \n", p->data,p->password); p=p->next;} printf("\n");
return;
}
int Locate(LinkList L, int x){//带头结点
LNode* p=L; int j=0;
while(p&&(j!=x)) {p=p->next; j++;}
if(!p) {printf("(L)No such Element %4d\n", x); return 0;}
return p->password;
}
void Delete(LinkList L,int x){
LNode* p=L; int j=0;
while(p&&(j!=x-1)) {p=p->next; j++;}
if(!p) printf("(D)No such Element %4d\n", x);
printf("Delete number %d \n",p->next->data);
p->next=p->next->next;
}
int main(){
LinkList L;
int x,k,j;
printf("Please enter an integer to be SQList length ----\n ");
CreateList(L);
k=Length(L);
printf("Please enter an random number m ---- \n");
scanf("%d",&x);
while(k>0){
while(x>k)x=x-k;
j=Locate(L,x);
Delete(L,x);
x=j-k+x;
k=k-1;
if(x<=0)x=x+k;
}
printf("\Program ends!\n"); }
三、实验结果:
四、结果分析:
运算结果完全正确。

相关文档
最新文档