实验要求
采用单向环表实现约瑟夫环。
请按以下要求编程实现:
(1)从键盘输入整数m,通过create函数生成一个具有m个结点的单向环表。环表中的结点编号依次为1,2,……,m。
(2)从键盘输入整数s(1<=s<=m)和n,从环表的第s个结点开始计数为1,当计数到第n个结点时,输出该第n结点对应的编号,将该结点从环表中消除,从输出结点的下一个结点开始重新计数到n,这样,不断进行计数,不断进行输出,直到输出了这个环表的全部结点为止。
例如,m=10,s=3,n=4。则输出序列为:6,10,4,9,5,2,1,3,8,7。
1.需求分析
本程序的任务是使用单向环表实现约瑟夫环。用户输入整数 m(节点数目),然后根据约瑟夫环规则,从给定的起始位置 s 和计数间隔 n 开始,输出序列并消除节点,直到所有节点都被输出。
2.概要设计
(1)抽象数据类型的定义
Node 结构体:表示环形链表的节点,包含数据成员 data(节点编号)和 next(指向下一个节点的指针)。
(2)主程序流程
① 输入节点数目 m、起始位置 s、计数间隔 n。
② 创建环形链表。
③ 执行约瑟夫环操作,输出符合规则的节点编号序列。
3.详细设计
(1)create 函数
根据输入的节点数目 m 创建一个具有 m 个节点的环形链表。
(2)josephus 函数
① 根据起始位置 s 和计数间隔 n,执行约瑟夫环操作。
② 遍历链表,找到指定位置的起始节点。
③ 循环输出满足条件的节点编号,删除节点并调整链表直至所有节点被输出。
4. 调试分析
在调试过程中,可能会遇到以下问题:
(1)节点删除及链表指针操作的正确性:确保节点的删除与链表指针的调整没有错误,避免出现内存泄漏或链表指针混乱的情况。
(2)计数规则和节点删除顺序:验证程序实现的约瑟夫环是否按照预期规则进行计数和节点删除。
5. 测试结果
使用 m=10、s=3、n=4 这组测试用例进行测试,预期输出序列为:6,10,4,9,5,2,1,3,8,7。测试结果应该与预期一致。
6.完整代码
#include <iostream>
//定义单向环形链表的节点结构
struct Node {
int data;//节点数据,这里表示节点编号
Node* next;//指向下一个节点的指针
Node(int value) : data(value), next(nullptr) {}//节点结构体构造函数
};
//创建单向环形链表
Node* create(int m) {
if (m <= 0) {
return nullptr;
}
//创建链表头节点
Node* head = new Node(1);
Node* current = head;
//依次创建 m-1 个节点,构成环形链表
for (int i = 2; i <= m; ++i) {
current->next = new Node(i);
current = current->next;
}
current->next = head;//将链表闭合成环形
return head;//将链表闭合成环形
}
//执行约瑟夫环操作
void josephus(int m, int s, int n) {
if (m <= 0 || s <= 0 || s > m || n <= 0) {
std::cout << "输入无效!" << std::endl;
return;
}
Node* head = create(m);//创建具有 m 个节点的环形链表
Node* current = head;
Node* prev = nullptr;
//创建具有 m 个节点的环形链表
for (int i = 1; i < s; ++i) {
prev = current;
current = current->next;
}
std::cout << "约瑟夫环输出序列为:";
while (m > 0) {
for (int i = 1; i < n; ++i) {
prev = current;
current = current->next;
}
std::cout << current->data << " ";//输出节点编号
//删除当前节点并调整链表
if (current == head) {
head = head->next;
}
prev->next = current->next;
delete current;
current = prev->next;
--m;//减少链表节点数目
}
std::cout << std::endl;
}
int main() {
int m, s, n;
std::cout << "输入节点数目 (m):";
std::cin >> m;
std::cout << "输入起始位置 (s):";
std::cin >> s;
std::cout << "输入计数间隔 (n):";
std::cin >> n;
josephus(m, s, n);
return 0;
}