循环链表来实现约瑟夫环问题 c语言

  已知n个人(以编号1,2,3,…,n分别表示)围坐在一张圆桌周围。从编号为k的人开始报数,数到m的那个人出列;他的下一个人又从K开始报数,数到m的那个人又出列;依次规律重复下去,直到圆桌周围的人全部出列。
解:本题是约瑟夫环问题的实际场景。可用循环链表来实现。问题的核心步骤为: 建立无头结点的循环链表; 确定第一个报数人的位置; 不断从链表中删除结点,直到链表为空。

代码如下:

#include
#include
//不带头结点的循环链表  //约瑟夫环问题
typedef struct LNode
{
    int data;
    struct LNode* next;
}LNode,*LinkList;

void JOSEPHUS (int n,int k,int m)//n人数,k第一个开始报数的人,m出列者喊到的数
{
    LinkList p,head;
    //建立循环链表
    head=(LinkList)malloc(sizeof(LNode));
    head->data=1;
    head->next=NULL;
    p=head;
    for(int i=2;i<=n;++i)
    {
       LinkList  s=(LinkList)malloc(sizeof(LNode));
       s->data=i;
       s->next=NULL;
       p->next=s;
       p=p->next;
    }
    p->next=head;

    //找到尾结点,也就是第一个结点的上一个结点
    LinkList tail=head;
    while(tail->next!=head)
    {
       tail=tail->next;
    }
    //找编号为k的人
    p=head;
    while(p->data!=k)
    {
       tail=p;
       p=p->next;
    }
    //只有当p->next==p时,说明链表中只剩p结点了
    while(p->next!=p)
    {
       //找到从p开始报数,报m的人,tail始终为p的上一个结点,为删除p做准备
       for(int i=1;i<m;++i)
       {
          tail=p;//tail跟上p,tail为p的前驱结点
          p=p->next;
       }
       tail->next=p->next;
       printf("出列人编号:%d\n",p->data);
       free(p);//删除p
       p=tail->next;//p指向删除后的下一个结点,重新进入循环
    }
    //只剩p一个结点
    printf("出列人编号:%d\n",p->data);
    free(p);
}

int main()
{
    JOSEPHUS(5,3,2);//测试用例
    return 0;
}

运行结果如下:
循环链表来实现约瑟夫环问题 c语言_第1张图片

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