约瑟夫环问题,是一个经典的循环链表题。
约瑟夫环问题描述:已知 n 个人(分别用编号 1,2,3,…,n 表示)围坐在一张圆桌周围,从编号为 k 的人开始顺时针报数,数到 m 的那个人出列;他的下一个人又从 1 开始,还是顺时针开始报数,数到 m 的那个人又出列;依次重复下去,直到圆桌上剩余一个人。输出的最后一个人即为圆桌剩余的一人。
#include<stdio.h>
#include<stdlib.h>
typedef struct LNode{
int data;
struct LNode *next;
}CLinkList;
CLinkList *creat(int n){
CLinkList *head,*node,*end;
int i=0;
head=(CLinkList*)malloc(sizeof(CLinkList));
head->data=1;
end=head;
for(i=2;i<=n;i++){
node=(CLinkList*)malloc(sizeof(CLinkList));
node->data=i;
end->next=node;
node->next=NULL;
end=end->next;
}
end->next=head;
return head;
}
void findAndKillK(CLinkList * head, int k, int m) {
CLinkList * p = NULL;
CLinkList * tail = head;
//找到链表第一个结点的上一个结点,为删除操作做准备
//while (tail->next != head) {
tail = head->next;
// }
p = head;
//找到编号为k的人
while (p->data != k) {
tail = p;
p = p->next;
}
//从编号为k的人开始,只有符合p->next==p时,说明链表中除了p结点,所有编号都出列了,
while (p->next != p) {
int i = 0;
//找到从p报数1开始,报m的人,并且还要知道数m-1de人的位置tail,方便做删除操作。
for (i = 1; i < m; i++) {
tail = p;
p = p->next;
}
tail->next = p->next;//从链表上将p结点摘下来
printf("出列人的编号为:%d\n", p->data);
free(p);
p = tail->next;//继续使用p指针指向出列编号的下一个编号,游戏继续
}
printf("出列人的编号为:%d\n", p->data);
free(p);
}
int main() {
int n = 0, k = 0, m = 0;
CLinkList * head = NULL;
printf("输入圆桌上的人数:");
scanf("%d", &n);
head = creat(n);
printf("从第几个人开始报数(k>1且k<%d):", n);
scanf("%d", &k);
printf("数到几的人出列:");
scanf("%d", &m);
findAndKillK(head, k, m);
return 0;
}
输出结果
输入圆桌上的人数:5
从第几个人开始报数(k>1且k<5):1
数到几的人出列:2
出列人的编号为:2
出列人的编号为:4
出列人的编号为:1
出列人的编号为:5
出列人的编号为:3