约瑟夫环

约瑟夫环

1.问题描述
(1)问题描述 设有编号为 1,2,…,n 的 n(n>0)个人围成一个圈,每个人持有一个密码 m。 从第一个人开始报数,报到 m 时停止报数,报 m 的人出圈,再从他的下一个人 起重新报数,报到 m 时停止报数,报 m 的出圈,……,如此下去,直到所有人 全部出圈为止。当任意给定 n 和 m 后,设计算法求 n 个人出圈的次序。 (2)基本要求 建立模型,确定存储结构。 对任意 n 个人,密码为 m,实现约瑟夫环问题。 出圈的顺序可以依次输出,也可以用一个数组存储。 (3)思考: 采用顺序存储结构如何实现约瑟夫环问题? 如果每个人持有的密码不同,应如何实现约瑟夫环问题?
2.数据结构设计
该题考虑用链表来进行,选择性删除人以后还得回到起点再次进行循环删除,
故考虑利用循环链表进行实验

3.算法设计
系统规定的功能设计的算法有:建立循环链表,删除结点

head=rear=(struct shushu*)malloc(sizeof(struct shushu));
		//建立头结点 
	for(i=1;i<n;i++)
	{
		p=(struct shushu*)malloc(sizeof(struct shushu));
		rear->data=i;
		rear->next=p;
		rear=p;
	}//利用循环建立链表 
p->data=n;
	p->next=head;//将头结点和最后一个结点连接形成循环链表 
	head=p;
		for(i=1;i<=n;i++)//n个人都要输出 
	{
		for(j=1;j<k;j++)//利用给定的密码进行循环找人并删除 
			p=p->next;
			rear=p->next;
			p->next=rear->next;//找到对应结点删除
			printf("%4d",rear->data); 
			free(rear);
	}
	head=p;

4.界面设计
程序功能较为简单,故输出界面只有一个

程序中利用判断读入为两个数则一直进行,当需要退出时随意输入一个非数字字符即可。
6.实验收获及思考
写约瑟夫环加深了对循环链表的理解,在写程序中也遇见一些问题但主要语句的错误改正即可运行,能正确画出链表执行过程。
思考题:
(1)当每个人密码不同时在链表中再加入一个数据域存储密码,每次删除结点前留下该密码作为新的循环数据找到并删除。

typedef struct node{
	int number;//编号 
	int password;//个人密码 
	struct node *next;
} LNode,*LinkList;
void insertList(LinkList *list,LinkList q,int e1,int e2){
	LinkList p;
	p=(LinkList)malloc(sizeof(LNode));
	p->number=e1;
	p->password=e2;
	if(!*list){
		*list=p;
		p->next=NULL;
	}
	else{
		p->next=q->next;
		q->next=p;
	}
}//建立链表 
void CreatJoseph(LinkList *jsp,int n)
{
	LinkList q=NULL,list=NULL;
	int i, e;
	printf("请输入每个人的密码\n");
	for(i=0;i<n;i++){
		scanf("%d",&e);//读入每个人密码 
		insertList(&list,q,i+1,e);
		if(i==0) q=list;
		else q=q->next;
	}
	q->next=list;
	
	*jsp=list;
}
void exJoseph(LinkList *jsp,int m)
{
	LinkList p,q;
	int i;
	q=p=*jsp;
	while(q->next !=p) q=q->next;//将q指向开始结点的前一个结点 
	printf("约瑟夫环的顺序\n");
	while(p->next !=p){
		for(i=0;i<m-1;i++)
		{
			q=p;
			p=p->next;
		}
		q->next = p->next;//删除结点 
		printf("%d ",p->number);
		m=p->password;//记录下一个人密码作为新密码 
		free(p);
		p=q->next;
	}
	printf("%d\n",p->number);
}

(2)顺序链表
当找到对应结点时不删除而直接将该结点令为0,以后读取时直接跳过该结点即可
7.附录


```c
#include<stdio.h>
#include<stdlib.h>
struct shushu 
{
	int data;
	struct shushu *next;
};//设定链表中元素为数据域和指针域
int main()
{
	int i,j,n,k;
	struct shushu *head,*p,*rear;
	printf("输入总人数和密码\n");
	while(scanf("%d%d",&n,&k)==2)//实现程序的可持续输入,当输入不为数字时则退出
{
	if(n==0)
	{
		printf("怎么没有人来啊\n");
	}//当人数为0 时不运行
	else 
	if(n==1)
	{
		printf("就一个人,你搞笑呢,算了,给你自己玩的机会\n");
		printf("%d",n);
	}//人数为1时直接输出 
	else
	{
		head=rear=(struct shushu*)malloc(sizeof(struct shushu));
		//建立头结点 
	for(i=1;i<n;i++)
	{
		p=(struct shushu*)malloc(sizeof(struct shushu));
		rear->data=i;
		rear->next=p;
		rear=p;
	}//利用循环建立链表 
	p->data=n;
	p->next=head;//将头结点和最后一个结点连接形成循环链表 
	head=p;
	printf("\n哎,可怜你还是逃不掉啊,算了,别强求吧\n");
	for(i=1;i<=n;i++)//n个人都要输出 
	{
		for(j=1;j<k;j++)//利用给定的密码进行循环找人并删除 
			p=p->next;
			rear=p->next;
			p->next=rear->next;//找到对应结点删除
			 
			printf("%4d",rear->data);
			if(i%5==0)printf("\n");//5个数字为一组输出 
			free(rear);
	}
	head=p;
	 } 
printf("\n---------------------------------\n");	
printf("输入人数和密码\n");
}
return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值