约瑟夫环问题

一、             实验目的

  1. 熟悉线性表的操作和应用;
  2. 利用顺序表的存储结构解决约瑟夫环问题。

二、             实验原理

1. 问题描述:设编号为1,2,…,n(n>0)个人按顺时针方向围坐—圈,从第一个人开始报数,当报到第M个人时,该人出圈。然后接着报,L个人出圈或圈里还剩(N-L)个人。

2. 方法实现:利用线性表中循环链表的结构特点,每个节点表示一个人。用一个程序模拟人的报数出圈,1表示人还在圈里,0表示人已经出圈了。当第L个人出圈之后,报数程序结束,输出最后的在圈子里的人的情况。

3. 程序设计思路:

⑴先定义一个链表节点的结构体,结构体中data的值用来表示该节点所表示的人是否出圈,*next指针指向下一节点;

⑵用一个函数初始化一个n个节点的链表,并把最后一节点的*next指针指向头结点,以便形成循环链表。

⑶用一函数将指针所指向的整个循环链打印输出。

⑷用一函数模拟循环报数出圈:函数中采用三重循环,外层循环为报数出圈的人数,即第L个人出圈后停止报数;中层循环为报数的数值,即循环M次直到报到M的人出圈;内层循环用来排除已经出圈了的人,报数时遇到节点data值为0(即已经出圈了的人)则循环,直到节点data值为1(即未出圈的人)后退出本循环继续报数。

三、             实验程序

//========================================================

#include<iostream.h>

/*****************************************************************

函数功能:           定义一个链表的结构体

*****************************************************************/

struct node

{

       int data;

       node *next;

};

/*****************************************************************

函数功能:           初始化一个n个节点的循环链表,值分别为1

*****************************************************************/

node *Initnode(int n)     //

{

       node *head,*p;

       head=p=new node;

       for(int i=1;i<=n-1;i++)

       {

              p->data=1;      //i           //将每个节点的值赋为1,表示该节点的人未被提出

              p->next=new node;        //节点指针指向新创建的节点

              p=p->next;

       }

       p->data=1;      //n                                            

       p->next=head;               //将最后一个节点的指针指向头结点,以便形成循环链表

       return head;

}

/*****************************************************************

函数功能:           显示当前人数情况

*****************************************************************/

void Print(node *head,int n)                //(节点起始位置,总共要显示人数)

{

       node *q;

       q=head;                                      //将q节点指向头结点

       for(int i=0;i<n;i++)

       {

              cout<<q->data;                    //输出当次报数后所剩人的排队情况

              q=q->next;

       }

       cout<<endl;

}

/*****************************************************************

函数功能:           报数踢人

*****************************************************************/

void Done(node *head,int n,int m ,int k)    

{                                               //(节点起始位置,总人数,报数,提出人数)

       node *p;

       p=head;

       for(int j=0;j<k;j++)                     //该循环为踢出人,共循环k次

       {

              for(int i=1;i<m;i++)      //该循环为报数的次数

              {

                     while(p->data==0) //如果该节点已经被踢出了,则从下一个没被踢出的节点数

                     {

                            p=p->next;

                     }

                     p=p->next;            //每数一次,指针指向下一个节点

              }

              while(p->data==0)        //如果该节点已经被踢出了,则从下一个没被踢出的节点数

              {

                     p=p->next;

              }

              p->data=0;                    //将报数为m的人提出

              cout<<"第"<<(k+1)<<"次报数结果为:"<<' ';

              Print(head,n);               //显示每次报数后的情况

       }

}

/*****************************************************************

函数功能:           主函数

*****************************************************************/

void main()

{

       node *head;   

       int a=0;

       int m,n,l;

       cout<<"请分别输入总人数N,每次报数M,及踢出L个人:";

       cin>>n>>m>>l;

       head=Initnode(n);                        //头结点指向初始化好的循环链表

       Done(head,n,m,l);                       //开始报数踢人

}

原文地址:https://www.cnblogs.com/fickleness/p/3148959.html