约瑟夫环

约瑟夫问题

约瑟夫问题(有时也称为约瑟夫斯置换,是一个出现在计算机科学和数学中的问题。在计算机编程的算法中,类似问题又称为约瑟夫环。又称丢手绢问题”.

*问题来历

     据说著名犹太历史学家 Josephus有过以下的故事:在罗马人占领乔塔帕特后,39个犹太人与Josephus及他的朋友躲到一个洞中,39个犹太人决定宁愿死也不要被敌人抓到,于是决定了一个自杀方式,41个人排成一个圆圈,由第1个人开始报数,每报数到第3人该人就必须自杀,然后再由下一个重新报数,直到所有人都自杀身亡为止。然而Josephus和他的朋友并不想遵从。首先从一个人开始,越过k-2个人(因为第一个人已经被越过),并杀掉第k个人。接着,再越过k-1个人,并杀掉第k个人。这个过程沿着圆圈一直进行,直到最终只剩下一个人留下,这个人就可以继续活着。问题是,给定了和,一开始要站在什么地方才能避免被处决?Josephus要他的朋友先假装遵从,他将朋友与自己安排在第16个与第31个位置,于是逃过了这场死亡游戏。

*问题分析与算法设计

一般形式

约瑟夫问题是个有名的问题:N个人围成一圈,从第一个开始报数,第M个将被杀掉,最后剩下一个,其余人都将被杀掉。

       例如N=6M=5,被杀掉的顺序是:546231

分析:

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;
}



 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值