数据结构
设有n个人围坐在一个圆桌周围,现从第s个人开始报数,数到第m的人出列,然后从出列的下一个人重新开始报数,数到m的人又出列,如此重复,直到所有的人全部出列为止。Josephus问题是:对于任意给定的n,m,s,求出按出列次序得到的n个人员的顺序表。
思路:从 1 到 n 构成一个循环链表。找到开始报数的结点p 。依次报数,数到m的结点,输出data值,并更新为下一个结点的data值。
p->next 指向 p->next->next。也就是将下一个结点提前一位,起到删除当前结点的效果
#include<stdio.h>
#include<stdlib.h>
typedef struct list{
int data;
struct list *next;
}list,*Linklist;
//构建循环链表 date 为 1,2,3,4,5,6,7........
void InitLink(Linklist &L,int n){
L = (list*)malloc(sizeof(list));//没有头节点
L->next = L;
L->data = 1;
Linklist p;
for (int i = n; i > 1; i--)
{
p= (Linklist)malloc(sizeof(list));
p->next = L->next;
L->next = p;
p->data = i;
}
}
void outList(Linklist L,int s,int m,int n){
//list* p = L;
Linklist p = L;
Linklist q;
int i;
for(i=1;i<=n;i++){
if(p->data==s){
break;
}
p=p->next;
}//找出s的位置,并用p记录
printf("data:%d\n",p->data);
printf("依次出圈的顺序为:");
for(i=0;i<n;i++){//n次出圈
int j = 1;
while(j<m){
p = p->next;//依次报数,当j=m时,结束循环。找到相应的p结点
j++;
}
printf("%d ",p->data);
// 将当前p结点的数据域输出,并修改当前的数据域为下一结点的数据域,同时指向下一结点的下一结点!起到删除当前结点的效果
q= p->next;//用q保存p的下一结点,最后释放
p->data = p->next->data;//p的数据域 改为下一结点的数据域
p->next = p->next->next;//指向下一个结点
free(q);
}
}
int main(){
int m,n,s;
printf("请输入围绕圆桌的人数:");
scanf("%d",&n);
printf("请输入开始的序号:");
scanf("%d",&s);
printf("请输入报到的数字:");
scanf("%d",&m);
list* L;
InitLink(L,n);
printf("循环链表:\n");
for(int q=0;q<n;q++){
printf("L->data = %d\n",L->data);
L = L->next;
}
outList(L,s,m,n);
}
运行结果
请输入围绕圆桌的人数:10
请输入开始的序号:2
请输入报到的数字:3
循环链表:
L->data = 1
L->data = 2
L->data = 3
L->data = 4
L->data = 5
L->data = 6
L->data = 7
L->data = 8
L->data = 9
L->data = 10
data:2
依次出圈的顺序为:4 7 10 3 8 2 9 6 1 5
--------------------------------
Process exited after 4.362 seconds with return value 0
请按任意键继续. . .