约瑟夫环 C语言 循环链表

合集下载

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

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

C语⾔⽤循环单链表实现约瑟夫环⽤循环单链表实现约瑟夫环(c语⾔),供⼤家参考,具体内容如下源代码如下,采⽤Dev编译通过,成功运⾏,默认数到三出局。

主函数:main.c⽂件#include <stdio.h>#include "head.h"#include "1.h"int main(){Linklist L;int n;printf("请输⼊约瑟夫环中的⼈数:");scanf("%d",&n);Createlist(L,n);printf("创建的约瑟夫环为:\n");Listtrave(L,n);printf("依次出局的结果为:\n");Solution(L,n);return 0;}head.h⽂件:#include "1.h"#include <stdio.h>#include <stdlib.h>typedef int Elemtype;typedef struct LNode{Elemtype data;struct LNode *next;}LNode,*Linklist;void Createlist(Linklist &L,int n){Linklist p,tail;L = (Linklist)malloc(sizeof(LNode));L->next = L;//先使其循环p = L;p->data = 1;//创建⾸节点之后就先给⾸节点赋值,使得后⾯节点赋值的操作能够循环tail = L;for(int i = 2;i <= n;i++){p = (Linklist)malloc(sizeof(LNode));p->data = i;p->next = L;tail->next = p;tail = p;}printf("已⽣成⼀个长度为%d的约瑟夫环!\n",n);}void Listtrave(Linklist L,int n)//遍历函数{Linklist p;p = L;for(int i = 1;i <= n;i++){printf("%3d",p->data);p = p->next;}printf("\n");}int Solution(Linklist L,int n){Linklist p,s;p = L,s = L;int count = 1;while(L){if(count != 3){count++;p = p->next;//进⾏不等于3时的移位}else{Linklist q;q = p;//⽤q保存p所指的位置,⽅便进⾏节点的删除if(s->next->data == s->data)//当只有⼀个元素的时候{printf("%3d\n",s->data);free(s);return OK;}else//当有两个及两个以上的元素的时候{count = 1;//先将count重置为1printf("%3d",p->data);//再打印出出局的值while(s->next != p){s = s->next;//将s移位到p的前驱节点处}p = p->next;//使p指向⾃⼰的下⼀个节点s->next = p;//进⾏删除free(q);}}}}1.h⽂件:#define TRUE 1#define FALSE 0#define OK 1#define ERROR 0#define INFEASIBLE -1#define OVERFLOW -2运⾏结果:以上就是本⽂的全部内容,希望对⼤家的学习有所帮助,也希望⼤家多多⽀持。

约瑟夫生死游戏(C++)数据结构实现

约瑟夫生死游戏(C++)数据结构实现

一:【内容与要求】约瑟夫游戏的大意是:每30 个旅客同乘一条船,因为严重超载,加之风高浪大,危(wei)险万分;因此船长告诉乘客,惟独将全船一半的旅客投入还中,其余人材干避免遇难。

无奈,大家只得允许这种办法,并议定30 个人围成一圈,由第一个人数起,挨次报数,数到第9人,便把他投入大海中,然后再从他的下一个人数起,数到第9 人,再将他扔进大海中,如此循环地进行,直到剩下15 个乘客为止。

问哪些位置是将被扔下大海的位置。

二:概要设计利用链表循环来解决。

首先,就必须先定义一个链表,按照所需要的长度进行定义,然后令其为指针指向头指针,即完成为了一个循环链表的创建。

接下来先打印链表输出。

其次,就是算法实现,需要利用指针来进行,数据域标记人员编号,先用一个指针循环查找,找到第一个需要删除的人,标记为1,先输出节点数,再进行删除。

挨次循环查找,直到被删除的节点数量为总人数的一半的时候则结束。

三:程序执行流程图否三:详细代码结构1. 链表的创建(1) 创建头节点Josephring(){head=new Node;//为头结点申请空间head->no=1;//为数据域赋值head->next=head;//形成循环链表}(2) 循环插入链表void Josephring::CreateJosephus(int n){Node*s=head;//标记头结点totalnum=n;for(int i=2;i<=n;i++){ Node*w=new Node;//新建一个节点w->no=i;w->next=head;s->next=w;s=w;//S 作为尾指针}}首先申请一个节点,并且W 指针指向它,然后从2 开始赋值,此时先令新节点的W 指针指向头结点,再令S 指针指向它,挨次循环插入创建。

2. 打印输出链表void Josephring::show(){cout<<head->no<<"\t";//先输出头节点Node*q=head->next;while(q!=head){cout<<q->no<<"\t";q=q->next;}}先打印输出头结点,然后循环判定,将不等于头结点的全部输出。

约瑟夫环问题 数据结构C语言描述

约瑟夫环问题 数据结构C语言描述

void Josephus()
{
Linklist L;
Node *p,*r,*q;
int m,n,C,j;
L=(Node*)malloc(sizeof(Node)); /*初始化单向循环链表*/
if(L==NULL) { printf("\n 链表申请不到空间!");return;}
L->next=NULL;
r=L;
printf("请输入人数 n 的值(n>0):");
scanf("%d",&n);
for(j=1;j<=n;j++)
/*建立链表*/
{
p=(Node*)malloc(sizeof(Node));
if(p!=NULL)
{
printf("请输入第%d 个人的密码:",j);
scanf("%d",&C);
约瑟夫环问题
约瑟夫问题的一种描述为:编号 1,2,…,n 的 n 个人按顺时针方向围坐一圈,每个人持有一 个密码(正整数)。一开始任选一个报数上限值 m,从第一个人开始顺时针自 1 开始顺序报 数,报到 m 时停止报数。报 m 的人出列,将他的密码作为新的 m 值,从他在顺时针方向上 的下一个人开始重新从 1 报数,如此下去,直至所有的人全部出列为止。试设计一个程序, 求出出列顺序。利用单向循环链表作为存储结构模拟此过程,按照出列顺序打印出各人的编 号。
/*获得新密码*/
n--;
q->next=p->next; /*p 出列*/
r=p;
p=p->next;
free(r);

【案例】约瑟夫环问题--结构体数组、链表

【案例】约瑟夫环问题--结构体数组、链表

int main() { Josephus man[N]; init_Josephus(man,N); baoshu(man, N, M) ; printf("\n按座位顺序排列:\n"); display_Josephus(man,N); sort_by_count(man,N); printf("\n按出列顺序排列:\n"); display_Josephus(man,N); getch(); return 0; }
p->num=n++; // 座位号 strcpy(p->name,name); p->count=0; // 出列序号
if(*head==NULL){//循环单链表的头指针 *head=p; p->next=p; } else{ p->next=pre->next; pre->next=p; } pre=p; }while(1); return n-1; //链表中的节点个数 }
方法2:结构体数组
如果,还要知道参加游戏人的名字,怎么办? • 座位号:结构体成员(整型) 或 数组的下标 • 名字:结构体成员(字符串) • 出列序号:结构体成员(整型)
// 定义结构体类型 typedef struct { int num; // 座位序号 char name[20]; int count; // 出列序号 }Josephus; // 定义结构体数组 Josephus man[N]; // 结构体数组元素的初始化 for(i=0;i<N;i++) { man[i].num=i+1; gets(man[i].name); man[i].count=0; }
Hale Waihona Puke // 遍历显示所有节点,循环链表没有表尾 void display_link(Josephus *head, int n){ Josephus *p; int i=0; for(p=head; i<n; p=p->next,i++) printf("%d %s %d\n", p->num, p->name,p->count); }

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;}。

C++编写的 约瑟夫环问题 代码

C++编写的 约瑟夫环问题 代码

程序源代码:#include <stdio.h>#include <malloc.h>#include<conio.h>#include <stdlib.h>#include<ctime>#define NULL 0typedef struct Node{int m;//密码int n;//序号struct Node *next;}Node,*Linklist;Linklist create(int z) //生成循环单链表并返回,z为总人数{int i,mm;Linklist H,r,s;H=NULL;printf("请按顺序依次为每个人添加密码:");for(i=1;i<=z;i++){printf("\ninput cipher=");scanf("%d",&mm);s=(Linklist)malloc(sizeof(Node));s->n=i;s->m=mm;printf("%d号的密码%d",i,s->m);if(H==NULL)//从链表的第一个节点插入{H=s;r=H;}else//链表的其余节点插入{r->next=s;r=s;//r后移}//for结束r->next=H;/*生成循环单链表*/return H;}void search(Linklist H,int m0,int z)//用循环链表实现报数问题{int count=1;//count为累计报数人数计数器int num=0;//num为标记出列人数计数器Linklist pre,p;p=H;printf("出列的顺序为:");while(num<z){do{count++;pre=p;p=p->next;}while(count<m0);{pre->next=p->next;printf("%d ",p->n);m0=p->m;free(p);p=pre->next;count=1;num++;}//while结束}void clean(){int system(const char *string);int inquiry;printf("请问需要清除上一次操作记录吗(1.清屏/2.不清屏)...?\n"); scanf("%d",&inquiry);if(inquiry ==1)system("cls");}void text(){int m0,z,i, choose,k=1; //k用来阻止第一次进入程序清屏操作Linklist H;bool chooseFlag=false;while(1){if(k!=1)clean();k++;while(!chooseFlag){printf(" ……………………欢迎进入约瑟夫环问题系统…………………… \n"); printf( "* 1.输入约瑟夫环数据 * \n"); printf(" * 2.什么是约瑟夫环 * \n"); printf(" * 3.退出系统 * \n"); printf("........................................................ \n"); printf("请输入相应的数字进行选择: ");scanf("%d",&choose);for(i=1;i<=4;i++){if(choose==i) { chooseFlag=true; break;}else chooseFlag=false;}if(!chooseFlag) printf("Error Input!\n");} //end while(!chooseFlag)if(choose==1) //if 开始{printf("Input how many people in it:");//z为总人数scanf("%d",&z);if(z<=30){H=create(z);//函数调用printf("\nInput the start code m0=");scanf("%d",&m0);search(H,m0,z);printf("\n\n\n");}else{printf("超过最大输入人数\n");break;}}else if(choose==2){printf("\n约瑟夫环问题:设有n个人,其编号分别为1,2,3,…,n,安装编号顺序顺时针围坐一圈。

约瑟夫环问题

约瑟夫环问题

约瑟夫环问题问题描述:有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;有了这个公式,问题就变得多了。

工作报告之约瑟夫环实验报告总结

工作报告之约瑟夫环实验报告总结

约瑟夫环实验报告总结【篇一:约瑟夫环实验报告】实验报告课程名称:数据结构实验名称:顺序表和链表的应用实验编号:实验一指导教师:一、实验目的(1)掌握线性表的基本操作(插入、删除、查找)以及线性表合并等运算在顺序存储结构、链式存储结构上的实现。

重点掌握链式存储结构实现的各种操作。

(2)掌握线性表的链式存储结构的应用。

二、实验内容与实验步骤(1)实验内容:实现约瑟夫环,约瑟夫环(joseph)问题的一种描述是:编号为1、2、3……n的n个人按照顺时针方向围坐一圈,每人持有一个密码(正整数)。

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

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

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

(2)抽象数据类型和设计的函数描述,说明解决设想。

首先定义一个链表,用其中的data项存储每个人的编号,用password项存储每个人所持有的密码,并且声明一个指针。

之后使用creatlist_cl函数来创建一个循环链表,在其中的data和password中存入编号和密码,最后使最后一个节点的next指向l,使其能够形成循环队列。

定义了函数display来显示链表当中的内容,以确定存储的数据没有错误。

定义了函数delete_l来实现约瑟夫环中依次删除的功能,依次比较,如果某个人所持的密码和m值相等,则删除这个结点,并且输出此时该结点的编号和密码,实现出列的功能。

(3)简短明确地写出实验所采用的存储结构,并加以说明。

该实验我主要采用的是线性表的链式存储结构,首先定义了链表的结构,其中包括data项和password项,分别存储每个人的编号和所持密码,还声明了指向下一个结点的指针,该指针可以连接各个结点,并且将最后一个结点的指针指向第一个结点使之成为一个循环链表。

三、实验环境操作系统:windows 7调试软件名称:vc++版本号:6.0上机地点:综合楼311四、实验过程与分析(1)主要的函数或操作内部的主要算法,分析这个算法的时、空复杂度,并说明设计的巧班级:学号:姓名:组号:实验成绩:批阅教师签字:实验日期:实验时间:妙之处。

约瑟夫环问题-数据结构实现代码

约瑟夫环问题-数据结构实现代码
}
if((q = (SCLNode *)malloc(sizeof(SCLNode)))==NULL) exit(1);
q->data = x;
q->next = p->next;
p->next = q;
return 1;
}
int SCLLDelete(SCLNode *head,int i,DataType *x)//删除一个指定位置的结点
for(i=1;i<=n;i++)
SCLLInsert(head,i,test[i-1]);
JesephRing(head,m,n);
printf("\n\n");
}
j++;
}
if(j!=i)
{
printf("取元素位置参数错!");
return 0;
}
*x = p->data;
return 1;
}
int SCLLNotEmpty(SCLNode *head)//判断链表非空否
{
if(head->next == head)
return 0; //为空返回0
else
{
SCLNode *p,*q;
int j;
p = head; j=0;
while(p->next!=head&&j<i-1)
{
p = p->next;
j++;
}
if(j!=i-1)
{
printf("删除位置参数出错");
return 0;
}
q = p->next;

约瑟夫问题的C++代码

约瑟夫问题的C++代码

#include<iostream>using namespace std;struct Node//定义节点的结构类型{int data;Node* next;};class CircularLinkedList//循环链表类{public:CircularLinkedList(){first=new Node;first->next=NULL;}CircularLinkedList(int n);//构建一个附有值的循环链表~CircularLinkedList();int Josephus(int num);//约瑟夫函数private:Node* first;};CircularLinkedList::CircularLinkedList(int n){first=new Node;Node * r=first;for(int i=1;i<=n;i++){Node* s=new Node;s->data=i;s->next=NULL;r->next=s;r=s;} //头插法初始化链表r->next=first; //最后一个元素的next志指向头结点}CircularLinkedList::~CircularLinkedList(){Node* p=first,*q;while(p->next!=first)//p指向最后一个结点时结束循环{q=p;p=p->next;delete q;}delete p;//删除头结点}int CircularLinkedList::Josephus(int num){Node* p=first,*q;if(num<=0)throw "输入错误!";while(first->next->next!=first){for(int i=1;i<num;i++) //p向后移动num位,指向要删除的元素的前一个结点{p=p->next;if(p==first) //若循环过程中出现p指向头结点,则跳过头结点{p=p->next;}}if(p->next==first) //若循环结束后p指向最后一个元素,则要跳过头结点,并让头结点的next指向要删除元素的下一个{p=first;q=p->next;p->next=q->next;//first->next=q->next;cout<<q->data<<" ";delete q;}else{q=p->next;p->next=q->next;cout<<q->data<<" ";delete q;}}cout<<endl;cout<<"最后一个数为:";return first->next->data;}void main(){int n,m;cout<<"请输入约瑟夫问题的人数和间隔人数:";cin>>n>>m;cout<<"依次删除:"<<endl;CircularLinkedList Josephus1(n);//创建的对象调用第二个构造函数cout<<Josephus1.Josephus(m)<<endl;}。

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分别表示)围坐在一张圆桌周围。

约瑟夫问题详解(CC++)

约瑟夫问题详解(CC++)

约瑟夫问题详解(CC++)Josephus 约瑟夫问题假设n个竞赛者排成一个环形,依次顺序编号1,2,…,n。

从某个指定的第1号开始,沿环计数,每数到第m个人就让其出列,且从下一个人开始重新计数,继续进行下去。

这个过程一直进行到所有的人都出列为止。

最后出列者为优胜者。

无论是用链表实现还是用数组实现来解约瑟夫问题都有一个共同点:要模拟整个游戏过程,不仅程序写起来比较麻烦,而且时间复杂度高达O(nm),当n,m非常大(例如上百万,上千万)的时候,几乎是没有办法在短时间内出结果的。

注意到原问题仅仅是要求出最后的胜利者的序号,而不是要模拟整个过程。

因此如果要追求效率,就要打破常规,实施一点数学策略。

为了讨论方便,先把问题稍微改变一下,并不影响原意:问题描述:n个人(编号0~(n-1)),从0开始报数,报到(m-1)的退出,剩下的人继续从0开始报数。

求胜利者的编号。

我们知道第一个人(编号一定是m%n-1) 出列之后,剩下的n-1个人组成了一个新的约瑟夫环(以编号为k=m%n的人开始): k k+1 k+2 ... n-2, n-1, 0, 1, 2, ... k-2并且从k开始报0。

现在我们把他们的编号做一下转换:k --> 0k+1 --> 1k+2 --> 2......k-2 --> n-2变换后就完完全全成为了(n-1)个人报数的子问题,假如我们知道这个子问题的解:例如x 是最终的胜利者,那么根据上面这个表把这个x变回去不刚好就是n个人情况的解吗?变回去的公式很简单:x'=(x+k)%n如何知道(n-1)个人报数的问题的解?显然,只要知道(n-2)个人的解就行了。

(n-2)个人的解呢?当然是先求(n-3)的情况---- 这显然就是一个倒推问题!递推公式:令f[i]表示i个人玩游戏报m退出最后胜利者的编号,最后的结果自然是f[n]递推公式f[1]=0;f[i]=(f[i-1]+m)%i; (i>1)有了这个公式,我们要做的就是从1-n顺序算出f[i]的数值,最后结果是f[n]。

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

C语言程序设计漫谈之从“约瑟夫问题”谈起

C语言程序设计漫谈之从“约瑟夫问题”谈起

从“约瑟夫问题”谈起约瑟夫问题是一个出现在计算机科学和数学中的问题。

在计算机编程的算法中,类似问题又称为约瑟夫环。

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

然而Josephus 和他的朋友并不想自杀。

为避免与其他39个决定自杀的犹太人发生冲突,Josephus要他的朋友先假装遵从,他将朋友与自己安排在第16个与第31个位置,于是逃过了这场死亡游戏。

17世纪的法国数学家加斯帕在《数目的游戏问题》中讲了这样一个故事:15个教徒和15 个非教徒在深海上遇险,必须将一半的人投入海中,其余的人才能幸免于难,于是想了一个办法:30个人围成一圆圈,从第一个人开始依次报数,每数到第九个人就将他扔入大海,如此循环进行,直到仅余15个人为止。

问怎样的排法,才能使每次投入大海的都是非教徒。

【例1】约瑟夫问题。

N个人围成一圈,从某个人开始,按顺时针方向从1开始依次编号。

从编号为1的人开始顺时针“1,2,…M”报数,报到M的人退出圈子。

这样不断循环下去,圈子里的人将不断减少。

由于人的个数是有限的,因此最终会剩下一个人,该人就是优胜者。

输入N和M,输出出圈顺序。

例如,N=6、M=5,出圈的顺序是:5,4,6,2,3,1。

(1)编程思路。

为输出出圈顺序,采用一个数组来进行模拟。

定义int circle[N+1],并按circle[i]=i+1的方式赋予各元素初值。

该值代表两个含义:1)值为0,代表编号i+1的人不再圈中;2)值非0,代表圈中第i个位置的人编号为i+1。

定义变量i代表报数位置的流动,i的初值为0,代表编号为1的人的位置,i的变化方式为:i=(i+1)%(n),即0-->1-->2……->n-1 ->0-->1……。

循环链表长度

循环链表长度

循环链表长度介绍循环链表是一种特殊的链表结构,它与普通链表的区别在于尾节点指针不为null,而是指向链表的头节点,形成一个循环链表。

循环链表可以解决一些特定的问题,比如在某些场景下需要循环遍历链表或者需要快速访问链表的最后一个节点。

在这篇文章中,我们将重点讨论循环链表的长度计算方法,以及一些相关的问题和应用场景。

计算循环链表长度的方法计算循环链表的长度可以通过遍历链表的方式来实现,也可以通过记录链表的节点数来实现。

下面将介绍两种方法。

方法一:遍历链表遍历链表是一种直观的方法,通过从链表的头节点开始,依次遍历下一个节点,直到回到头节点。

在遍历的过程中,我们可以用一个计数器来记录遍历的节点数,最终的计数器值就是循环链表的长度。

具体的实现步骤如下: 1. 初始化计数器count为0; 2. 从链表的头节点开始,依次遍历下一个节点,每遍历一个节点,计数器count加1; 3. 当遍历到头节点时,停止遍历; 4. 返回计数器count的值,即为循环链表的长度。

遍历链表的代码示例:count = 0current = headwhile True:count += 1current = current.nextif current == head:breakreturn count方法二:记录节点数在循环链表中,每个节点都可以通过其下一个节点来访问到,因此可以通过每个节点的next指针来记录链表的节点数。

具体做法是,从链表的头节点开始,依次遍历下一个节点,每访问到一个节点,节点数加1,直到再次回到头节点为止。

具体的实现步骤如下: 1. 初始化节点数为1; 2. 从链表的头节点开始,依次遍历下一个节点,每访问到一个节点,节点数加1; 3. 当节点的next指针指向头节点时,停止遍历; 4. 返回节点数,即为循环链表的长度。

记录节点数的代码示例:count = 1current = head.nextwhile current != head:count += 1current = current.nextreturn count循环链表长度的应用场景循环链表长度的计算方法可以在一些特定的问题中得到应用。

数据结构——约瑟夫环

数据结构——约瑟夫环

数据结构——约瑟夫环今⽇⼀⾔:谢谢你,成为我前进的理由。

——《⾔叶之庭》数据结构 —— 约瑟夫环这是⽤链表实现的,约瑟夫环的规则是:总数为N的同学围成⼀个圆环,并将这些同学从1开始编号,游戏开始时,约定好⼀个数字K,从1号同学开始轮着叫号,当叫到K号时,该同学淘汰,下⼀位同学从1开始重新叫号,只要叫到K号即淘汰,留下来的最后⼀位同学赢得游戏。

C语⾔实现/*********************************************************************************** 约瑟夫环* create: 2020年5⽉24⽇ 22点22分* author: LOS(⼩鱼)** *******************************************************************************/#include<stdio.h>#include<stdlib.h>/********************************************************************************** 链表需要********************************************************************************/typedef struct Elem{int value;struct Elem *prev,*next;}Elem;struct{Elem elems[200];int size;} Elems; // 全部的链表数据存储在这⾥(不销毁, 但会覆盖)// 定义链表结构typedef struct {struct Elem *first;struct Elem *last;int size;} LinkList;// 初始化链表void initLinkList( LinkList *list ){list->size = 0;}// 获取表长int getSizeL(LinkList *list){return list->size;}void addFirst(LinkList *list,Elem *elem){if( !getSizeL(list) ){list->first = elem;list->last = elem;}else {elem->next = list->first;list->last->next = elem;list->first->prev = elem;list->first = elem;}list->size++;}// 添加元素void addLast(LinkList *list,Elem *elem){if( !getSizeL(list) ){list->first = elem;list->last = elem;} else {elem->prev = list->last;elem->next = list->first;list->last->next = elem;list->first->prev = elem;list->last = elem;}list->size++;}Elem * getElem(LinkList *list, int index){int i ;Elem *elem;// 逐项访问if ( index > list->size/2 ){elem = list->last;for ( i = list->size-1 ; i >= index ; i-- ){if( i == index ){return elem;}elem = elem->prev;}} else {elem = list->first;for ( i = 0 ; i <= index ; i++ ){if( i == index ){return elem;}elem = elem->next;}}}// 移除元素void removeIndexL(LinkList *list, int index){ int i;Elem *elem = list->first;int flag = 0;for ( i = 0 ; i <= index ; i++ ){if( i == index ){elem->prev->next = elem->next;elem->next->prev = elem->prev;if( list->first == elem ){list->first = elem->next;}if( list->last == elem ){list->last = elem->prev;}flag = 1;}elem = elem->next;}if(!flag) printf("没能完成任务\n"); list->size--;}void removeElemL(LinkList *list, Elem *e){ int i;Elem *elem = list->first;int flag = 0;for ( i = 0 ; i < list->size ; i++ ){if( elem == e ){elem->prev->next = elem->next;elem->next->prev = elem->prev;list->first = elem->next;}if( list->last == elem ){list->last = elem->prev;}flag = 1;}elem = elem->next;}if(!flag) printf("没能完成任务\n");list->size--;}/********************************************************************************** 链表需要********************************************************************************/Elem *createElem( int value ){Elem *p = Elems.elems+Elems.size;p->value = value;Elems.size++;if( Elems.size == 200 ) Elems.size = 0; // 注意不能超过200,否则数据错误return p;}void main(){LinkList list;int n,k,i,count;printf("请输⼊参与游戏的总⼈数:");scanf("%d",&n);fflush(stdin);printf("请输⼊淘汰的间隔数:");scanf("%d",&k);fflush(stdin);initLinkList(&list);for ( i = 0 ; i < n ; i++ ){Elem *elem = createElem(i+1);addLast(&list,elem);}printf("游戏开始......\n");count = 0;while(list.size>1){count = (count+k-1)%list.size;printf("%d号同学被淘汰.\n",getElem(&list,count)->value);removeIndexL(&list,count);}printf("最后的赢家是 --> %d号同学!\n",st->value);}运⾏结果请输⼊参与游戏的总⼈数:10请输⼊淘汰的间隔数:3游戏开始......3号同学被淘汰.6号同学被淘汰.9号同学被淘汰.2号同学被淘汰.7号同学被淘汰.1号同学被淘汰.8号同学被淘汰.5号同学被淘汰.10号同学被淘汰.最后的赢家是--> 4号同学!--------------------------------Process exited after 2.205 seconds with return value 27请按任意键继续. . .。

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

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

⽤顺序表解决约瑟夫环问题⼀、实验题⽬:约瑟夫环问题:设编号为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;}。

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

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

约瑟夫环问题的两种解法(循环链表和公式法)问题描述这⾥是数据结构课堂上的描述: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),显然,这不是⼀个好的算法。

循环队列解决约瑟夫问题

循环队列解决约瑟夫问题

循环队列解决约瑟夫问题有n个⼈围成⼀圈,从第1个⼈开始,1,2,…,m报数,报⾄m出局,余下的⼈继续从1,2,…,m报数,重复之前的流程,要求:求出被淘汰编号的序列,及最后剩下的⼀⼈是原来的第⼏号?(要求:⽤循环队列解决该问题。

)#ifndef STATUS_H#define STATUS_H#define TRUE 1#define FALSE 0#define OK 1#define ERROR 0#define INFEASIBLE -1#define OVERFLOW -2typedef int Status;#endif#include <iostream>using namespace std;#include "Status.h"typedef int ElemType;typedef struct{ElemType *base;int front;int rear;int MAXSIZE;}SqQueue;Status InitQueue(SqQueue& Q,int n) //初始化队列{Q.base = new ElemType[100];if(!Q.base){cout << "创建队列失败!";return ERROR;}Q.front=Q.rear=0;Q.MAXSIZE = n+1;//MAXSIZE是总⼈数+1,是为了留出⼀个空位置来放置rearreturn OK;}void QueueTraverse(SqQueue Q) //遍历队列{int i;i=Q.front;while(i!=Q.rear){cout<<Q.base[i]<<"";i=(i+1)%Q.MAXSIZE;}cout<<endl;}Status EnQueue(SqQueue& Q,ElemType e) //⼊队{if((Q.rear+1)%Q.MAXSIZE==Q.front){cout << "队列已满!";return ERROR;}Q.base[Q.rear] = e;Q.rear = (Q.rear+1)%Q.MAXSIZE;return OK;}Status DeQueue(SqQueue& Q,ElemType& e) //出队{if(Q.front==Q.rear){cout << "队列为空!";return ERROR;}e = Q.base[Q.front];Q.base[Q.front] = 0;Q.front = (Q.front+1)%(Q.MAXSIZE-1);//总⼈数为MAXSIZE-1return OK;}int main(){int n,m,i=1;SqQueue Q;ElemType e;cout << "请输⼊n个⼈(n<=100):";do{cin >> n;if(n>100 || n<1){cout << "输⼊⼈数错误!请重新输⼊:";}}while(n>100 || n<1);InitQueue(Q,n);while(i<=n)//⼊队操作{EnQueue(Q,i);i++;}cout << "\n此时的序列顺序为:"<<endl;QueueTraverse(Q);cout << "\n请输⼊第m个⼈出队(1<=m<=n):";do{cin >> m;if(m>n || m<1){cout << "m输⼊错误!请重新输⼊:";}}while(m>n || m<1);cout << endl;int Count = n;//⽤来记录剩下的⼈数while(Count != 1){i = 1;//i⽤来控制是第⼏个⼈报数while(i != m)//当i的值不等于m的值时{Q.front = (Q.front+1)%(Q.MAXSIZE-1);//总⼈数为MAXSIZE-1if(Q.base[Q.front] != 0)//当此时不为0的话,i++⽤来控制第⼏个⼈{i++;}}DeQueue(Q,e);while(Q.base[Q.front] == 0)//当此时为0的时候,循环找到下⼀个不为0的位置{Q.front = (Q.front+1)%(Q.MAXSIZE-1);}cout << "序号:" << e << "出局!\n";Count--;}DeQueue(Q,e);cout << "\n最后⼀个是:" << e << endl;return0;}1.有n个⼈围成⼀圈,从第1个⼈开始,1,2,…,m报数,报⾄m出局,余下的⼈继续从1,2,…,m报数,重复之前的流程,要求:求出被淘汰编号的序列,及最后剩下的⼀⼈是原来的第⼏号?(要求:⽤循环队列解决该问题。

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

约瑟夫环c语言算法实现:
#include <stdio.h>
#include <stdlib.h>
#define N 10 //节点个数
#define NSTART 1 //开始计数的节点序号#define NDELETE 4 //计数的个数
//声明链表结构体
typedef struct Node
{ int data;
struct Node *next;
}Node;
//创建数据为n 的一个节点
Node *Create_Node(int n){
Node *p;
p=(Node*)malloc(sizeof(Node));
p->data=n;
p->next=NULL;
return p;
}
//创建节点数为num 的数据连续的单链表
Node *Create_Linklist(Node *head,int num){
int i;
Node *p,*rear;
printf("链表中的数据为:\n");
for(i=1;i<=num;i++){
p=Create_Node(i);
//当链表为空时,新节点接在头结点之后
if(head==NULL){
head=p;
rear=p;
head->next=p;
p->next=NULL;
}
//当链表不为空,在最后一个节点之后接上新的节点else{
rear->next=p;
rear=p;
}
//逐个打印链表数据,检验创建是否成功
printf("%d\n",p->data);
}
//将单链表首尾相连,成为循环链表
rear->next=head;
return head;
}
//删除节点,并打印删除节点的数据
void *delete_Node(Node *pHead,int Nstart,int Ndelete)
{
int i,cnt=1; //cnt用来计数,计算每个需要删除的节点位置
Node *p,*s;
p=pHead;
for(i=1;i<Nstart;i++){ //寻找开始的节点
p=p->next;}
while(p->next!=p){
for(i=1;i<Ndelete;i++){
s=p; //记下要删除的节点前一个节点的位置
p=p->next;
}
s->next=p->next; //删除了p此刻的节点
printf("第%d个删除的为第%d个\n",cnt,p->data); //打印删除结果
free(p); //删除节点
cnt++;
p=s->next;//删除处的下一个节点作为下一轮开始的起点
}
//只剩一个节点时,这个节点就是最后一个删除的,也是头结点
printf("第%d个删除的为第%d个\n",cnt,p->data);
free(p); //释放头结点
pHead=NULL;
}
int main()
{
Node *head = NULL,*p;
int num=N;
int Nstart=NSTART;
int Ndelete=NDELETE;
//printf("请输入要创建的节点数、开始的节点序号和报数个数:");
//scanf("%d %d %d\n",&num,&Nstart,&Ndelete);
//调用生成函数生成循环链表
p=Create_Linklist(head,num);
//调用删除函数依次去除节点并打印去除的节点的数据
delete_Node(p,Nstart,Ndelete);
return 0;
}。

相关文档
最新文档