约瑟夫环的普通解法及优化

本文介绍约瑟夫环问题的两种解决方法:一种是普通解法,通过不断遍历循环链表并删除节点来找出最后存活的人,时间复杂度为O(n*m);另一种是优化解法,直接计算出最后存活的节点位置,再删除其他节点,时间复杂度为O(n)。
摘要由CSDN通过智能技术生成

约瑟夫环问题的普通解法很简单,就是不断遍历循环链表,删除节点,假如有n个人,等到第m个人报数时杀掉这个人,即删除这个节点,直到只剩下一个人。

struct Node
{
    Node(int data)
        :_data(data)
        ,_pNext(NULL)
    {}

    int _data;
    Node* _pNext;
};

1,普通解法,时间复杂度为O(n*m),因为删掉一个节点需要遍历 m 次;
代码实现

Node* josephuskill1(Node* pHead,int m)//第m个人被杀掉
{
    if(pHead == NULL)
        return NULL;

    //构环
    Node* pCur = pHead;
    while(pCur->_pNext)
        pCur = pCur->_pNext;
    pCur->_pNext = pHead;

    pCur = pHead;
    int num = m;
    Node* pRev;
    while(pCur->_pNext != pCur)//只剩下一个节点
    {
        num = m;
        while(--num)
        {
            pRev = pCur;
            pCur = pCur->_pNext;
        }
        pRev->_pNext = pCur->_pNext;//删除节点
    }

    pHead = pCur;
    return pHead;
}

测试代码

void funtest1()
{
    Node node1(1);
    Node node2(2);
    Node node3(3);
    Node node4(4);
    Node node5(5);

    node1._pNext = &node2; 
    node2._pNext = &node3;
    node3._pNext = &node4;
    node4._pNext = &node5;

    Node* ret = josephuskill1(&node1,3);
}
int main()
{
    funtest1();
    getchar();
    return 0;
}

2.约瑟夫环的优化,时间复杂度为O(n)

思路:我们直接直到最后存活的节点,然后删除其余节点,保存这个节点;
问题是:我们怎样直接找到该节点呢?
这里写图片描述

代码实现:

int GetLive(int i,int m)//i是链表中总的节点个数,m是第m个报数的人被杀掉,返回存活的新的编号
{
    if(i == 1)//当链表中只剩下一个节点的时候,此时该节点对应的新编号就是1
        return 1;
    return (GetLive(i-1,m)+m-1)%i+1;//递归,当i=2时,我们得到存活节点(i=2)对应两个节点时的编号,直到i = N 时
}


Node* josephuskill2(Node* pHead,int m)//第m个人被杀掉
{
    if(pHead == NULL)
        return NULL;

    //构环
    Node* pCur = pHead;
    while(pCur->_pNext)
        pCur = pCur->_pNext;
    pCur->_pNext = pHead;


    int num = 1;
    pCur = pHead;

    while(pCur->_pNext != pHead)
    {
        num++;//获取链表中节点的个数
        pCur = pCur->_pNext;
    }
    int retnum = GetLive(num,m);//得到的retnum就是存活节点在总数为num个节点的编号

    //根据编号找到节点
    while(--retnum)
    {
        pHead = pHead->_pNext;
    }
    pHead->_pNext = pHead;
    return pHead;
}

测试代码:

void funtest1()
{
    Node node1(1);
    Node node2(2);
    Node node3(3);
    Node node4(4);
    Node node5(5);

    node1._pNext = &node2; 
    node2._pNext = &node3;
    node3._pNext = &node4;
    node4._pNext = &node5;

    Node* ret = josephuskill2(&node1,3);
}
int main()
{
    funtest1();
    getchar();
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值