- 什么是约瑟夫问题?
约瑟夫问题是一个有名的问题,编号为1-N的N个人安顺时针围坐一圈,选取M为报数的上限,从第一个人按顺时针开始报数,将第M个人出列,,下一个人继续从1开始报数,报到M的人再出列,直至所有的人全部出列为止。
- 循环链表:
循环链表与单链表一样,是一种链式的存储结构。区别在于循环链表的最后一个节点的指针指向该循环链表的第一个节点或头结点,从而形成一个环。在建立一个循环链表的时候,要注意以下几点:
1、建立循环链表的时候,必须要让其最后一个节点指向链表的第一个节点或头结点,而不像单链表将租后节点的下一个指向NULL;
2、判断循环链表是否到表尾的方法是采用判断该节点的链域值(下一个节点的地址)是否是表头节点的方法,即当链域值等于表头指针时,说明已到链尾,而不像单链表中判断链域值是否为NULL。
- 用循环链表来解答约瑟夫问题:
为记录退出的人的先后顺序,采用一个顺序表进行存储。程序结束后在输出依次出列的人的编号。
程序代码如下:
//约瑟夫问题
#include <iostream>
using namespace std;
struct Node
{
int data;
Node *next;
};
//构造节点数量为n的单项循环链表
Node *node_create(int n)
{
Node *pRet=NULL;
if(n!=0)
{
int n_idx=1;
Node *p_node=NULL;
//构造n个节点
p_node=new Node[n];
if(p_node==NULL)
return NULL;
else
memset(p_node,0,n*sizeof(Node));//初始化内存
pRet=p_node;
while(n_idx<n)//构造循环链表
{
//初始化链表的每个节点从1到n
p_node->data=n_idx;
p_node->next=p_node+1;
p_node=p_node->next;
n_idx++;
}
p_node->data=n;
p_node->next=pRet;
}
return pRet;
}
int main()
{
Node *pList=NULL;
Node *pIter=NULL;
int n=20;//设置总人数有20人
int m=6;//初始报数的上限值
pList=node_create(n);//构造节点数量为n的循环链表
//约瑟夫循环取数
pIter=pList;
m%=n;
while(pIter!=pIter->next)//该链表不是空表
{
int i;
//取第m-1个节点
for(i=1;i<m-1;i++)
{
pIter=pIter->next;
}
//取第m个绩点的值
cout<<pIter->next->data<<" ";
//删除第m个节点
pIter->next=pIter->next->next;
pIter=pIter->next;
}
cout<<pIter->data<<endl;
delete []pList;
return 0;
}
运行结果如下: