首先我们来了解一下什么是约瑟夫环:
约瑟夫环(约瑟夫环问题)是一个数学的应用问题:已知n个人(以编号1,2,3...n分别表示)围坐在一张圆桌周围。从编号为k的人开始报数,数到m的那个人出列;他的下一个人又从1开始报数,数到m的那个人又出列;依此规律重复下去,直到圆桌周围只剩下一个人。
今天用单链表实现约瑟夫环:
了解完什么是约瑟夫环问题后,我们知道这是一个同心圆,而单链表并不是一个循环链表,要想实现链表的循环以构成同心圆,我们首先要做的就是让单链表构成一个循环链表,即让单链表的尾节点的pNext指向头节点;其次在已知数到m的人(从1开始报数)出列的情况下,我们要做的就是先找到这个人,即找到要删除的节点,因为数到m的人要出列,所以我们只需要走m-1步便可以找到要删除的节点。在找到要删除的节点之后,为了让删除节点的下一个节点作为下一次开始报数的第一个节点,在找删除节点的过程中,我们必须保存每个节点的前一个节点。一直循环下去,直到循环链表中只剩下一个节点。
代码实现如下:
#include <stdlib.h>
#include <assert.h>
#include <stdio.h>
typedef int DataType;
typedef struct SListNode
{
DataType data;
struct SListNode* pNext;
}SListNode;
//初始化
void SListInit(SListNode **ppFirst)
{
*ppFirst = NULL;
}
//打印函数
void SListNodePrint(SListNode **ppFirst)
{
SListNode *pNode = NULL;
for (pNode = *ppFirst; pNode != NULL; pNode = pNode->pNext)
{
printf("%d ->", pNode->data);
}
printf(" NULL\n");
}
//约瑟夫环
SListNode * JocephCircle(SListNode *pFirst, int k)
{
assert(pFirst);
SListNode *pCur = pFirst;
SListNode *pPre = NULL;
//构成循环链表
while (pCur->pNext)
{
pCur = pCur->pNext;
}
pCur->pNext = pFirst;
pCur = pFirst;
while (pCur->pNext != pCur) //只剩下一个节点时返回
{
//找
for (int i = 0; i < k - 1; i++) //找第k个节点,走k-1步
{
pPre = pCur; //记录每个节点的前一个节点
pCur = pCur->pNext;
}
//删
pPre->pNext = pCur->pNext;
free(pCur);
pCur = pPre->pNext; //从删除节点的下一个节点开始继续循环
}
return pCur;
}