约瑟夫环(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实验报告约瑟夫斯环问题

约瑟夫斯(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)。
4.简述每一部分的对象、目的和要求:(1)主函数部分:对象:链表;目的:创建新链表;要求:将该链表初始化。
(2)被调函数部分:对象:结构体;目的:创建循环链表并且模拟约瑟夫斯问题;要求:让链表首尾相接,并且释放原来单链表的头结点空间。
通过该函数的调用,依次输出各结点的编号,并且符合规则。
二.需求分析1.程序所能达到的基本可能:该程序用循环链表来模拟n个人顺时针围坐一圈,用链表中的每一个结点代表一个人,结点结构体中设置两个变量,分别存放其编号以及密码。
在输入初始密码后,对该链表进行遍历,直到遍历到第m个结点,释放其空间,使其出列。
然后用被释放空间结点的密码值作为新的密码值,重复上述过程,直至所有结点被释放空间出列,链表成为空链表。
2.输入输出形式及输入值范围:程序运行后显示提示信息:"Please input a data:",提示用户输入密码信息,在输入达预定次数后自动跳出该循环,同时循环链表创建成功,在主函数中有相应的输出给予检验。
然后程序显示提示信息:"Please input the number m:",提示用户输入初始密码,程序执行结束后会输出相应的出列结点的顺序,亦即其编号。
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,安装编号顺序顺时针围坐一圈。
约瑟夫环数据结构C语言版

{tail = tail->next;} } p = tail->next; printf("%d,", p->num); tail->next = p->next; code = p->code; free(p); p = NULL; --num; } } printf("%d.",tail->num); free(tail); tail = NULL; return; }
3. 程序执行的命令包括: (1)构造链表;(2)输入数据;(3)执行报数,储存出列人的序号,删除出列人 的信息以及把出列人的密码赋给 m;(4)结束。
4. 测试数据 n=7,7 个人的密码依次为:3,1,7,2,4,8,4,首先 m 值为 6,则这正确
的出列顺序为 6,1,4,7,2,3,5。
示范代码:(Tc 2.0 编译) #include "stdio.h" #include "alloc.h" #include "conio.h"
int num = 0,code = 0; scanf("%d%d",&num, &code); {
SeqList * tail = NULL; tail=Creat(num); OutQueue(tail, num, code); } } getch();
return(1); }
SeqList * Creat(int num) {
typedef struct Node {
int num; int code; struct Node * next; }SeqList;
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语言实现约瑟夫环问题解析

(一)基本问题1.问题描述设有编号为1,2,…,n的n(n>0)个人围成一个圈,每个人持有一个密码m。
从第一个人开始报数,报到m时停止报数,报m的人出圈,再从他的下一个人起重新报数,报到m 时停止报数,报m的出圈,……,如此下去,直到所有人全部出圈为止。
当任意给定n和m后,设计算法求n个人出圈的次序。
建立模型,确定存储结构。
对任意n个人,密码为m,实现约瑟夫环问题。
2.数据结构设计首先,设计实现约瑟夫环问题的存储结构。
由于约瑟夫环问题本身具有循环性质,考虑采用循环链表,为了统一对表中任意结点的操作,循环链表不带头结点。
将循环链表的结点定义为如下结构类型:struct Node{int data;Node *next;};其次,建立一个不带头结点的循环链表并由头指针first指示3.算法设计1、工作指针first,r,s,p,q初始化2、输入人数(n)和报数(m)3、循环n次,用尾插法创建链表Node *q;for(int i=1;i<=n;i++){Node *p;p=new Node;p-> data =i;p->next=NULL;if(i==1) L=q=p;else{q->next=p;q=q->next;}}q->next=L;if(L!=NULL){return(L);}4、输入报数的起始人号数k;5、Node *q = new Node;计数器初始化i=1;6、循环n次删除结点并报出位置(其中第一个人后移k个)当i<n时移动指针m-2次p=p->next;删除p结点的后一结点qq=p->next;p->next=q->next;*L = p->next;报出位置后Delete q;计数器i++;运行流程图代码和相关解释#include<iostream>using namespace std;struct Node//循环节点的定义{int data;//编号Node *next;};Node *CreateList(Node *L,int &n,int &m);//建立约瑟夫环函数void Joseph(Node *L,int n,int m);//输出每次出列号数函数Node *DeleteList(Node **L,int i,Node *q);//寻找每次出列人的号数int LengthList(Node *L);//计算环上所有人数函数void main()//主函数//在主函数中,完成人数(n)和报数(m)的输入和工作指针的初始化{Node *L;L=NULL;//初始化尾指针int n, m;cout<<"请输入人数N:";cin>>n;//环的长度if(n<1){cout<<"请输入正整数!";}//人数异常处理else{cout<<"请输入所报数M:";cin>>m;if(m<1){cout<<"请输入正整数!";}//号数异常处理else{L=CreateList(L,n,m);//重新给尾指针赋值Joseph(L,n,m);}}system("pause");}Node *CreateList(Node *L,int &n,int &m)//建立一个约瑟夫环(尾插法){Node *q;for(int i=1;i<=n;i++){Node *p;p=new Node;p->data=i;p->next=NULL;if(i==1) L=q=p;//工作指针的初始化else{q->next=p;q=q->next;}}q->next=L;if(L!=NULL){return(L);}//返回尾指针else cout<<"尾指针异常!"<<endl;//尾指针异常处理}void Joseph(Node *L,int n,int m)//输出每次出列的人{int k;cout<<"请输入第一个报数人:";cin>>k;if(k<1||k>n){cout<<"请输入1-"<<n<<"之间的数"<<endl;} else{cout<<"\n出列顺序:\n";for(int i=1;i<n;i++){Node *q = new Node;if(i==1) q=DeleteList(&L,k+m-1,q);//第一个出列人的号数else q=DeleteList(&L,m,q);cout<<"号数:"<<q->data<<endl;delete q;//释放出列人的存储空间}cout<<"最后一个出列号数是:"<<L->data<<endl;;//输出最后出列人的号数}}Node *DeleteList(Node **L,int i,Node *q) //寻找每次出列的人{if(i==1) i+=LengthList(*L);//顺序依次出列情况的处理方式Node *p;p=*L;int j=0;while(j<i-2) {p=p->next;j++;}q = p->next;p->next=p->next->next;*L = p->next;return(q);}int LengthList(Node *L)//计算环上的人数{if(L){cout<<"尾指针错误!"<<endl;}//异常处理else{int i=1;Node *p=L->next;while(p!=L){i++;p=p->next;}return(i);}}复杂度分析:for(int i=1;i<=n;i++){Node *p;p=new Node;p->number=i;p->next=NULL;if(i==1) L=q=p;else{q->next=p;q=q->next;}时间复杂度:O(n)if(i==1) i+=LengthList(*L);Node *p;p=*L;int j=0;while(j<i-2) {p=p->next;j++;}q = p->next;p->next=p->next->next;*L = p->next;return(q);时间复杂度:O(n2)算法的空间复杂度:O(n2)4.界面设计5. 运行、测试与分析(二)采用顺序存储结构如何实现约瑟夫环问题代码和解释#include <stdlib.h>#include<stdio.h>#include<malloc.h>#define MaxSize 50typedef char ElemType;typedef struct Seqlist{//线性表顺序存储结构定义ElemType *elem[MaxSize];//存放顺序表数据元素int length;//当前长度}*JSeqlist;//线性表存储结构类型名JSeqlist Int_SeqList(void){//顺序表初始化JSeqlist L;L=(JSeqlist)malloc(sizeof(struct Seqlist));if(L!=NULL)L->length=0;elseprintf("超出范围!!");return L;}ElemType *Locate_SeqList(JSeqlist L,int p){//查找线性表中下标为P的元素if(p>=0&&L->length)return(L->elem[p]);else{printf("顺序表中不存在相关元素");return NULL;}}int Insert_SeqList(JSeqlist L,int i,ElemType *x){//在顺序表中指定元素前插入Xint j;if(L->length==MaxSize)//L.length是最后一个元素的位置{printf("线性表已满,无法进行插入操作!!!!\n");return 0;}if(i<0||i>L->length){printf("插入位置不对,超出顺序表长度\n");return 0;}if(i==0){L->elem[i]=x;L->length=L->length+1;return 1;}for(j=L->length;j>=i;j--){L->elem[j]=x;}L->length++;return 1;}int Delete_JSeqlist(JSeqlist L,int i){//在顺序表中删除第i个元素int j;if(i<0||i>L->length-1){printf("删除位置不对,超出顺序表的长度啦\n");return 0;}for(j=i;j<L->length-1;j++)L->elem[j]=L->elem[j+1];L->length--;return 1;}void josephus(JSeqlist L,int start,int m){//josephus问题求解的非常牛逼的函数int s,i;ElemType *w;s=start-1;for(i=L->length;i>0;i--){s=(s+m-1)%i;w=Locate_SeqList(L,s);printf("出列人员为:%s\n",w);Delete_JSeqlist(L,s);}}int main (void){JSeqlist Josephus;int n,m,i,k,s;Josephus=Int_SeqList();//顺序表初始化printf(" 约瑟夫环问题顺序表求解_愚人节特别版\n\n");printf("请输入本问题中总人数m=");scanf("%d",&n);printf("请输入本问题开始人员的位置S=");scanf("%d",&s);printf("请输入本问题的计数值m=");scanf("%d",&m);printf("请输入本问题中这些人的名字\n");for(i=0;i<n;i++){printf("第%d位置的人员的名字为:",(i+1));Josephus->elem[i]=(ElemType *)calloc(10,sizeof(char));scanf("%s",Josephus->elem[i]);k=Insert_SeqList(Josephus,i,Josephus->elem[i]);if(k==0)exit(1);}josephus(Josephus,s,m);free(Josephus);getchar();return 0;}运行结果(三)密码不同#include <iostream.h>struct CList{int password;int number;struct CList *next;};typedef struct CList CNode;typedef CNode *CLink;CLink CreateList(int length){CLink head;CLink before;CLink new_node;int i;head=new CNode;if(head==NULL)return NULL;cout << "Please Input Password 1 :" << endl;cin >> head->password;head->number=1;head->next=NULL;before=head;for(i=1;i<length;i++){new_node=new CNode;if(new_node == NULL)return NULL;new_node->number = i+1;cout << "Please Input Password " << new_node->number << ":" <<endl;cin >> new_node->password;new_node->next = NULL;before->next=new_node;before=new_node;}new_node->next =head;return head;}int main(){CLink head;CLink ptr,back,last;int i,j,m,n;cout << "Please Input the Number of Persons: " << endl;cin >> n;cout << "Please Input the First Password M: " << endl;cin >> m;head=CreateList(n);ptr=head;for(i=0;i<n;i++){for(j=0;j<m-1;j++){back=ptr;//定位最后一个数的接点赋值给backptr=back->next;}cout <<"第"<<i+1<<"个出列的编号为:"<<ptr->number<<endl;m=ptr->password;if(ptr==head){last=head;while(last->next!=head)last=last->next;last->next=head->next;delete ptr;ptr=last->next;head=ptr;}else{back->next=ptr->next;delete ptr;ptr=back->next;}}return 0;}运行结果(三)心得体会:1.编程是个很细致的工作,尤其是在写顺序表的时候,涉及的函数很多,函数名中最初为了看在清晰,涉及成单词首字母是大写的,但是后来在函数调用的时候,就忘记了最初命名的时候是大写的了,导致编译的时候不能识别。
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……。
C语言数组实现约瑟夫环问题,以及对其进行时间复杂度分析

C 语⾔数组实现约瑟夫环问题,以及对其进⾏时间复杂度分析尝试表达本⼈试着去表达约瑟夫环问题:⼀群⼈围成⼀个圈,作这样的⼀个游戏,选定⼀个⼈作起点以及数数的⽅向,这个⼈先数1,到下⼀个⼈数2,直到数到游戏规则约定那个数的⼈,⽐如是3,数到3的那个⼈就离开这个游戏;按这样的规则,剩下⼀个⼈,游戏就结束,这个⼈就为赢家。
(读者可以试着表达,不认同,直接忽略)抽象分析这个⼈就是⼀个数据个体,数据结点,数据元素。
上⾯产⽣的数据结构为:单⽅向循环的链。
可以⽤链表实现,也可以⽤数组来实现。
链表到数组的迁移⼈(数据元素、数据结点、数据个体)结点关系(结构关系结点移动)范型“指针”定义:能够定位到下⼀个结点(变)“指针“移到下⼀个结点拿到下⼀个结点的”指针“即可,⼀般都有作“移动”变量,移动变量变,就相当于移动。
删除结点数组连续的数组元素(基本数据类型,机构体)数组元素⾥⾯保存有下个结点元素的数组元素下标position 。
arrayname 固定的,只要给出position ,就可以算是定位到数组元素≈poisiton []move =array[move]元素内容 = -1(数组的⼤⼩固定)链表离散的链表结点(结构体)结构体⾥⾯保存有下⼀个结点的指针node* nextpoiter 直接定位到结点,在结合常员变量,就可以拿到数据=poiter ->move = move ->next销毁画图分析:代码实现:#include<stdio.h>#include<stdlib.h>/*Function:遍历数组实现的约瑟夫环。
traverse_joseph_circle_array*param:int[] array,int tail*return: void* 假设是⽤数组实现的约瑟夫环链⼀定存在。
* */void traverse_joseph_circle_array (int array[], int tail ){//数组保存的是下个结点的“指针”,只不过这个指针要通过array 才能够拿到结点的元素,因为array 是固定的,只要变换指针就能够变换结点。