您的位置:首页 > 编程语言

约瑟夫环问题的解释及代码实现

2017-03-01 18:40 871 查看
                                                                          约瑟夫环问题

故事背景:

     据说著名犹太历史学家 Josephus有过以下的故事:在罗马人占领乔塔帕特后,39
个犹太人与Josephus及他的朋友躲到一个洞中,39个犹太人决定宁愿死也不要被敌人抓到,于是决定了一个自杀方式,41个人排成一个圆圈,由第1个人开始报数,每报数到第3人该人就必须自杀,然后再由下一个重新报数,直到所有人都自杀身亡为止。然而Josephus 和他的朋友并不想遵从,Josephus要他的朋友先假装遵从,他将朋友与自己安排在第16个与第31个位置,于是逃过了这场死亡游戏。

问题描述:

       有n个人围成一个环,然后给从某个人开始顺时针从1开始报数,每报到m时,将此人出环杀死(当然不杀死也可以啊),然后从下一个人继续从1报数,直到最后只剩下一个人,求这个唯一剩下的存活的人是谁?

 解决问题的核心步骤:(程序的基本算法)

  1.建立一个具有n个链结点,无头结点的循环链表;

  2.确定第1个报数人的位置;

  3.不断地从链表中删除报数报到指定数num的那个人的链结点,直到链表剩一个节点。

  pNode JosephCycle(pList* pplist, int num) //pplist是传进来的带环链表,num为出列者喊到的数

​代码也很简单,直接看代码吧!

#include<stdlib.h>
#include<stdio.h>
#include<assert.h>
#include<windows.h>
#pragma warning(disable:4996)

typedef int DataType;

typedef struct Node
{
DataType data;
struct Node* next;
}Node, *pNode, *pList;

//初始化链表
void InitLinkList(pList* pplist)
{
assert(pplist != NULL);
*pplist = NULL;
}

//创建一个节点空间
pNode BuyNode(DataType d)
{
pNode temp = NULL;
temp = (pNode)malloc(sizeof(Node));
temp->data = d;
temp->next = NULL;
return temp;
}

//在链表上尾插节点
void PushBack(pList* pplist, DataType d)
{
assert(pplist != NULL);
pNode NewNode = BuyNode(d);
pNode cur = *pplist;
if (*pplist == NULL)
{
*pplist = NewNode;
return;
}
while (cur->next != NULL)
{
cur = cur->next;
}
cur->next = NewNode;
return;
}

//寻找并返回指定结点的地址
pNode Find(pList plist, DataType d)
{
pNode cur = plist;
if (cur == NULL)
{
printf("链表为空,");
return NULL;
}
while (cur != NULL)
{
if (cur->data == d)
{
return cur;
}
cur = cur->next;
}
return NULL;
}

//约瑟夫环问题代码
pNode JosephCycle(pList* pplist, int num)
{
int i = 0;
pNode del = NULL;
pNode cur = *pplist;
assert(pplist);
while (1)
{
if (cur->next == cur) //判断链表上是否只有一个节点,如果是则返回这个节点
{
return cur;
}
for (i = 0; i < num - 1; i++) //找出报数报到num的人,每报到num的人就跳出链表,然后删除
{
cur = cur->next;
}
del = cur->next;
printf("%d\n", cur->data);
cur->data = cur->next->data;
cur->next = cur->next->next;
free(del);
}
}

int main()
{
pList plist;
pNode ret = NULL;
InitLinkList(&plist); //初始化链表

PushBack(&plist, 1); //这里可以随意设置链表的长度
PushBack(&plist, 3);
PushBack(&plist, 5);
PushBack(&plist, 7);
PushBack(&plist, 8);

Find(plist, 8)->next = plist; //构造环

printf("依次报到指定数字的人:\n");
ret = JosephCycle(&plist, 3); //这里设置报数每报到三的出列
printf("最后一个人是:\n%d\n", ret->data);
return 0;
}


内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: