1.5 约瑟夫环是个经典的问题。有M个人围坐成一圈,编号依次从1开始递增,现从编号为1的人开始报数,报到N的人出列,然后再从下一人开始重新报数,报到N的人出列;重复这一过程,直至所有人出列。求出列次序。本题要求用循环单链表实现。提示:开始时将循环单链表的指针变量设为空,设计实现尾部添加一人函数Append,添加第1人时,将结点的指针域指向自己,后面新添加人员时,在循环单链表指针变量所指尾部后添加新结点,并始终将循环单链表指针变量指向新添加结点,对应M个人的循环单链表中有M个结点;报数时,报到指定数后输出对应结点里的人员编号,并将该结点从链表中删除。题目输入包括M、N两个正整数,题目要求按出队列顺序输出他们的编号。 输入格式: 正整数M、N 输出格式: 出队列次序,1行,每个数据占4位。
时间: 2024-03-05 07:48:37 浏览: 151
好的,下面是我的回答:
这是一个经典的约瑟夫环问题,可以使用循环单链表来实现。首先,我们需要设计一个节点结构体,包含一个指向下一个节点的指针以及一个表示当前节点的编号的整数:
```
typedef struct Node {
int num; // 当前节点的编号
struct Node *next; // 指向下一个节点的指针
} Node;
```
接下来,我们需要实现一个尾部添加一人的函数`Append`,它可以将一个新的节点添加到循环单链表的尾部:
```
Node *Append(Node *tail, int num) {
Node *new_node = (Node *)malloc(sizeof(Node)); // 创建一个新节点
new_node->num = num; // 设置节点的编号为num
new_node->next = NULL; // 将新节点的指针域初始化为NULL
if (tail == NULL) { // 如果链表为空
new_node->next = new_node; // 将新节点的指针域指向自己
tail = new_node; // 将循环单链表的指针变量指向新节点
} else { // 如果链表不为空
new_node->next = tail->next; // 将新节点的指针域指向头节点
tail->next = new_node; // 将尾节点的指针域指向新节点
tail = new_node; // 将循环单链表的指针变量指向新节点
}
return tail; // 返回循环单链表的指针变量
}
```
现在,我们可以使用`Append`函数来创建一个包含M个节点的循环单链表:
```
Node *tail = NULL; // 循环单链表的指针变量初始化为空
for (int i = 1; i <= M; i++) {
tail = Append(tail, i); // 添加一个新节点
}
```
接下来,我们可以按照题目要求,依次报数并删除节点,直到所有节点都被删除:
```
Node *cur = tail->next; // cur指向循环单链表的第一个节点
Node *prev = tail; // prev指向循环单链表的最后一个节点
while (cur->next != cur) { // 当循环单链表中只有一个节点时退出循环
for (int i = 1; i < N; i++) { // 报数
prev = cur;
cur = cur->next;
}
printf("%4d", cur->num); // 输出出队列次序
prev->next = cur->next; // 从循环单链表中删除当前节点
Node *tmp = cur;
cur = cur->next;
free(tmp); // 释放当前节点的内存空间
}
printf("%4d", cur->num); // 输出最后一个出队列的人员编号
free(cur); // 释放最后一个节点的内存空间
```
完整代码如下:
阅读全文