约瑟夫问题
约瑟夫问题(有时也称为约瑟夫斯置换,是一个出现在计算机科学和数学中的问题。在计算机编程的算法中,类似问题又称为约瑟夫环。又称“丢手绢问题”.)
*问题来历
据说著名犹太历史学家 Josephus有过以下的故事:在罗马人占领乔塔帕特后,39个犹太人与Josephus及他的朋友躲到一个洞中,39个犹太人决定宁愿死也不要被敌人抓到,于是决定了一个自杀方式,41个人排成一个圆圈,由第1个人开始报数,每报数到第3人该人就必须自杀,然后再由下一个重新报数,直到所有人都自杀身亡为止。然而Josephus和他的朋友并不想遵从。首先从一个人开始,越过k-2个人(因为第一个人已经被越过),并杀掉第k个人。接着,再越过k-1个人,并杀掉第k个人。这个过程沿着圆圈一直进行,直到最终只剩下一个人留下,这个人就可以继续活着。问题是,给定了和,一开始要站在什么地方才能避免被处决?Josephus要他的朋友先假装遵从,他将朋友与自己安排在第16个与第31个位置,于是逃过了这场死亡游戏。
*问题分析与算法设计
一般形式
约瑟夫问题是个有名的问题:N个人围成一圈,从第一个开始报数,第M个将被杀掉,最后剩下一个,其余人都将被杀掉。
例如N=6,M=5,被杀掉的顺序是:5,4,6,2,3,1。
分析:
(1)根据n个人围成个圈,然后按顺序报数在指定位置杀掉,不难想到,这个顺序可以是一个数组或者链表组成。(这里我采用链表实现)当然得是链表组成的环,
(2)在指定位置杀死此人,而且是循环报数,可以采用快慢指针,或者利用一个指针和一个计数器来实现
(3)杀死此人相当于在指定位置删除指定元素
举一个简单的例子,方便理解:
基本思想:
1先创建一个节点,依次循环,形成一个链表,将最后一个节点的指向下一个节点指向第一的节点位置,形成环,循环添加链表的数据
2,或者创建一个链表,将给链表的尾部与头部链接,形成一个环
利用while(plist->len!=1)//控制循环范围
while(i<m-1)//控制死亡节点位置然后删除指定位置元素
代码实现:
建立节点,连接成链表:
struct _Node
{
int data;
struct _Node*next;
};
typedef struct _Node node_t;
typedef struct _Linklist
{
node_t *phead;
node_t *ptail;
int len;
}Linklist;Linklist pList;
#endif//_LINKLIST_H__
初始化链表
static node_t *GetNode(int i)//新建并初始化节点
{
node_t *pNode;
pNode=(node_t*)malloc(sizeof(node_t));
if(!pNode)
{
printf("Error,the memory is no tenough!\n");
exit(-1);
}
pNode->data=i;
pNode->next=NULL;
return pNode;
}
void init_list(Linklist*plist)//用第一个节点初始化循环单链表
{
node_t *p;
p=GetNode(1);
plist->phead=p;
plist->ptail=p;
p->next=plist->phead;
plist->len=1;
}
static void Create_List(Linklist*plist,int n)//把其余数据添加到循环单链表中
{
int i=0;
node_t *pNew;
for(i=2;i<=n;i++)
{
pNew=GetNode(i);
plist->ptail->next=pNew;
plist->ptail=pNew;
pNew->next=plist->phead;
plist->len++;
}
printf("Completes thee-way circulation chain table the foundation!\n");
}
输出链表:
void Print_List(Linklist*plist)//输出链表内容
{
node_t *pCur=plist->phead;
while(pCur->next!=plist->phead)
{
printf("The%dperson.\n",pCur->data);
pCur=pCur->next;
}
printf("The length of the List:%d\n",plist->len);
}
约瑟夫回环实现
//约瑟夫回环函数实现
//
void joseph(Linklist*plist,int m)//约瑟夫回环函数实现
{
node_t *pPre=plist->ptail;
node_t *pCur=plist->phead;
int i;
while(plist->len!=1)
{
i=0;
while(i<m-1)
{
pPre=pPre->next;
i++;
}
pCur=pPre->next;
pPre->next=pCur->next;
printf("The kill one is:%d\n",pCur->data);
free(pCur);
plist->len--;
}
printf("The last one is:%d\n",pPre->data);
}
测试部分:
<div>int main()
{
int n=0;
int m=0;
printf("Please input the Length of the Circlelist:");
scanf("%d",&n);</div><div>
</div><div> printf("Please input the Stop point:");
scanf("%d",&m);</div><div>
</div><div> init_list(&pList);
Create_List(&pList,n);
Print_List(&pList);
joseph(&pList,m);
system("pause");
return 0;
}</div><div>源代码:</div><div><pre class="cpp" name="code">#define _CRT_SECURE_NO_WARNINGS 1
#ifndef _LINKLIST_H__
#define _LINKLIST_H__
#include<stdio.h>
#include<stdlib.h>
struct _Node
{
int data;
struct _Node*next;
};
typedef struct _Node node_t;
typedef struct _Linklist
{
node_t *phead;
node_t *ptail;
int len;
}Linklist;Linklist pList;
#endif//_LINKLIST_H__
static node_t *GetNode(int i)//新建并初始化节点
{
node_t *pNode;
pNode=(node_t*)malloc(sizeof(node_t));
if(!pNode)
{
printf("Error,the memory is no tenough!\n");
exit(-1);
}
pNode->data=i;
pNode->next=NULL;
return pNode;
}
void init_list(Linklist*plist)//用第一个节点初始化循环单链表
{
node_t *p;
p=GetNode(1);
plist->phead=p;
plist->ptail=p;
p->next=plist->phead;
plist->len=1;
}
static void Create_List(Linklist*plist,int n)//把其余数据添加到循环单链表中
{
int i=0;
node_t *pNew;
for(i=2;i<=n;i++)
{
pNew=GetNode(i);
plist->ptail->next=pNew;
plist->ptail=pNew;
pNew->next=plist->phead;
plist->len++;
}
printf("Completes thee-way circulation chain table the foundation!\n");
}
void Print_List(Linklist*plist)//输出链表内容
{
node_t *pCur=plist->phead;
while(pCur->next!=plist->phead)
{
printf("The%dperson.\n",pCur->data);
pCur=pCur->next;
}
printf("The length of the List:%d\n",plist->len);
}
//约瑟夫回环函数实现
//
void joseph(Linklist*plist,int m)//约瑟夫回环函数实现
{
node_t *pPre=plist->ptail;
node_t *pCur=plist->phead;
int i;
while(plist->len!=1)
{
i=0;
while(i<m-1)
{
pPre=pPre->next;
i++;
}
pCur=pPre->next;
pPre->next=pCur->next;
printf("The kill one is:%d\n",pCur->data);
free(pCur);
plist->len--;
}
printf("The last one is:%d\n",pPre->data);
}
int main()
{
int n=0;
int m=0;
printf("Please input the Length of the Circlelist:");
scanf("%d",&n);
printf("Please input the Stop point:");
scanf("%d",&m);
init_list(&pList);
Create_List(&pList,n);
Print_List(&pList);
joseph(&pList,m);
system("pause");
return 0;
}