约瑟夫环问题
作者:互联网
问题描述
设有n个人围坐在圆桌周围,现从某个位置m(1≤m≤n)上的人开始报数,报数到k的
人就站出来。下一个人,即原来的第k+1位置上的人又从1开始报数,再报数到k的人站出来。依此重复下去,直到全部的人都站出来为止。试设计一个程序求出出列序列。
数据结构
循环单链表
算法分析与设计
这是一个使用循环链表的经典问题。因为要不断地出列,采用链表的存储形式能更好地模拟出列的情况。本算法即采用一个不带表头的循环链表来处理约瑟夫环问题,其中的n个人用n个结点来表示。程序有两个函数:
➢ 函数Create_ clist(): 用来创建-一个不带头结点的单循环链表,clist 为头指针,创建结束后让全局指针joseph指向循环链表的头。
➢ 函数Joseph():实现出列。
Joseph算法伪代码描述如下:
{
初始化工作指针p=joseph;
循环做p=p->next,直到p指向第m个结点(从m报数);
while p
{
循环做 p=p->next,直到p指向第k-1个结点:
q=p->next,输出结点q的编号(输出数到k的人);
if(p->next==p即链表中只有-一个结点)(数到k的人出列)
删除p;
else删除q;
}
链表指针clist置空;
}
操作示意图
在此算法中,每次找出需出列的结点,要经过k次循环移动定位指针。全部结点出列
需经过n个k次循环。因此,本算法的时间复杂度为O(k*n)。在实际问题的处理中,有许多与约瑟夫问题类似,都可以采用此方法完成。
程序实现
#include<stdio.h>
#include<stdlib.h>
#include<conio.h>
#define OVERFLOW -1
typedef int Elemtype;//定义数据元素类型
typedef struct Conode
{
Elemtype data;
struct Cnode *next;
}CNode;
CNode *joseph;//定义一个全局变量
//创建单循环链表
int Create_clist(CNode *clist,int n)
{
CNode *p,*q;
int i;
clist=NULL;
for(i=n;i>=1;i--)
{
p=(CNode *)malloc(sizeof(CNode));
if(p==NULL) return OVERFLOW;//存储分配内存失败
p->data=i;
p->next=clist;
clist=p;
if(i==n) q=p;//用q指向链表的最后一个结点
}
q->next=clist;//把链表的最后一个结点的链域指向链表的第一个节点,构成循环链表
joseph=clist;//把创建好的循环链表头指针赋给全局变量
return 1;
}
int Joseph(CNode *clist,int m,int n,int k)
{
int i;
CNode *p,*q;
if(m>n) return -1;//起始位置错误
if(!Create_clist(clist,n))
return -1;//循环链表创建失败
p=joseph;//指向创建好的循环链表
for(i=1;i<m;i++)
p=p->next;//p指向m位置的节点
while(p)
{
for(i=1;i<k-1;i++)
p=p->next;//找出k-1个结点
q=p->next;
printf(" %d",q->data);//输出应出列的的节点
if(p->next==p)
p=NULL;//删除最后一个结点
else{
p->next=q->next;
p=p->next;
free(q);
}
}
clist=NULL;
return 1;
}
int main()
{
int m,n,k;
CNode *clist;
clist=NULL;
printf("\n 请输入围坐在圆桌周围的人数n:");
scanf("%d",&n);
printf(" 请输入第一次开始报数人的位置m:");
scanf("%d",&m);
printf("你希望报数到第几个数的人出列?");
scanf("%d",&k);
Create_clist(clist,n);
printf("出列结果如下:\n");
Joseph(clist,m,n,k);
printf("\n");
return 0;
}
标签:链表,结点,int,next,问题,clist,约瑟夫,CNode 来源: https://blog.csdn.net/weixin_44895651/article/details/105903697