约瑟夫问题描述:设由n个人围坐在一个圆桌周围,现从第s个人开始从1报数,数到m的人出列,然后从出列的下一个人重新开始从1报数,数到m的人在出列.......如此反复,知道所有人都出列,求出出列的顺序。
算法思路:由于约瑟夫问题是n个人围坐在一圈,所以采用循环链表实现,因为报数是可能循环到开始,所以使用不到头结点的循环链表结构。
算法步骤:
(1)在不带头结点的循环链表中查找第s个结点,用p作为第s个结点的指针。
(2)从p所指的节点开始计数查找第m个结点,pre指向p的前驱。
(3)输出该结点元素值。
(4)删除该结点,同时将该结点下一个结点指针作为当前指针即p指针,重复步骤(2),直到链表中所有结点都被删除为止。
算法程序如下:
#include"stdio.h"
#include"stdlib.h"
#define truer 1
#define false 0
int n = 6;
typedef int Datatype;
typedef struct node {
Datatype data;
struct node *next;
}LNode, *Linklist;
Linklist Creat_Linklist()
{
Linklist head, p, q;
int i;
Datatype data;
p = q = NULL;
head = (Linklist)malloc(sizeof(LNode));
if (!head)
{
printf("空间申请失败!\n");
return false;
}
else
{
head= NULL;
}
printf("输入每个人所表示的元素:");
for (i = 0;i < n;i++)
{
p = (Linklist)malloc(sizeof(LNode));
if (!p)
{
printf("申请空间失败!\n");
return false;
}
scanf_s("%d", &data);
p->data = data;
if (head== NULL)
{
q = p;
head = q;
}
else
{
q->next = p;
q = p;
}
}
q->next = head;
return head;
}
void Printf_Linklist(Linklist josephus )
{
Linklist p;
int i;
p = josephus;
printf("输出链表:");
for (i = 0;i < n;i++)
{
printf("%5d", p->data);
p = p->next;
}
printf("\n");
}
int Josephus_Linklist(Linklist josephus, int s, int m)
{
Linklist p, pre;
int count;
if (!josephus)
{
printf("表中无元素!\n");
return false;
}
p = josephus;
for (count = 1;count < s;count++)
p = p->next;
printf("输出约瑟夫序列:");
while (p!=p->next)
{
pre = p->next;
while (pre->next != p) pre = pre->next;
for (count = 1;count < m;count++)
{
pre = p;
p = p->next;
}
printf("%5d",p->data );
pre->next = p->next;
free(p);
p = pre->next;
}
printf("%5d",p->data );
free(p);
printf("\n");
return truer;
}
int main()
{
int s, m;
Linklist josephus;
josephus = Creat_Linklist();
Printf_Linklist(josephus);
printf("输入第一个报数人的编号:");
scanf_s("%d",&s);
printf("输入报到数为:");
scanf_s("%d", &m);
Josephus_Linklist(josephus, s, m);
return truer;
}
程序实现如下: