约瑟夫环问题,编好为1,2,3....n的个人按顺时针围坐一圈,每人手持一个密码。一开始选定m=6,从第一个人开始顺时针方向自1开始顺序报数,报到m时停止报数。报m的人出列,将他的密码作为新的m值,从他在顺时针方向上的下一个人开始重新从1报数,如此下去,直至所有人全部出列为止,显示出列顺序,打印出编号。
#include <iostream>
#include <stdio.h>
using namespace std;
template <class T>
struct node
{
T data; //存取每个人手持的密码
T id; //存取每个人的序号
node<T> *next;
};
template <class T>
class linklist
{
private:
node<T> *head; //定义循环链表头节点
public:
linklist(){head=new node<T>; head->next=head;} //构造函数
linklist(T a[],int n);
int Joseph(int n); //约瑟夫环算法
void show_link(int n) //展示链表中节点的序号和手持的密码值
{
node<T> *p=head->next;
for(int i=0;i<n;i++)
{
cout<<"节点序号:"<<p->id<<",手持密码:"<<p->data<<endl;
p=p->next;
}
}
};
template <class T>
linklist<T>::linklist(T a[],int n)
{
head=new node<T>;
head->next=head; //头节点不存储任何值
node<T> *pr=head;
for(int i=0;i<n;i++)
{
node<T> *p=new node<T>;
p->data=a[i];
p->id=i+1;
pr->next=p; //采用尾插法插入节点
pr=p;
}
pr->next=head; //这一步一定不能忘,这是循环链表的关键
}
template <class T>
int linklist<T>::Joseph(int n) //约瑟夫环算法
{
int m=n;
int count=1,order=0;
node<T> *pr=head; //前一节点
node<T> *p=head->next; //当前节点
while(pr!=p->next) //不算头节点,如果节点数量等于1,跳出循环
{
if(p!=head&&count==m) //跳过头节点,如果报数等于m
{
node<T> *x=new node<T>;
x=p;
pr->next=p->next;
p=p->next; //删除该节点
order++;
printf("第%2d个出列,序号为%d",order,x->id);
cout<<endl;
m=x->data; //下次报数的m为该节点的密码
delete(x);
count=1; //下个节点报数从1开始
}
else
{
if(p!=head)
count++; //报数增加
pr=p; //保持pr与p的关系
p=p->next;
}
}
printf("第%2d个出列,序号为%d",++order,p->id);
delete(pr);
delete(p);
}
int main()
{
int a[7]={3,1,7,2,4,8,4}; //7个人密码的顺序
int m=6;
linklist<int> link(a,7);
link.show_link(7);
link.Joseph(m);
return 0;
}