约瑟夫问题是个有名的问题:N个人围成一圈,从第K个开始报数,第M个将被杀掉,最后剩下一个,其余人都将被杀掉。例如N=6,K=1,M=5,被杀掉的顺序是:5,4,6,2,3,1。
/*用循环链表实现约瑟夫问题*/
#include<iostream>
#include<stdlib.h>
using namespace std;
typedef struct LNode
{
int data;
struct LNode *next;
}LNode,*LinkList;
void Josephus(int n,int m,int k)
{
LinkList p,r,list=NULL;
int i;
for(i=1;i<=n;i++)
{
p=(LinkList)malloc(sizeof(LNode));//申请一个新的链结点
p->data=i;//存放第i个结点的编号
if(list==NULL)
list=p;
else
r->next=p;
r=p;
}
p->next=list;//至此,建立一个循环链表
p=list;
for(i=1;i<k;i++)
{
//r指向第k个结点,p指向第k-1个结点
r=p;
/*请注意,此行不是多余的,因为当k!=1,但m=1时如果没有这条语句,此时删除动作无法完成*/
p=p->next;
}//此时p指向第1个出发结点
while(p->next!=p)
{
for(i=1;i<m;i++)
{
r=p;
p=p->next;
}//p指向第m个结点,r指向第m-1个结点
r->next=p->next;//删除第m个结点
printf("%4d",p->data);//依次输出删除结点的编号
free(p);//释放被删除结点的空间
p=r->next;//p指向新的出发结点
}
printf("\n最后剩余的结点是:%4d\n",p->data);//输出最后一个结点的编号
}
int main()
{
int n,m,k;
cout<<"请输入结点的个数:"<<endl;
scanf("%d",&n);
cout<<"请输入报道报数周期是:"<<endl;
scanf("%d",&m);
cout<<"请输入从第几个数开始报数:"<<endl;
scanf("%d",&k);
Josephus(n,m,k);
return 0;
}
/*任务:
一群小孩围成一圈,任意假定一个数m,从第一个小孩起,顺时针方向数,每数到第m个小孩时,该小孩便离开。小孩不断离开,圈子不断缩小。最后剩下的一个小孩便是胜者。求胜者的编号?
要求
以面向对象技术进行程序设计
建立环状链表类
程序便于维护与扩张:如易于对小孩数量n和数数间隔m进行变化
改变获胜者数量,使其可设为任意值
可中途增加小孩人数
*/
/*结构体实现*/
#include<iostream>
#include<stdlib.h>
using namespace std;
typedef struct LNode
{
int data;
struct LNode *next;
}LNode,*LinkList;
class Jos
{
private:
int n,m,k,last;//结点个数,报数周期,报数起始数.
int index;//标记剩余人数,标记插入时r第一个的指向.
LinkList list,r;
public:
Jos(){list=NULL;r=NULL;}
void set();
void Josephus();
void Insert();
void is_add();
void print_Josephus();
}XPY;
void Jos:: set()//插入函数
{
cout<<"请输入结点的个数:"<<endl;
scanf("%d",&n);
cout<<"请输入报道报数周期是:"<<endl;
scanf("%d",&m);
cout<<"请输入从第几个数开始报数:"<<endl;
scanf("%d",&k);
cout<<"请输入剩余个数:"<<endl;
scanf("%d",&last);
}
void Jos:: Josephus()//建立一个循环链表
{
LinkList p;
int i;
index=n;//结点个数赋初值
for(i=1;i<=n;i++)
{
p=(LinkList)malloc(sizeof(LNode));//申请一个新的链结点
p->data=i;//存放第i个结点的编号
if(list==NULL)
list=p;
else
r->next=p;
r=p;
}
p->next=list;//至此,建立一个循环链表
}
void Jos:: Insert()//循环链表的插入
{
LinkList p=(LinkList)malloc(sizeof(LNode));
p->data=n+1;
n++;//个数加1
index++;//个数加1
p->next=r->next;
r->next=p;
r=p;
}
void Jos:: is_add()//中途添加函数
{
printf("是否添加成员(Y/N)\n");
char ch;
cin>>ch;
while(1)
{
system("cls");
ch=tolower(ch);//转换为全小写的
if(ch=='y')
Insert();
else if(ch=='n')
break;
else
printf("输入有误\n");
system("cls");
printf("是否继续添加成员(Y/N)\n");
cin>>ch;
}
}
void Jos:: print_Josephus()//循环的执行
{
LinkList p=list;
for(int i=1;i<k;i++)
{
r=p;
/*请注意,此行不是多余的,因为当k!=1,但m=1时如果没有这条语句,此时删除动作无法完成*/
p=p->next;
}//此时p指向第1个出发结点
printf("删除的结点号是:\n");
while(index>last)
{
for(int i=1;i<m;i++)
{
r=p;
p=p->next;
}//p指向第m个结点,r指向第m-1个结点
r->next=p->next;//删除第m个结点
printf("%3d",p->data);//依次输出删除结点的编号
free(p);//释放被删除结点的空间
// is_add();
p=r->next;//p指向新的出发结点
index--;//删除结点,个数减1
}
while(index--)//胜利者的输出
{
printf("\n最后剩余的结点是:%4d\n",p->data);//输出最后一个结点的编号
p=p->next;
}
}
int main()
{
XPY.set();
XPY.Josephus();
XPY.print_Josephus();
return 0;
}