约瑟夫环问题C++实现:功能需求及代码解析
约瑟夫环问题C++实现:功能需求及代码解析
约瑟夫环问题是一个经典的数学问题,可以描述为:n个人围成一圈,从第1个人开始报数,报到m的人出圈,然后从出圈人的下一个人开始继续报数,直到最后剩下一个人为止。本篇文章将使用C++语言实现约瑟夫环问题,并对代码进行详细解释。
功能需求如下:
- **初始化链表头:**定义一个节点,并将其'next'指针指向自身。
- **建立循环链表:**根据输入的总人数,创建一个循环单链表,每个节点的'id'依次递增。
- **移动节点到开始的序号:**根据输入的开始序号,将'p'和'r'指针移动到对应的节点位置。
- **循环出圈:**当链表中的节点数大于1时,循环报数和删除节点,直到只剩下一个节点。
- **输出最后剩下的人:**输出最后剩下的节点的'id'号。
代码实现:
#include <iostream>
using namespace std;
class List {
public:
//链表结构体
struct node {
int id;
node* next;
};
int m, startId, n;//m报数的最大值,n总人数,startId开始序号。
node* p, * r;
//构造函数:
List() {
p = NULL;
}
//析构函数:
~List() {};
//初始化链表头:
void startset(node*& m) {
m = new node;
m->next = m;
}
//建立循环链表(尾插法):
void setlist(int x) {
node* q;
r = p;
p->id = 1;
for (int i = 2; i <= x; i++) {
q = new node;
q->id = i;
r->next = q;
r = q;
}
r->next = p;//尾指针指向头节点。
}
//核心环节:
void runlist() {
int i = 1;
startset(p);//初始化链表头。
cout << "请输入总人数:";
cin >> n;
cout << "请输入报数最大值:";
cin >> m;
cout << "请输入报数开始时的序号:";
cin >> startId;
system("pause");
cout << "依次出列人员的编号:\n";
setlist(n);//创建循环单列表。
//移动节点,到开始的那个数:
while (--startId) {
p = p->next;
r = r->next;
}
//当圈不为1个人时,循环出圈:
if (p->next != p) {
do {
if (i == m)//报数与m相等时。
{
i = 1;
cout << p->id << "号\n";
r->next = p->next;
delete(p);//删除结点。
p = r->next;
}
else//报数不满m时,继续循环。
{
r = r->next;
p = p->next;
++i;
}
} while (p->next != p);
}
//到最后剩下的人:
cout << "最后一位是:" << p->id << "号" << endl;
}
};
int main() {
List list;
list.runlist();
return 0;
}
代码解析:
- 链表结构体定义:
struct node {
int id;
node* next;
};
定义了一个名为'node'的结构体,用来表示链表中的节点。每个节点包含一个'id'和一个指向下一个节点的指针'next'。
- 初始化链表头:
void startset(node*& m) {
m = new node;
m->next = m;
}
该函数用来初始化链表头。首先使用'new'运算符创建一个新的节点,然后将该节点的'next'指针指向自身,形成一个循环链表。
- 建立循环链表:
void setlist(int x) {
node* q;
r = p;
p->id = 1;
for (int i = 2; i <= x; i++) {
q = new node;
q->id = i;
r->next = q;
r = q;
}
r->next = p;//尾指针指向头节点。
}
该函数用来建立循环链表。首先将头节点的'id'设为1,然后使用循环创建其他节点,并将每个节点的'id'设为i。最后将尾节点的'next'指针指向头节点,形成循环链表。
- 移动节点到开始的序号:
while (--startId) {
p = p->next;
r = r->next;
}
该循环用来将'p'和'r'指针移动到指定的开始节点。每次循环将'p'和'r'指针都向后移动一个节点,直到'startId'减为0。
- 循环出圈:
do {
if (i == m)//报数与m相等时。
{
i = 1;
cout << p->id << "号\n";
r->next = p->next;
delete(p);//删除结点。
p = r->next;
}
else//报数不满m时,继续循环。
{
r = r->next;
p = p->next;
++i;
}
} while (p->next != p);
该循环用来模拟报数出圈的过程。每次循环都会判断当前报数是否等于'm',如果是则将当前节点删除,并将'r'指针指向下一个节点,否则将'r'和'p'指针都向后移动一个节点。循环条件为'p->next != p',即链表中只有一个节点时停止。
- 输出最后剩下的人:
cout << "最后一位是:" << p->id << "号" << endl;
循环结束后,'p'指针指向最后剩下的节点,输出该节点的'id'号。
总结:
本篇文章详细介绍了约瑟夫环问题的C++实现,包括链表的初始化、循环链表的建立、节点移动、循环出圈和最后剩下的人的输出。提供了完整的代码示例,并对每个功能进行了详细解释。希望本文能帮助读者更好地理解约瑟夫环问题,并掌握相关代码实现。
原文地址: https://www.cveoy.top/t/topic/qvPh 著作权归作者所有。请勿转载和采集!