数据结构考研复习--线性表3(约瑟夫环)

约瑟夫环这个在一开始看的时候是一个相当蛋疼的问题,本节将为大家讲述约约瑟夫环利用循环链表以及递归来进行求解

**约瑟夫环问题的原来描述为,设有编号为1,2,……,n的n(n>0)个人围成一个圈,从第1个人开始报数,报到m时停止报数,报m的人出圈,再从他的下一个人起重新报数,报到m时停止报数,报m的出圈,……,如此下去,直到所有人全部出圈为止。当任意给定n和m后,设计算法求n个人出圈的次序。 稍微简化一下。
问题描述:n个人(编号0~(n-1)),从0开始报数,报到(m-1)的退出,剩下的人继续从0开始报数。求胜利者的编号。
思路:容易想到的就是用环链表来做,构建一个环链表,每个结点的编号为0, 1, …… n-1。每次从当前位置向前移动m-1步,然后删除这个结点。最后剩下的结点就是胜利者。**

我们先来非递归的算法

void JosephusProblem_Solution1(int n, int m)    //n个人,每m退出
{
    int  i = 0;
    LinkList *pm;
    LinkList *pcur;
    LinkList *head = (LinkList *)malloc(sizeof(LinkList));
    LinkList *plast;

    pcur = head;
    pcur->next = head;
    head->data = 0;

    //构造循环链表
    for (i = 1; i <10;i++)
    {
        pm = (LinkList *)malloc(sizeof(LinkList));
        pm->data = i;
        pcur->next = pm;
        pcur = pm;
    }
    pcur->next = head;

//over
    pcur = head;

    while(pcur != pcur->next)
    {
        //前进m-1步
        for (i = 0;i<m-1;i++)
        {
            plast = pcur;
            pcur = pcur->next;
        }
        //删除
        plast->next = pcur->next;
        free(pcur);
        pcur = plast->next;
    }

    printf("%d ",pcur->next->data);
}

这样的效率显然不是最高的,时间复杂度o(mn),

接下来看递归算法

公里公道的说,这个递归算法真不好想。

我们先反过来想,如果只有一个人,那么他一定就是我们要求的,如果有两个人,那么他一定跟如果只有一个人的那种情况有关,通过只有一个人我们一定会得到一些线索,同理,我们算n个人的约瑟夫环,必然跟n-1个人的约瑟夫环有关,……一定跟2个人的有关,一定跟一个人的有关。那么到底有什么规律呢?这是我们即将要讨论的问题

我们假设m = 8 , n = 3

1>>很显然第一个被删除的数是(m-1)%n

2>>假设第二轮开始的数是K,那么只有n-1个人

    K -------> 0
    K+1------> 1
    K+2------> 2    //假设最终他是胜利者
    ...
    k-2-----> n-2

那么我就知道,这n-1个人,如果说我们现在知道了胜利者,他的编号是X,那么说他在链表中一开始是(k+x)%n,
其中, k = m%n,带入式子我们知道其实对于n个人,胜利者的编号是(X+m)%n

还记得我们的X是什么吗???—>n-1个人时的胜利者

那么简而言之,要求n个人最终的胜利者,我们只需要知道n-1个人时候的情况就行了,同理要知道n-1个人必须先求出n-2个人………..必须先求出1个人的情况,一个人编号自然是0,转化成代码就是

fun(1) = 0;
fun(n) = ( fun(n-1) + m ) %n;
int JosephusProblem_Solution2(int n, int m )
{
    if (n==1)
    {
        return 0;
    }
    return (JosephusProblem_Solution2(n-1, m) + m) % n;

}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值