C语言——经典约瑟夫环问题(循环链表)

题目要求:


已知n个人(以编号1,2,3...n分别表示)围坐在一张圆桌周围。
从编号为k的人开始报数,数到m的那个人自杀;他的下一个人又从1开始报数,
数到m的那个人又出列;依此规律重复下去,请问:最后一个存活的人编号是多少。

输入格式: 3个数n k m(含义如上题) 
输出格式: 最后一个出列的人编号。

样例输入:

6 1 2

样例输出:

5

算法思路: 


        约瑟夫环是一道经典的循环链表问题,每当报数到指定数字,那个人就出局,接下来的一个人重新开始报数,相当于链表回到了开头,循环反复,直到只剩下一个人。

  1. 我们需要先创建一个带有头节点循环链表,然后用把所有人一次插入到循环链表当中,并赋值他们相对应的报数;
  2.  接下来开始处理从第几个人开始报数的问题:循环遍历链表,直到到指定的那个人,退出循环,返回节点,则为开始报数的人;
  3. 最后解决循环链表删除问题,向函数中传入指定删除的报数,循环遍历链表,每到之指定报数,退出循环进行删除操作,外面大循环继续往下走,直到结束。

具体实现如下:

#include <stdio.h>
#include <stdlib.h>

typedef struct node{
	int data;
	struct node *next;
}Node,*Link;

Link create(int n,int k);	//创建一个带有头节点的循环链表,并控制从k开始报数 
void Josephus(Link p,int m);	//传入链表和报数

int main()
{
	Link p = NULL;
	int n,k,m;
	scanf("%d %d %d",&n,&k,&m);	//输入总人数,开始的报数,自杀报数
	
	p = create(n,k);
	Josephus(p,m); 
	
	return 0;
}

Link create(int n,int k)
{
	Link head = NULL,p = NULL, pr = NULL;	//pr是新节点p的前一个结点
	int i;
	for(i = 1;i <= n;i++)
	{
		p = (Link)malloc(sizeof(Node));
		if(p == NULL)
		{
			printf("动态内存分配失败");
			return NULL; 
		}
		p->data = i;		//给每个人赋上报数的值 
		if(head == NULL)	//如果头节点指向空,直接放 
		{
			head = p;
		}
		else
		{
			pr->next = p;	
		}
		pr = p; 
	} 
	p->next = head;			//循环结束就回到头节点,形成完整的循环链表 
	p = head;
	
	
	//开始处理从第几个人开始报数
	for(i = 1;i < k;i++)
	{
		pr = p;
		p = p->next;		//一直遍历,到了k就出循环 
	} 
	
	return p; 				//返回指定的第一人 
	 
} 

void Josephus(Link p,int m)
{
	Link pr = NULL;
	int i;
	while(p->next != p)		//循环链表首尾未连接
	{
		for(i = 1;i < m;i++)
		{
			pr = p;
			p = p->next;
		}						//循环结束,就是要自杀的人
		pr->next = p->next; 	//删除操作
		free(p); 
		
		p = pr->next;			//重新开始,p指向新的出发点 
	}
	
	printf("%d",p->data);		//输出最后存活的人
	
	return; 
} 

运行结果:

  • 1
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值