@约瑟夫环的故事
约瑟夫环又名自杀环,据说著名犹太历史学家Josephus有过以下的故事:
在罗马人占领乔榙帕特后,39个犹太人与Josephus以及他的朋友躲到一个洞中,39个犹太人决定宁愿死也不要被敌人抓到,于是决定了一个自杀方式,自杀规则是这样的:41个人排成一个圆圈,由第一个人开始报数每报数到第三个人该人就必须自杀,然后再由下一个人重新报数,直到所有人都自杀身亡为止。但是聪明的Josephus并不想遵守这样的死亡游戏,那仫他和他的朋友是如何逃脱的呢?这就是我今天要实现的约瑟夫环的问题。
首先先给出代码的结构部分:
typedef int DataType;
typedef struct LinkNode
{
DataType data;
struct LinkNode *next;
}LinkNode,*pLinkNode;
typedef struct LinkList
{
LinkNode *phead;
}LinkList,*pLinkList;
@约瑟夫环的分析
首先我们假设环内有4个人(便于分析):
要找到最后一个存活的人,我们首先要构造出环,在这里我使用的构造环的思路是:遍历链表找到最后一个结点,将最后一个结点的指针域(原来为空)连接到第一个结点上,这就构造出了约瑟夫环,在构造环是用到了前面的Find_num(查找结点的函数);接下来约瑟夫环的分析过程了:
@约瑟夫环的实现:
pLinkNode JosephCycle(pLinkNode phead,int k) //约瑟夫环问题
{
pLinkNode cur=phead;
pLinkNode del=NULL;
int m=0;
while(1)
{
m=k; //更新m的值,使得k的值可以多次使用
if(cur->next == cur)
break;
while(--m) //cur指向要退出的结点
{
cur=cur->next;
}
printf("del:%d\n",cur->data);
cur->data=cur->next->data; //采用交换的方法
del=cur->next;
cur->next=del->next;
free(del);
del=NULL;
}
return cur;
}
@约瑟夫问题的测试结果:
看测试的结果和我们分析的一致,那仫对于上面提到的自杀问题的结果又是什仫呢?
可知最后两个留下来的是16和31位,聪明的Josephus就是将自己和朋友放到16和31位上才逃脱了自杀循环.
测试代码:
void text9()
{
int i=0;
LinkList plist;
pLinkNode ret=NULL;
Init_LinkList(&plist);
//Push_back(&plist,1);
//Push_back(&plist,3);
//Push_back(&plist,5);
//Push_back(&plist,7);
//Push_back(&plist,9);
//Push_back(&plist,11);
for(i=0;i<41;i++)
{
Push_back(&plist,i+1);
}
//构成环
ret=Find_NUM(&plist,i);
ret->next=plist.phead;
ret=JosephCycle(plist.phead,3);
printf("last:%d\n",ret->data);
free(ret);
}
至此约瑟夫环的问题就分析完成了~