作者 陈越 单位 浙江大学
编号为 1,2,3,⋯,n 的 n 个人按照顺时针方向围坐一圈。从第一个人开始按照顺时针方向从 1 开始报数,当报到指定的数 m 时,报 m 的人出列。再从他顺时针方向的下一位人开始重新从 1 开始报数,报到 m 的人出列,如此下去,直到所有人都出列。请设计算法用单向循环链表模拟约瑟夫问题的出列过程,输出出列的顺序。
函数接口定义:
List JosephusProblem( int n, int m );
其中List
结构定义如下:
typedef struct ListNode *Position; /* 指针即结点位置 */
struct ListNode {
ElemSet data; /* 存储数据*/
Position next; /* 线性表中下一个元素的位置 */
};
typedef struct HeadNode *List;
struct HeadNode {
Position head; /* 单链表头指针 */
int length; /* 表长 */
};
函数接口定义中,n
是总人数,m
是出列间隔的人数。该函数须将出列人的编号按照出列顺序存为带空头结点的单链表,并返回该链表的表头指针。
裁判测试程序样例:
#include <stdio.h>
#include <stdlib.h>
typedef int ElemSet;
typedef struct ListNode *Position; /* 指针即结点位置 */
struct ListNode {
ElemSet data; /* 存储数据 */
Position next; /* 线性表中下一个元素的位置 */
};
typedef struct HeadNode *List;
struct HeadNode {
Position head; /* 单链表头指针 */
int length; /* 表长 */
};
List JosephusProblem( int n, int m );
void PrintList( List list )
{ /* 顺序输出链表结点数据 */
Position p;
p = list->head->next; /* p指向第1个结点 */
while (p) {
printf("%d ", p->data);
p = p->next;
}
}
int main(void)
{
List list;
int n, m;
scanf("%d %d", &n, &m);
list = JosephusProblem(n, m);
PrintList( list );
return 0;
}
/* 你的代码将被嵌在这里 */
输入样例:
10 3
输出样例:
3 6 9 2 7 1 8 5 10 4
答案:
List JosephusProblem(int n, int m)
{
Position head = (Position)malloc(sizeof(struct ListNode)); // 头节点
Position current = head; // 当前节点
Position newNode;
// 创建循环链表
for (int i = 1; i <= n; i++)
{
newNode = (Position)malloc(sizeof(struct ListNode));
newNode->data = i;
current->next = newNode;
current = newNode;
}
current->next = head->next; // 完成循环链表
// 创建结果链表
List resultList = (List)malloc(sizeof(struct HeadNode));
Position resultHead = (Position)malloc(sizeof(struct ListNode));
Position resultTail = resultHead; // 结果链表的尾部
resultList->head = resultHead;
resultList->length = 0;
// Josephus 问题处理
Position prev = head; // prev 指向当前节点的前一个节点
Position toRemove = head->next; // 要删除的节点
int count = 1;
while (resultList->length < n)
{
if (count != m)
{
// 如果还没到第 m 个节点,继续前进
prev = toRemove;
toRemove = toRemove->next;
count++;
}
else
{
// 删除第 m 个节点
prev->next = toRemove->next;
resultTail->next = toRemove;
resultTail = resultTail->next;
resultTail->next = NULL; // 结果链表尾部节点的 next 设为 NULL
// 更新要删除的下一个节点
toRemove = prev->next;
count = 1;
resultList->length++;
}
}
free(head); // 释放循环链表的头节点
return resultList;
}