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

                                                                          约瑟夫环问题

故事背景:

     据说著名犹太历史学家 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
#include
#include
#include
#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;
}

约瑟夫环问题的解释及代码实现_第1张图片

你可能感兴趣的:(c语言)