循环链表——约瑟夫问题

约瑟夫问题

约瑟夫问题具体描述
设有编号为1,2,3,···,n的n(n>0)个人按顺时针方向围坐一圈,每个人手持一个随机产生的密码(正整数)。现从第k个人开始按顺时针的方向从1开始报数,报数上限是第一个人持有的密码m,报到m的人出列。然后将出列人持有的密码作为新的m的值,从下一个人开始重新从1开始报数,如此下去,直到所有人全部出列为止。
约瑟夫问题分析
很显然这是一个线性结构,可以用线性表来表示。进行的主要操作是报数、出列,这相当于对线性表进行删除操作,因此宜选用链表存储结构,每个结点代表一个人。n个人围坐成一圈循环报数,则利用单循环链表解决本问题更容易。因此需创建一个含有n个结点的单循环链表,每个结点的数据域可以用来存储结点的编号和密码,密码可由随机函数产生。结点的指针域指向下一结点的位置。第一次报数前首先应找到第k个结点,然后从它开始报数。为了找到报数为m的结点,需要从第k个结点开始计数,当找到报数为m的结点后,删除该结点,并且需要把该结点的密码作为新的m值,从该结点开始重新报数,如此重复,直到链表为空为止。
例题

编号是1,2,……,n的n个人按照顺时针方向围坐一圈,每个人持有一个密码(正整数)。一开始任选一个正整数作为报数上限值m,从第一个仍开始顺时针方向自1开始顺序报数,报到m时停止报数。报m的人出列,将他的密码作为新的m值,从他的顺时针方向的下一个人开始重新从1报数,如此下去,直到所有人全部出列为止。请设计一个程序输出出列顺序。
提示:存储结构采用不带头结点的循环单链表,结点结构如下:

typedef struct Node
{ int ID;
int password;
struct Node *next;
}LNode,*LinkList;
要求:
(1)编写建立循环单链表的函数,依次输入每个人的ID和password建立不带头结点的循环单链表。
(2)编写函数,按照规则依次删除相应的元素。
(3)main()函数调用(1)和(2)中的函数,输出约瑟夫序列。
Input
输入n
输入m
第1行为n
第2行为m
接下来每行表示每个人的ID和password
Output
依次输出出列者的ID
每输出一个人的ID换行。
Sample Input
8
4
1 3
2 1
3 9
4 2
5 4
6 7
7 4
8 6
Sample Output
4
6
7
3
5
8
2
1
HINT
注意:处理m=1的特殊情况。

代码如下

#include <stdio.h>
#include <stdlib.h>
typedef struct Node
{  int ID;
   int password;
   struct Node *next;
}LNode,*LinkList;
LinkList CreateList(LinkList L,int num);
void OutNum(LinkList L,int theFirstNum);
int main()
{
    LinkList L = NULL;
    int num;
    int theFirstNum;
    scanf("%d",&num);
    scanf("%d",&theFirstNum);
    L = CreateList(L,num);
    OutNum(L,theFirstNum);
    return 0;
}

LinkList CreateList(LinkList L,int num)
{
    LinkList s,p;
    int i = 1;
    L = (LinkList)malloc(sizeof(LNode));
    scanf("%d %d",&L->ID,&L->password);
    L->next = NULL;
    p = L;
    while(i<num)
    {
        s = (LinkList)malloc(sizeof(LNode));
        scanf("%d",&s->ID);
        scanf("%d",&s->password);
        s->next = NULL;
        p->next = s;
        p = s;
        i++;
    }
    p->next = L;
    return L;
}
void OutNum(LinkList L,int theFirstNum)
{
    LinkList p,q,m;
    int password,i;
    password = theFirstNum;
    p = L;
    while(p->next != p)
    {
        for(i=1;i<password;i++)
        {
            q = p;
            p = p->next;
        }
        password = p->password;
        q->next = p->next;
        printf("%d\n",p->ID);
        free(p);
        p = q->next;
    }
    printf("%d\n",p->ID);

}

  • 2
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值