循环链表解决约瑟夫环问题

这篇具有很好参考价值的文章主要介绍了循环链表解决约瑟夫环问题。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

一、问题描述

n 个人围成一圈,从第一个人开始报数,数到 m 的人出列,再由下一个人重新从 1开始报数,数到 m 的人再出圈,依次类推,直到所有的人都出圈,请输出依次出圈人的编号。

二、算法思路

n个人围成一圈,很容易可以想到用循环链表解决问题,用结点代表每个人,节点的数据域存储人的编号。对链表的定义如下

typedef struct node
{
	int data;			//数据域
	struct node* next;	//指针域
}node;

首先我们需要将链表初始化,对约瑟夫环问题,已知链表结点总数,也就是循环次数,且结点存储的数据就是初始化时结点在链表的顺序(比如第一个结点存储的数据就是1)。于是我们采取for循环来进行链表初始化,假设循环n次,则前n-1次创建新结点,最后一次让尾结点指向头结点完成循环链表的创建。相关代码如下:

//初始化循环链表
node* CreatList(int n)	//参数为链表结点数,即围成环的人数
{
	node* headNode = (node*)malloc(sizeof(node));	//为头结点申请内存
	node* p = headNode;				//用p来遍历链表
	for (int i = 1; i <= n; i++)	//有n个数据==人,则循环n次
	{
		p->data = i;				//令第i个结点的存储的数据==i
		if (i < n)					//前n-1次申请下一个结点
		{
			p->next = (node*)malloc(sizeof(node));	//给下一个结点申请内存
			p = p->next;			//让p向后挪一位用于下一次遍历
		}
		else p->next = headNode;	//第n次让尾结点指向头节点
	}
	return headNode;				//返回头结点
}

之后,就要进入我们今天的正题了,约瑟夫环问题可以抽象成通过不断地删除链表中的元素直至链表中只剩最后一个元素,那根据循环链表地定义,当链表中只剩一个元素的时候,链表头节点的下一个结点就是它自己,如图
用循环链表解决约瑟夫问题,链表,数据结构,算法

那么headNode==headNode->next就可以成为我们判断循环结束的条件。在遍历时,先用node* p指向报数为“1”的人(注意报数为“1”不是编号为“1”)第一次报数为“1”的人就是编号为“1”的人,也就是我们的 headNode,再通过循环让p指向被删除的数的上一个结点,若要删除的结点为报数为k,则需要循环k-2次。之后就是打印此结点、删除结点……不再做过多赘述。在删除之后p->next就是原来被删除的结点的下一个结点了,于是让headNode指向这个结点,也就是“再由下一个人重新从 1开始报数”。之后开始下一次遍历。代码如下

int Joseph(node* headNode, int n, int k)
{
	while (headNode->next != headNode)	//当headNode==headNode->next的时候说明只剩一个人未出圈
	{
		node* p = headNode;				//用p遍历链表
		for (int i = 1; i <= k - 2; i++)//让p->next指向要出圈的人
			p = p->next;
		node* q = p->next;				//用q暂存要出圈的人,防止丢失
		printf("%d ", q->data);			//打印本次要出圈的人的编号
		p->next = p->next->next;		//将此人出圈
		free(q);						//释放出圈人所占的空间
		headNode = p->next;				//让头结点指向出圈人的下一个结点,即“再由下一个人重新从 1开始报数”
	}
	return headNode->data;				//返回最后出圈人的编号
}

三、整体代码

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

typedef struct node
{
	int data;
	struct node* next;
}node;
//初始化循环链表
node* CreatList(int n)	//参数为链表结点数,即围成环的人数
{
	node* headNode = (node*)malloc(sizeof(node));	//为头结点申请内存
	node* p = headNode;				//用p来遍历链表
	for (int i = 1; i <= n; i++)	//有n个数据==人,则循环n次
	{
		p->data = i;				//令第i个结点的存储的数据==i
		if (i < n)					//前n-1次申请下一个结点
		{
			p->next = (node*)malloc(sizeof(node));	//给下一个结点申请内存
			p = p->next;			//让p向后挪一位用于下一次遍历
		}
		else p->next = headNode;	//第n次让尾结点指向头节点
	}
	return headNode;				//返回头结点
}

int Joseph(node* headNode, int n, int k)
{
	
	while (headNode->next != headNode)	//当headNode==headNode->next的时候说明只剩一个人未出圈
	{
		node* p = headNode;				//用p遍历链表
		for (int i = 1; i <= k - 2; i++)//让p->next指向要出圈的人
			p = p->next;
		node* q = p->next;				//用q暂存要出圈的人,防止丢失
		printf("%d ", q->data);			//打印本次要出圈的人的编号
		p->next = p->next->next;		//将此人出圈
		free(q);						//释放出圈人所占的空间
		headNode = p->next;				//让头结点指向出圈人的下一个结点,即“再由下一个人重新从 1开始报数”
	}
	return headNode->data;				//返回最后出圈人的编号
}


int main()
{
	int n, k;
	scanf("%d %d", &n, &k);				//输入总人数和出圈序号
	node* headNode = CreatList(n);		//链表初始化
	printf("%d", Joseph(headNode,n,k));	//输出最后一个出圈人的编号
	return 0;
}

四、课后思考

最后,以上内容在洛谷P1996可以AC,但是在P8671却不行,有没有聪明的小伙伴知道这是为什么吗?可以把你的思路放在评论区里。文章来源地址https://www.toymoban.com/news/detail-726132.html

到了这里,关于循环链表解决约瑟夫环问题的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 数据结构实验---顺序表的合并---链表的基本操作---重点解析约瑟夫问题

    实验的写法多种多样,但本文并未采用 #define 定义容量的写法,这样写已经是很老旧过时的写法。所有实验主体采用均为动态开辟,后续如果利用 C++ 来写或许会应用更多语法… 本篇展示数据结构的两个实验 其中,重点分析约瑟夫问题 实验中代码的命名风格等均与下方博客

    2024年02月16日
    浏览(49)
  • 【c语言习题】使用链表解决约瑟夫问题

    创作不易,本篇文章如果帮助到了你,还请点赞 关注支持一下♡𖥦)!! 主页专栏有更多知识,如有疑问欢迎大家指正讨论,共同进步! 🔥c语言系列专栏:c语言之路重点知识整合 🔥 给大家跳段街舞感谢支持!ጿ ኈ ቼ ዽ ጿ ኈ ቼ ዽ ጿ ኈ ቼ ዽ ጿ ኈ ቼ ዽ ጿ ኈ ቼ 链表有

    2024年02月08日
    浏览(29)
  • C语言---数据结构实验---顺序表的合并---链表的基本操作---重点解析约瑟夫问题

    实验的写法多种多样,但本文并未采用 #define 定义容量的写法,这样写已经是很老旧过时的写法。所有实验主体采用均为动态开辟,后续如果利用 C++ 来写或许会应用更多语法… 本篇展示数据结构的两个实验 其中,重点分析约瑟夫问题 实验中代码的命名风格等均与下方博客

    2024年02月16日
    浏览(35)
  • 重温数据结构与算法之约瑟夫问题

    约瑟夫问题 ,是一个计算机科学和数学中的问题,在计算机编程的算法中,类似问题又称为 约瑟夫环 ,又称“丢手绢问题”。 据说著名犹太历史学家 Josephus 有过以下的故事: 在罗马人占领乔塔帕特后,39个犹太人与Josephus及他的朋友躲到一个洞中,39个犹太人决定宁愿死也

    2024年02月08日
    浏览(31)
  • 数据结构—约瑟夫环问题(C语言版)

    目录 首先什么是约瑟夫环 约瑟夫环实现方式 一、创建结构体变量 二、初始化链表 三、构建循环链表 四、删除链表  五、完整代码及注释讲解 约瑟夫环 是 循环链表 中的一个经典问题;题目描述:n 个人围成一圈,从第一个人开始报数,数到 m 的人出列,再由下一个人重新

    2024年02月11日
    浏览(32)
  • 力扣环形链表(1)进阶环形链表(2)及环形链表的约瑟夫问题

    为了加深对环形链表的理解和掌握,这两道题是很不错的选择。 这里所说环形链表不是一个圈圈的结构,而是带环链表。 链接:环形链表(1) 注意这里链表的长度 所以要注意链表是否为空 第一种方法,应该是比较容易想到的方法(偷鸡取脚)  遍历链表,将每个节点的

    2024年02月06日
    浏览(23)
  • 约瑟夫死者游戏-C语言实现-双向循环链表

    设计题目 1 : 约瑟夫生者死者游戏 [问题描述]: 约瑟夫生者死者游戏的大意是: 30 个旅客同乘一条船,因为严重超载,加上风高浪大, 危险万分;因此船长告诉乘客,只有将全船一半的旅客投入海中,其余人才能幸免遇难。无 奈,大家只得同意这种办法,并议定 30 个人围

    2024年02月03日
    浏览(29)
  • 约瑟夫环问题解决

    单链表 实现 错例 在使用malloc函数开辟的空间中,不要进行指针的移动, 因为一旦移动之后可能出现申请的空间和释放空间大小的不匹配 循环链表 单独创建 逐节点创建 约瑟夫环问题 实现方式一: 实现方式二: 删除节点并建立新链表 实现

    2024年02月02日
    浏览(28)
  • 4种方法解决约瑟夫环问题

            约瑟夫环问题是大多数编程初学者必须要跨越的一道坎。在第一次见到它的时候,我还是个刚刚学会循环语句的小蒟蒻,而现在的我已经是深陷图论以及各种其他算法的大蒟蒻了(bushi)。可以说,约瑟夫环问题是我从编程基础向编程思维踏出的重要一步。        

    2024年02月12日
    浏览(26)
  • 数据结构上机实验——栈和队列的实现、栈和队列的应用、进制转换、约瑟夫环问题

      1.利用栈的基本操作实现将任意一个十进制整数转化为R进制整数。   2.利用循环队列实现.约瑟夫环问题:已知n个人(以编号1,2,3…n分别表示)围坐在一张圆桌周围。从编号为k的人开始报数,数到k的那个人出圈;他的下一个人又从1开始报数,数到k的那个人出圈;依

    2024年02月08日
    浏览(31)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包