约瑟夫环问题的普通解法很简单,就是不断遍历循环链表,删除节点,假如有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;
}