题目描述:
设编号分别为:1,2,…n 的 n 个人围坐一圈。约定序号为 k (1<= k <=n) 的人从 1 开始计数,数到 m 的那个人出列,他的下一位又从 1 开始计数,数到 m 的人又出列,依次类推,直到所有人出列为止。
例子:
假设 n=8, k=3, m=4:
则出列序列为:(6,2,7,4,3,5,1,8)
算法思路:
用一个不带头结点的循环链表来处理此问题,先构成一个有 n 个结点单循环链表,然后从第 k 个结点起从 1 计数,记到 m 时对应结点从链表中删除,然后再从被删除结点的下一个结点起又从1开始计数…直到所有结点都出列时算法结束。
头文件 list.h:
#ifndef _LIST_H_
#define _LIST_H_
#include<stdio.h>
#include<stdlib.h>
//单项循环链表
typedef struct node{
int data;
struct node *next;
}listnode,*linklist;
linklist list_create(); //创建一个单向循环单链表
void list_show(linklist H); //打印单向循环链表的内容
void list_jose(linklist H,int k,int m); //joseph问题实现
linklist list_create() //创建一个单链表
{
linklist H,r,p;
int i,n;
loop:
printf("please input n:\n");
scanf("%d",&n);
if(n<0)
{
printf("n > 0\n");
goto loop; //当输入为负数,跳转到 loop:处重新输入
}
if((H = (linklist)malloc(sizeof(listnode))) == NULL)
{
printf("malloc failed\n");
return NULL;
}
H->data=1;
H->next=H;
r=H; //r指向尾部
for(i=2;i<=n;i++)
{
if((p = (linklist)malloc(sizeof(listnode))) == NULL)
{
printf("malloc failed\n");
return NULL;
}
p->data=i;
r->next=p;
r=p;
}
p->next=H;
return H;
}
void list_show(linklist H) //打印单链表的内容
{
linklist p=H;
while(p->next!=H)
{
printf("%d ",p->data);
p=p->next;
}
printf("%d\n",p->data); //因为最后一个结点指向头结点,所以在循环中没有打印出来
}
void list_jose(linklist H,int k,int m) //joseph问题实现
{
linklist r,p;
int i;
r=H;
//找到第k个结点
while(r->next->data != k)
{
r=r->next;
}
printf("k=%d\n",k);
while(r->next!=r) //循环结束的条件是就一个结点了
{
//循环结束后r指向m-1的位置
for(i=0;i<m-1;i++)
{
r=r->next;
}
p=r->next; //p指向要删除的结点
r->next=p->next;
printf("%d ",p->data);
free(p);
p=NULL;
}
//删除最后一个结点
printf("%d ",r->data);
free(r);
p=NULL;
}
#endif
测试文件 josephTest.c
#include "list.h"
int main()
{
linklist H;
int k,m;
H=list_create();
list_show(H);
printf("=======================\n");
printf("please input k and m:\n");
scanf("%d%d",&k,&m);
list_jose(H,k,m);
return 0;
}