关闭

约瑟夫问题(Josephus problem)的一点思考

1171人阅读 评论(0) 收藏 举报
问题的提出:
假设N个人决定选出一个领导,将所有人排成一个圆周,沿着这个圆周每次数M个人就排除对应者,每当有人出列后,剩下的人靠拢,仍然保持一个完整的圆周。问题是找出最后剩下的那个人是谁(根据数学方法,不用这么麻烦,可能早就算出应该是圆周中的哪一个人了)。确定领导的过程是一个N和M的函数,这就是所谓的约瑟夫函数(Josephus  function)。更一般地讲,我们可能希望知道出列人员的顺序。例如,若共有N=9个人,且每数M=5个人就排除对应者,则出列顺序为5  1  7  4  3  6  9  2 ,8为选出的领导。

问题的解答:
问题的解决方式有多种,在此可以构造一个循环链表来解决问题。将N个人按顺序插入一个循环链表,然后从第一个人开始数M个人就删除一个节点,如此往复,直到剩下最后一个节点为止。为此,编写程序如下。
#include <stdlib.h>
#include <stdio.h>

typedef int Item;
typedef struct node *link;
struct node{
    Item item;
    link next;
};

int main(int argc,char *argv[])
{
    int i,N=atoi(argv[1]),M=atoi(argv[2]);
    link t=(link)malloc(sizeof(*t)),x=t;
    t->item=1;t->next=t;
    for(i=2;i<=N;i++){
        x=(x->next=(link)malloc(sizeof(*x)));
        x->item=i;
        x->next=t;
    }
    while(x!=x->next){
        for(i=1;i<M;i++)
            x=x->next;
        x->next=x->next->next;
        N--;
    }
    printf("%d/n",x->item);
    return 0;
}
以上程序的优点在于它能够快速删除节点,若使用数组而不是链表,则会使删除节点的开销增大。使用数组的优点在于它能快速访问数组中任意下标的元素。当我们选择一种数据结构时,必须当心这种选择对算法处理数据的效率的影响。
在C中,指针为链表的抽象概念提供了一种直接而且方便的具体实现,但抽象的基本值并不依赖于任何特定的实现。我们同样可以用整数数组来针对约瑟夫问题实现链表,也就是说,我们可以使用数组索引实现链表,而不是使用指针。下面的表就说明了链表的数组表示方法。具体实现程序有兴趣的话可以编写一下。
  0 1 2 3 4 5 6 7 8
item 1 2 3 4 5 6 7 8 9
next 1 2 3 4 5 6 7 8 0
链表的数组表示

在此,我给出我的实现如下:

#include <stdio.h>
#include <stdlib.h>

struct node{
 int item;
 int next;
};

void main(int argc,char *argv[2])
{
 int i,j,N=/*atoi(argv[1])*/9,M=/*atoi(argv[2])*/5;
 // 构造循环链表
 node *t=(node *)malloc(sizeof node *N);
 for(i=0;i<N;i++)
 {
  t[i].next=i+1;
  t[i].item=i+1;
 }
 t[N-1].next=0;
 i=0 ;
 // 模拟选举过程
 while(t[i].next!=i)  /* 该节点的next域不指向自己则继续循环*/
 {
  for(j=0;j<M-2;j++)
   i=t[i].next;
  t[i].next=t[t[i].next].next; /* 将i的next域值设置为其下下个节点的索引*/
  i=t[i].next;     /* 移到下一个节点*/
 }
 printf("%d",t[i].item);
}

当然,这个实现并不是唯一的,我们还可以分别用两个数组来表示,一个Item数组,一个next数组。大小均为N,然后并不修改Item,只修改next。

问题的反思:
算法的灵魂在于思想,不在实现,我们要掌握的是算法本身,而不是程序。程序只是我们算法的实现,不要拘泥于某一特定语言。语言只是工具而已,选用哪种语言,要看我们要解决的问题的规模,复杂度,时间以及空间的要求。当然,我并不是说不用学语言,而只去学数学。我们要学的是将算法的思想用具体的语言工具表达出来,解决实际遇到的问题。
最后,以上纯属本人愚见,不要当真,不同时期,总会有不同的体会,所以,尽情的享受学习带给你的快乐与困苦吧。

0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:25747次
    • 积分:440
    • 等级:
    • 排名:千里之外
    • 原创:18篇
    • 转载:1篇
    • 译文:0篇
    • 评论:6条
    最新评论