一、约瑟夫问题
设编号分别为:1,2,...,n的n个人围坐一圈。约定序号为k(1<=k<=n)的人从1开始计数,数到m的那个人出列,他的下一位又从1开始计数,数到m的那个人又出列,依次类推,直到所有人出列为止。
二、算法思路
用一个不带头结点的循环链表来处理约瑟夫问题:先构成一个有n个结点的单循环链表,然后从第k结点起从1计数,记到m时。对应结点从链表中删除;然后再从被删除节点的下一个节点起又从1开始计数.....,直到所有节点都出列。
三、算法实现
1,创建单向循环链表
linklist create_list(void ){
int a=0;
linklist H,r,p;
loop:
printf("please input a\n");
scanf("%d",&a);//输入单向循环链表的结点数量a,a的值需要大于0,如果a小于等于0,则重新输入
if(a<=0) {
printf("a>0");
goto loop;
}
H= malloc(sizeof(listnode));//根据约瑟夫问题,创建第一个结点,并让其数据域为1
if(!H){
printf("malloc failed\n");
return NULL;
}
r=H;
H->data=1;
H->next=H;//只有一个结点的单向循环链表
//循环插入其他结点并给数据域赋值
for (int i = 2; i<=a ; i++) {
p= malloc(sizeof(listnode));//为新结点开辟空间
if(!p){//判断是否开辟成功
printf("malloc failed\n");
return NULL;
}
p->data=i;//赋值
r->next=p;//插入
r=p;
}
p->next=H;//最后一个节点的next域指向第一个结点,形成闭环
return H;
}
2、删除结点
void operate_list(linklist H,int k,int m){
linklist p,r;
p=H;
while (p->next->data!=k){//寻找起始节点的前一个节点,方便进行删除操作
p=p->next;
}
while(p->next!=p){//代跑指针指向自己时,则链表只剩最后一个元素,结束循环
int a=0;
while (a<m-1){//寻找出列节点的前驱
a++;
p=p->next;
}
r=p->next;//删除出列结点
p->next=r->next;
printf("%d\n",r->data);
free(r);
}
printf("%d\n",p->data);//打印仅存的一个结点
free(p);
p=NULL;
}
3,遍历并打印单向循环链表(此操作与解题无关,只为检查单向循环链表的创建)
void show_list(linklist H){
linklist p;//创建一个指针代跑,遍历链表
p=H;
while (p->next!=H){//循环链表,结束条件为p->next==H
printf("%d\n",p->data);
p=p->next;
//遍历,指针后移!!!!!!!
}
printf("%d",p->data);//打印最后一个元素
}
结束,感谢观看!!!!!