约瑟夫问题
(本题要求用循环链表实现)
约瑟夫问题是一个经典的问题。已知n个人(不妨分别以编号1,2,3,...,n 代表)围坐在一张圆桌周围,从编号为 k 的人开始,从1开始顺时针报数1, 2, 3, ...,顺时针数到m 的那个人,出列并输出。然后从出列的下一个人开始,从1开始继续顺时针报数,数到m的那个人,出列并输出,...依此重复下去,直到圆桌周围的人全部出列。
输入:n,k,m
输出:按照出列的顺序依次输出出列人的编号,编号中间相隔一个空格,每10个编号为一行。
非法输入的对应输出如下
a)
输入::n、k、m任一个小于1
输出:n,m,k must bigger than 0.
b)
输入:k>n
输出:k should not bigger than n.
例
输入
9,3,2
输出
4 6 8 1 3 7 2 9 5
测试用例1:
输入:
9,3,2↵
输出:
4 6 8 1 3 7 2 9 5↵
测试用例2:
输入:
10,12,3↵
输出:
k should not bigger than n.↵
代码如下:
#include<stdio.h>
#include<malloc.h>
#include<stdlib.h>
#define ListSize 100
typedef int DataType;
typedef struct Node
{
DataType data;
struct Node *next;
}ListNode,*LinkList;
/*函数声明*/
LinkList CreateCycList(int n);/*创建一个长度为n的循环单链表的函数声明*/
void Josephus(LinkList head,int n,int m,int k); /*在长度为n的循环单链表中,报数为编号为m的出列*/
void DisplayCycList(LinkList head);/*输出循环单链表*/
int main()
{
LinkList h;
int n,k,m;
scanf("%d,%d,%d",&n,&k,&m);
if(n<1||k<1||m<1)printf("n,m,k must bigger than 0.\n");
else if(k>n)printf("k should not bigger than n.\n");
else
{
h=CreateCycList(n);
Josephus(h,n,m,k);
}
system("pause");
return 0;
}
void Josephus(LinkList head,int n,int m,int k) /*在长度为n的循环单链表中,从第k个人开始报数,数到m的人出列*/
{
ListNode *p,*q;
int i,j;
p=head;
for(i=1;i<k;i++) /*从第k个人开始报数*/
{
q=p;
p=p->next;
}
for(j=1;j<=n;j++)
{
if (j==1)j=1;
else if((j-1)%10==0)printf("\n");
else printf(" ");
for(i=1;i<m;i++) /*数到m的人出列*/
{
q=p;
p=p->next;
}
q->next=p->next; /*将p指向的结点删除,即报数为m的人出列*/
printf("%d",p->data);
free(p);
p=q->next; /*p指向下一个结点,重新开始报数*/
}
printf("\n",p->data);
}
LinkList CreateCycList(int n) /*宏定义和单链表类型定义*/
{
LinkList head=NULL;
ListNode *s,*r;
int i;
for(i=1;i<=n;i++)
{
s=(ListNode*)malloc(sizeof(ListNode));
s->data=i;
s->next=NULL;
if(head==NULL)
head=s;
else r->next=s;
r=s; }
r->next=head;
return head; }
void DisplayCycList(LinkList head) /*输出循环链表的每一个元素*/
{ ListNode *p;
p=head;
if(p==NULL)
{ printf("该链表是空表");
return; }
while(p->next!=head) /*如果不是最后一个结点,输出该结点*/
{ printf("%4d",p->data);
p=p->next; }
printf("%4d\n",p->data);/*输出最后一个结点*/ }