C++ - 链式实现Josephus问题(不带头节点的单链表)

Josephus问题描述 :
     设有n个人围坐在一个圆桌周围,现从第s个人开始报数,数到第m的人出列、然后从出列的下一个人开始重新报数,数到第m的人又出列,如此反复直到所有人全部出列为止。

要求:对于任意给定的n、s、m,求出按出列次序得到的n个人员的序列。


/* 上机题1 - 单链表实现Josephus问题 */
#include 
#include 
using namespace std;

//单链表的结点定义
template        //单链表的节点类 
class link
{
public:
 T data;            //结点数据域 
 link *next;     //结点指针域 
 link(const T d, const link *next_value = NULL)               //link - 含参构造函数 ,const 保证传入的参数2不会被修改
 {
  data = d;
next = (link*)next_value;      //(link*)强制类型转换,因为next为(link*)类型,但next_value为(const link*)类型
 }                      
};

//单链表类型定义
template 
class ListJose
{
 private:
  link *h, *t, *p;              //指向头、尾、当前节点的指针
  int n, s, m;                     // n - 总人数、s - 从第s个人开始、 m - 报数间隔
  
 public:
     ListJose();                     //游戏初始化
  
  ~ListJose();                    //释放链表空间
  
  void play();                    //游戏实际过程算法
  
  void disp();                    //展示初始化后序列顺序 
};

//游戏初始化 
template 
ListJose::ListJose()
{
 cout << "请输入参与Josephus游戏的人数:";
    cin >> n;
 cout << "请输入游戏从第几个人开始(编号):" ;
 cin >> s;
 cout << "请输入游戏间隔:" ;
 cin >> m;
 
 //根据输入的总人数(n)创建链表 
 int i = 1;
 while( i <= n )
    {
     if( i == 1 )                      //头节点单独考虑 
     {
      p = new link(i);           // new、delete - 为运算符、所以不包含malloc.h头文件 
      h = p;                       // 但是 malloc() 和 free() - 库函数,得包含malloc.h头文件 
      t = p;
  }
  else                     //非头节点 
  {
   p = new link(i);
   t->next = p;
   t = p;
  }
  
  i++;
 }
} 
//析构函数 - 当 头指针(h)不在作用域时,自动销毁释放 
template 
ListJose::~ListJose()
{
 link *tmp;
 
 while( h != NULL )
 {
  tmp = h;
  h = h->next;
  delete tmp;
 }
 cout << "成功释放链表空间" << endl;
}
//输出链表所有节点数据函数 
template 
void ListJose::disp()
{
 p = h;
 while( p != NULL )
 {
  cout << p->data << " ";
  p = p->next;
 }
}

//Josephus问题求解的 - 核心算法 
//这里采用 - 报数到游戏间隔(m)时就直接输出此时编号,不再另设存储空间来保存输出编号信息
template 
void ListJose::play()
{
 int count = 0, k = 0;                          
 int num = 0;
    p = h;
 for( int i = 1; i < s; i++ )                                           // p 为指向报数起始位置的指针
 {
  p = p->next;                                                        // p 也再接下来的循环中充当着始终指向当前节点的指针
 }
 
 while( count < n )                                                 // count 为出序列人数循环计数变量,当count==n(总人数)时,循环结束
 {
  if( p->data != 0 ) k++;                                      // k 为报数间隔计数变量,k==m(报数间隔), 则k清0,重新计数
  
  if( k == m )
  {
   cout << p->data << " ";
   count++;
   p->data = 0;                                                          // 标记出序列的节点
   k = 0;
  }
  
  p = p->next;                                                  // 循环后移
  if( p == NULL ) p = h;                              // 当 p == t->next(尾节点的next指针), 这超出循环范围,( p = h )重新开始
 }
}

//主函数  
int main()
{
 ListJose A;                  //类模板的实例化 、 指定 template 中的T为int 
 
 cout << "游戏开始时顺序:";
 A.disp() ;
 cout << endl;
 cout << endl;
 
 cout << "Josephus问题结果:";
 A.play() ;
 cout << endl;
 cout << endl;
 
 return 0; 
}


以上代码都通过Dev - C++5.11版本编译运行通过,若有错误,欢迎同行者指出错误,相互学习。

你可能感兴趣的:(数据结构与算法)