约瑟夫环
题目描述
约瑟夫(Joseph)问题的一种描述是:编号为1,2,…,n的n个人按顺时针方向围坐一圈,每人持有一个密码(正整数)。一开始任选一个正整数作为报数上限值m,从第一个人开始按顺时针方向自1开始顺序报数,报到m时停止报数。报的人出列,将他的密码作为新的m值,从他在顺时针方向上的下一个人开始重新从1报数,如此下去,直至所有人全部出列为止。试设计一个程序求出出列顺序。
基本要求
利用单向循环链表存储结构模拟此过程,按照出列的顺序印出各人的编号。
测试数据
m的初值为20;n=7,7个人的密码依次为:3,1,7,2,4,8,4,首先m值为6(正确的出列顺序应为6,1,4,7,2,3,5)。
实现提示
程序运行后,首先要求用户指定初始报数上限值,然后读取各人的密码。可设n≤30。此题所用的循环链表中不需要“头结点”,请注意空表和非空表的界限。
选作内容
向上述程序中添加在顺序结构上实现的部分。
思路
首先定义一个指针 p
指向 rear
。然后进入一个循环,在循环中,首先进行报数,报数的次数是当前的上限值 m
。具体的操作是,p
指针沿着链表向前移动 m-1
次,然后 p
指向的节点的下一个节点就是需要移除的节点。
定义一个临时指针 tmp
指向 p
的下一个节点(需要移除的节点),然后输出 tmp
的 id
,并将 tmp
的 data
(密码)赋值给 m
作为新的报数上限值。接着,将 p
的 next
指针指向 tmp
的下一个节点,这样就实现了移除 tmp
节点的操作。最后,释放 tmp
节点的内存。
循环继续进行,直到链表中只剩下一个节点,这时 p
的下一个节点就是 p
本身,输出 p
的 id
并结束。
代码
#include <algorithm>
#include <iostream>
#define AUTHOR "HEX9CF"
using namespace std;
using Status = int;
using ElemType = int;
const int N = 1e6 + 7;
const int TRUE = 1;
const int FALSE = 0;
const int OK = 1;
const int ERROR = 0;
const int INFEASIBLE = -1;
// const int OVERFLOW = -2;
int n, m;
ElemType a[N];
struct ListNode {
int id;
ElemType data;
ListNode *next;
};
using LinkedList = ListNode *;
Status initList(LinkedList &rear) {
rear = NULL;
return OK;
}
Status pushBack(LinkedList &rear, int id, ElemType data) {
ListNode *newNode = (ListNode *)malloc(sizeof(ListNode));
if (!newNode) {
return ERROR;
}
newNode->id = id;
newNode->data = data;
if (rear) {
newNode->next = rear->next;
rear->next = newNode;
rear = newNode;
} else {
newNode->next = newNode;
rear = newNode;
}
return OK;
}
Status display(LinkedList rear) {
if (!rear) {
return ERROR;
}
ListNode *p = rear->next;
do {
cout << p->data << " ";
p = p->next;
} while (p != rear->next);
cout << endl;
return OK;
}
void solve(LinkedList &rear, int m) {
ListNode *p = rear;
do {
for (int i = 1; i < m && p; i++) {
p = p->next;
}
ListNode *tmp = p->next;
cout << tmp->id << " ";
m = tmp->data;
p->next = tmp->next;
free(tmp);
} while (p->next != p);
cout << p->id << "\n";
}
int main() {
cin >> n >> m;
for (int i = 0; i < n; i++) {
cin >> a[i];
}
LinkedList rear;
initList(rear);
for (int i = 0; i < n; i++) {
pushBack(rear, i + 1, a[i]);
}
// display(rear);
solve(rear, m);
return 0;
}