约瑟夫问题
约瑟夫问题:n个人围成一圈,初始编号从1~n排列,从约定编号为x的人开始报数,数到第m个人出圈,接着又从1开始报数,报到第m个数的人又退出圈,以此类推,最后圈内只剩下一个人,这个人就是赢家,求出赢家的编号。
本题采用无头环形链表的方式解决问题
根据循环依次删除第m个位置的数据,最后剩下的就是我们要找的结果。
这里我们共定义6个人,从第一个人开始计数,到第5个人开始出圈。 最终剩下的人获胜
上代码:
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
typedef int datatype;
//定义链表的结构体
typedef struct node_t
{
datatype data;//数据域
struct node_t *next;//指针域,指向自身结构体的指针
}link_node_t,*link_list_t;
int snum=6;//定义总人数
int main(int argc, char const *argv[])
{
//为链表申请空间
link_list_t h = (link_list_t)malloc(sizeof(link_node_t));
//赋初值
h->data=1;
h->next=h;
link_list_t r=h;//尾指向头,实现循环
for (int i = 0; i < snum-1; i++)
{
//插入链表
link_list_t pnew = (link_list_t)malloc(sizeof(link_node_t));
pnew->data=i+2;
//使用尾插法,每次将节点插入到末尾
pnew->next=r->next;
r->next=pnew;
r=pnew;
}
link_list_t a=h;
for (int i = 0; i < snum; i++)
{
printf("%d ",a->data);
a=a->next;
}
printf("\n");
link_list_t b = h;
//遍历,直到自己指向自己的时候,说明获胜者出现
while (b->next!=b)
{
link_list_t bdel=NULL;
//每次都数5个人,这里是指向第五个人的前一个的前一个
for (int i = 0; i < 3; i++)
{
b=b->next;
}
//将第五个人从循环链表中去掉
bdel = b->next;
//重新连接
b->next=bdel->next;
printf("del---%d\n",bdel->data);
//释放
free(bdel);
bdel=NULL;
b=b->next;
snum--;
a=h;
for (int i = 0; i < snum; i++)
{
printf("%d ",a->data);
a=a->next;
}
printf("\n");
}
return 0;
}