描述
约瑟夫环是一个数学的应用问题:已知n个人(以编号1,2,3...n分别表示)围坐在一张圆桌周围。从编号为k的人开始报数,数到m的那个人出列;他的下一个人又从1开始报数,数到m的那个人又出列;依此规律重复下去,直到圆桌周围的人全部出列。输入
8 1 3 (n=8 k=1 m=3)输出
7 (剩下的那个)
思路:使用无头的双向循环链表
#include <stdio.h>
#include <stdlib.h>
typedef int datatype; // 定义链表节点数据类型为int
typedef struct link
{
datatype data; // 节点数据
struct link *pre; // 指向前一个节点的指针
struct link *next; // 指向下一个节点的指针
}link;
// 初始化链表,返回头结点指针
link *Initlink()
{
link *head=NULL;
return head;
}
// 尾插法插入节点
link* TailInsertLink(link *head, datatype data)
{
if(head==NULL) // 如果链表为空
{
head=(link*)malloc(sizeof(link)); // 分配内存空间创建头结点
if(head==NULL)
return NULL;
head->next=head;
head->pre=head;
head->data=data;
}
else
{
link *p=(link*)malloc(sizeof(link)); // 分配内存创建新节点
if(p==NULL)
{
printf("内存空间申请失败!\n");
return NULL;
}
p->data=data;
p->pre=head->pre;
p->next=head;
head->pre->next=p;
head->pre=p;
}
return head;
}
// 循环右移链表
link* DriftLink(link *head, int pos)
{
if(head==NULL)
return NULL;
while(pos--)
head=head->next;
return head;
}
// 删除指定位置处的节点
link* DeleteLink(link *head, int pos)
{
if(head==NULL)
return NULL;
link *p=head;
while(--pos)
p=p->next;
head=p->next;
p->pre->next=p->next;
p->next->pre=p->pre;
free(p);
p=NULL;
return head;
}
// 遍历打印链表
void DisplayLink(link *head)
{
if(head==NULL)
return ;
link *p=head;
do
{
printf("%d\t",p->data);
p=p->next;
}
while(p!=head);
printf("\n");
}
int main(int argc, char *argv[])
{
link *head=Initlink(); // 初始化链表
int n,k,m;
printf("请输入n、k、m:\n");
scanf("%d%d%d",&n,&k,&m);
for(int i=1;i<=n;i++)
{
head=TailInsertLink(head,i); // 尾插法插入节点
}
DisplayLink(head); // 打印链表
//head=DriftLink(head,k); // 右移链表
// 依次删除节点,直到链表只剩下一个节点
while(head!=head->next)
{
head=DeleteLink(head,m);
}
printf("最终的赢家:%d\n",head->data); // 打印最终胜出者
return 0;
}