【C++OJ_单继承】约瑟夫环(结构体+循环链表)
题目描述
约瑟夫环是一个数学的应用问题:已知n个人(以编号1,2,3…n分别表示)围坐在一张圆桌周围。从编号为k的人开始报数,数到m的那个人出列;他的下一个人又从1开始报数,数到m的那个人又出列;依此规律重复下去,直到圆桌周围的人全部出列。
用循环链表实现约瑟夫环。
输入
输入多组测试数据,每组测试数据格式如下:
人数n(>0)开始位置k(>0)报数m(>0)
输出
对每组测试数据,输出出圈顺序。
输入样例
3 1 2
5 3 3
输出样例
2 1 3
5 3 2 4 1
参考代码
#include <iostream>
using namespace std;
struct node //定义一个结构体,用来表示每一个结点
{
int data; //表示每一个结点的数字,也就是序号
node *next; //定义一个结构体指针,用来指向后一个结点
};
class circle
{
private:
node *rear; //定义节点形指针,用来指向最后一个结点
public:
circle(int n); //构造函数,用来创建约瑟夫环
~circle(){}; //析构函数
void print(int m, int k); //展示出圈顺序
};
circle::circle(int n) //实现建立环形链接的链表
{
node *s = NULL;
rear = new node; //初始化指针
rear->data = 1; //首先,将第一个结点数据域赋值为1
rear->next = rear;
for (int i = 2; i <= n; i++) //从2开始
{
s = new node; //定义一个Node形指针s,指向新建的一个结点
s->data = i; //将新建的结点数字域赋值为i
s->next = rear->next; //将尾结点和节点连接起来,构成循环链表
rear->next = s; //将尾指针指向下一个结点,也就是s所指的结点
rear = s; //将尾结点移动到新建结点s
}
}
void circle::print(int m, int k)
{
node *pre = rear, *p = rear->next; //定义一个Node类型的p
int count = 1; //定义一个计数的count使其为1
while (p != NULL && count < k) //从count到开始位置k
{
pre = pre->next;
p = p->next;
count++;
}
count = 1;
while (p->next != p) //如果p->next所指向的结点是p的话,表示这已经是最后一个结点了,该节点为最后出圈
{
if (count < m) // count来计数,每次到了m就出圈对应结点
{
pre = p; //将pre等于p,以便于表示p变换前的结点
p = p->next; // p向下一结点移动
count++; //移动一次count加一次
}
else //每次count=m时候就开始删除对应结点
{
pre->next = p->next; //首先从环中摘去要删除的p所指的结点
cout << p->data << " "; //输出结点p所数据域,输出在屏幕上表示p结点的出圈
delete p; //删除空间
p = pre->next; // p指向下一结点,以便于下一轮的循环
count = 1; //将计数恢复为1,以便下一轮计数
}
}
cout << p->data << endl;
delete p; //输出最后再删除这一结点,释放内存
}
int main()
{
int n, m, k;
while (cin >> n >> k >> m)
{
circle r(n);
r.print(m, k);
}
return 0;
}