約瑟夫環問題的普通解法很簡單,就是不斷遍歷循環鏈表,刪除節點,假如有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;
}