约瑟夫环问题起源于一个犹太故事。约瑟夫环问题的大意如下:
罗马人攻占了桥塔帕特,41个人藏在一个山洞中躲过了这场浩劫。这41个人中,包括历史学家Josephus(约瑟夫)和他的一个朋友。剩余的39个人为了表示不向罗马人屈服,决定集体自杀。大家制定了一个自杀方案,所有这41个人围成一个圆圈,由第一个人开始顺时针报数,每报数为3的人就立刻自杀,然后再由下一个人重新开始报数,仍然是每报数为3的人就立刻自杀……,直到所有的人都自杀身亡为止。
约瑟夫和他的朋友并不想自杀,于是约瑟夫想到了一个计策,他们两个同样参与到自杀方案中,但是最后却躲过了自杀。请问,他们是怎么做到的?
约瑟夫环:
这是一个典型的循环链表题目。我们需要创建一个循环链表,依照游戏规则,依次进行删除结点操作。直至链表为空,打印出的元素顺序即为出局顺序!
#include <stdio.h>
#include <stdlib.h>
#define LEN sizeof(node)
typedef struct Node {
int data;
struct Node *next;
}node;
//创建一个n个结点的链表
node *CreateLink(int n) {
node *head, *pf, *pb; //head:头结点 pf:当前位置的结点 pb:新建的结点
//创建n个结点——循环n次
int count = 0;
for (int i=0; i<n; i++) {
pb = (node *)malloc(sizeof(LEN)); //新建一个结点
//判断是否建立成功
if (pb == NULL) {
printf("Create Link failed\n");
return NULL;
}
pb->data = ++count; //为新建结点的数据成员赋值
//判断新建立的结点的位置,
if (0 == i) {
head = pb; //如果是第一个结点,则赋给head
pf = pb; //新建的第一个结点也就是当前结点
} else {
pf->next = pb; //新建的结点为当前结点的下一个结点
}
pb->next = NULL; //为新建结点的next指针赋值
pf = pb; //当前结点改为pb,为下一个结点创立做准备
}
pf->next = head;
return head;
}
int main(void) {
int sum = 41;
int flag = 3;
node *t, *h; //h指向每次的起点
//t指向要删除的点
h = CreateLink(sum);
while (h != h->next) {
for (int i=1; i<flag-1; i++) {
h = h->next;
}
t = h->next;//t为要删除的结点
h->next = t->next;
printf("%d ", t->data);//输出删除的数
h = t->next;//新一轮开始
}
printf("%d\n", h->data);
return 0;
}
//修改版
#include
#include
typedef struct node {
int data;
struct node *next;
}node;
node *create(int n) {
node *head;
head = (node *)malloc(sizeof(node));
int i=1;
node *s,*p=head;
while (i<=n) {
s = (node*)malloc(sizeof(node));
s->data = i++;
p->next = s;
p = p->next;
}
p->next = head->next;
free(head);
return p->next;
}
int main(void) {
int i,n,m;
node *newstart,*h,*t;
m=3;
n=10;
newstart=create(n);
h=newstart;
while(h!=h->next) {
for(i=1;i<m-1;i++) {
h=h->next;
}
t=h->next;
printf("%d ",h->next->data);
h->next=t->next;
h=t->next;
free(t);
t = NULL;
}
printf("%d\n", h->data);
return 0;
}