
首先先了解一下什么是约瑟夫环问题
Josephus有过的故事:39 个犹太人与Josephus及他的朋友躲到一个洞中,39个犹太人决定宁愿死也不要被敌人抓。于是决定了自杀方式,41个人排成一个圆圈,由第1个人开始报数,每报数到第3人该人就必须自杀。然后下一个重新报数,直到所有人都自杀身亡为止。然而Josephus 和他的朋友并不想遵从,Josephus要他的朋友先假装遵从,他将朋友与自己安排在第16个与第31个位置,于是逃过了这场死亡游戏。
约瑟夫环是一个数学的应用问题:已知n个人(以编号1,2,3...n分别表示)围坐在一张圆桌周围。从编号为k的人开始报数,数到m的那个人出列;他的下一个人又从1开始报数,数到m的那个人又出列;依此规律重复下去,直到圆桌周围的人全部出列
其实解决约瑟夫环问题可以有很多种解法,用数组等等,但是用单链表来解决确是相对比较更直观更方便的一种,当把单链表头尾相接的时候它就变成了一个环,也比较符合问题的实际模型,
因为我们这里是使用单链表进行实现约瑟夫环,所以单链表肯定是必不可少的,为了方便用单链表建一个环,这里用到了几个关于单链表的基本操作,包括单链表结点结构体的定义,结点的创建,尾插,找到指定结点位置
对于单链表来实现解决约瑟夫环问题,我们在环中定义指针cur,每次指针走k次后删除当前指针所指位置的结点,然后继续向后走k次,接着删除当前所指结点,执行循环,直到环中只剩下一个结点(即cur->next == cur),那么最后的这个结点就是我们要找的结点,返回它的地址
总的来说解决约瑟夫环问题的思路并不复杂,代码如下:
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<stdlib.h>
typedef int DataType;
typedef struct SListNode
{
struct SListNode* _next;
DataType _data;
}SListNode;
SListNode* BuySListNode(DataType x)
{
SListNode* tmp = (SListNode*)malloc(sizeof(SListNode));
if (tmp != NULL)
{
tmp->_data = x;
tmp->_next = NULL;
return tmp;
}
printf("节点创建失败!");
return tmp;
}
void SListPushBack(SListNode** ppHead, DataType x)//从尾部插入数据
{
SListNode* newNode;
SListNode* tmp;
newNode = BuySListNode(x);
tmp = *ppHead;
if (NULL == *ppHead)
{
*ppHead = newNode;
(*ppHead)->_next = NULL;
}
else
{
while (tmp->_next)
{
tmp = tmp->_next;
}
tmp->_next = newNode;
newNode->_next = NULL;
}
}
SListNode* SListFind(SListNode* pHead, DataType x)//找到链表中的某个元素
{
SListNode* tmp;
tmp = pHead;
while (tmp)
{
if (tmp->_data == x)
{
return tmp;
}
tmp = tmp->_next;
}
return tmp;
}
SListNode* SListJosephCircle(SListNode* pHead, int k)//单链表实现约瑟夫环(JosephCircle)
{
SListNode* cur = pHead;
SListNode* tmp = NULL;
while (cur != cur->_next)
{
int count = k;
while (--count)
{
cur = cur->_next;
}
tmp = cur->_next;
cur->_data = tmp->_data;
cur->_next = tmp->_next;
free(tmp);
}
return cur;
}
int main()
{
SListNode* SList1 = NULL;
SListPushBack(&SList1, 1);
SListPushBack(&SList1, 2);
SListPushBack(&SList1, 3);
SListPushBack(&SList1, 4);
SListPushBack(&SList1, 5);
SListPushBack(&SList1, 6);
SListPushBack(&SList1, 7);
SListFind(SList1, 7)->_next = SListFind(SList1,1);
printf("%d\n", SListJosephCircle(SList1, 3)->_data);
system("pause");
return 0;
}这里简单的用1、2、3、4、5、6、7来做了一个简单的测试

以上就是关于用单链表解决约瑟夫环问题的相关解法以及思路
本文介绍了约瑟夫环问题的历史背景及其数学应用,阐述了使用单链表解决这一问题的优势。通过定义单链表节点结构、创建节点、尾插等操作构建环形链表,并详细说明了如何设置指针在链表中按步长移动并删除节点,直至链表只剩一个节点,从而找到问题的解决方案。文中还提供了简单的测试案例以验证代码的正确性。

1225

被折叠的 条评论
为什么被折叠?



