问题描述:
设有n个人围坐在圆桌周围,现从某个位m(1<=m<=n)上的人开始报数,报数到k的人就站出来。下一个人,即原来的第k+1位置上的人又从1开始报数,再报数到k的人站出来。依此重复下去,直到全部的人都站出来为止。输出这个序列。
经典的使用循环链表问题
算法分析:
1.圆桌可以使用单循环链表来实现,出列就相当于在链表中删除元素。
2.首先程序需要两个函数①创建一个不带头结点的循环链表(模拟圆桌)②另一个函数实现出列操作
存储示意图:
每次找出需要出列的结点,要经过k次循环移动指针。全部结点出列需要经过n个k次循环。
参考代码:
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<stdlib.h>
#define OVERFLOW -1
typedef int Elemtype; //定义数据元素类型
typedef struct Cnode //结点类型定义
{
Elemtype data;
struct Cnode *next;
}CNode;
CNode *joseph; //定义全局变量
//创建单循环链表
int Creat_list(CNode *clist, int n)
{
CNode *p=NULL;
CNode *q=NULL;
int i;
clist = NULL;
for (i = n; i >= 1; i--)
{
p = (CNode *)malloc(sizeof(CNode));
if (p == NULL)
{
return OVERFLOW; //存储分配失败
}
p->data = i; //赋值
p->next = clist;
clist = p;
if (i == n)
q = p; //q指向尾部
}
q->next = clist; //尾部和头部连接起来建立循环链表
joseph = clist; //将创建好的循环链表头指针赋给全局变量
return 1;
}
//寻找指定元素输出
int Joseph(CNode *clist, int m, int n, int k)
{
int i;
CNode *p, *q;
if (m > n) //起始位置不对
{
return -1;
}
if (!Creat_list(clist, n))
{
return -1; //链表创建失败
}
p = joseph; //p指向创建好的循环链表
for (i = 1; i < m; i++)
{
p = p->next; //*p指向m位置的结点
}
while (p)
{
for (i = 1; i < k - 1; i++) //找到要输出结点的前一个结点
p = p->next;
q = p->next; //q指向要输出的结点
printf(" %d", q->data);
if (p->next == p)
{
p = NULL; //删除最后一个结点
}
else
{
p->next = q->next;
p = p->next;
free(q);
}
}
clist = NULL;
return 1;
}
void main()
{
int m = 0;
int n = 0;
int k = 0;
CNode *clist;
clist = NULL; //初始化clist
printf("请输入圆桌总人数:", n);
scanf("%d", &n);
printf("请输入首次开始报数的位置:", m);
scanf("%d", &m);
printf("第几个人出列?", k);
scanf("%d", &k);
Creat_list(clist, n);
printf("输出序列如下:\n");
Joseph(clist, m, n, k);
printf("\n");
system("pause");
}
测试结果: