约瑟夫环
[问题描述]
约瑟夫(Joseph)问题的一种描述是:编号为1,2,…,n的n个人按顺时针方向围坐一圈,每人持有一个密码(正整数)。一开始任选一个正整数作为报数上限值m,从第一个人开始按顺时针方向自1开始顺序报数,报到m时停止报数。报m的人出列,将他的密码作为新的m值,从他在顺时针方向上的下一个人开始重新从1报数,如此下去,直至所有人全部出列为止。试设计一个程序求出出列顺序。
[基本要求]
利用单向循环链表存储结构模拟此过程,按照出列的顺序印出各人的编号。
[测试数据]
由学生任意指定。
如:m的初值为20;n的值为7;密码:3,1,7,2,4,8,4;
(正确的输出结果应为6,1,4,7,2,3,5)。
(报告上要求写出多批数据测试结果)
[实现提示]
程序运行后首先要求用户输入初始报数上限值m,人数n,(设n≤30)。然后输入各人的密码。
[选作内容]
向上述程序中添加在顺序结构上实现的部分。
单循环链表实现:
实现:
DeleteNode(LinkList &L,LinkList &s,int &m)
函数实现了删除链表中的s结点并更新m的值,并添加了输出s结点编号的功能。
Josephus()
:不断寻找第m个结点,如果是头结点就跳过,找到后更新m的值并删除该结点,然后进行下一次寻找,直到链表中只有头结点为止。
typedef struct LNode
{
int data;//存放密码
int num;//存放编号
LNode* next;
}LNode,*LinkList;
void InitList(LinkList &L)//头结点初始化
{
L=new LNode;
L->next=NULL;
}
void CreateListTail(LinkList &L,int n)//尾插法创建单循环链表
{
LinkList p,r;
L=new LNode;
r=L;
for (int i = 1; i <= n; i++)
{
p=new LNode;
cin>>p->data;
p->num=i;
r->next=p;
r=p;
}
r->next=L;//循环链表
}
void DeleteNode(LinkList &L,LinkList &s,int &m)//删除指定位置的结点
{
if(s==L) return ;
else
{
LinkList q=L;
while (q->next!=s)
{
q=q->next;
}
q->next=s->next;
m=s->data;
cout<<s->num<<' ';
delete s;
}
}
void Josephus()//算法实现部分
{
LinkList L;
InitList(L);//20 7 3 1 7 2 4 8 4
int m,n;
cin>>m>>n;
CreateListTail(L,n);
LinkList p=L->next;
while (p)
{
if(p==L) break;
for (int i = 1; i < m; i++)
{
p=p->next;
if(p==L) p=p->next;
}
LinkList q=p->next;
DeleteNode(L,p,m);
p=q;
if(p==L) p=p->next;
}
}
顺序表实现:
顺序表的实现类似于静态数组实现
Josephus1():
利用p作为表示数组下标的指针,每次向后查找m就是访问第(p+m-1)%i (i为当前顺序表的长度)
个元素,输出其编号num并更新m的值,直到顺序表为空。
#define MAXSIZE 31
typedef struct
{
int data;//存放密码
int num;//存放编号
}Jos;
typedef struct
{
Jos *elem;
int length;
}SqList;
void InitList(SqList &L)//初始化顺序表
{
L.elem=new Jos[MAXSIZE];
if (!L.elem)
{
cout<<"false!"<<endl;
return ;
}
L.length=0;
}
void ListInsert(SqList &L,int i,int e)//顺序表插入
{
if ((i<1)||(i>L.length+1))
{
cout<<"false";
return ;
}
if(L.length==MAXSIZE) cout<<"false";
for (int j = L.length-1; j >= i-1; j--)
{
L.elem[j+1]=L.elem[j];
}
L.elem[i-1].data=e;
L.elem[i-1].num=i;
++L.length;
}
bool ListDelete(SqList &L,int i)//删除节点
{
if((i<1)||(i>L.length))
{
cout<<"error"<<endl;
return false;
}
for (int j = i; j <= L.length-1; j++)
{
L.elem[j-1]=L.elem[j];
}
--L.length;
//cout<<"success!"<<endl;
return true;
}
void Josephus1()//算法代码
{ //样例:20 7 3 1 7 2 4 8 4
SqList L;
InitList(L);
int m,n;
cin>>m>>n;
for (int i = 1; i <= n; i++)//输入部分
{
int x;
cin>>x;
ListInsert(L,i,x);
}
int p=0;
for (int i = L.length; i >= 1; i--)
{
p=(p+m-1)%i;
cout<<L.elem[p].num<<' ';
m=L.elem[p].data;
//cout<<"m:"<<m<<endl;
ListDelete(L,p+1);
}
}
运行实例
实例一:
20 7 3 1 7 2 4 8 4
6 1 4 7 2 3 5
实例二:
10 5 7 2 6 4 3
5 3 2 1 4