面試題26:複雜鏈表的複製
1.題目描述
請實現函數 ComplexListNode*Clone(ComplexListNode* pHead)複製一個複雜鏈表。在複雜鏈表中,每個結點除了有一個 m_pNext指針指向下一個結點外,還有一個m_pSibling指向鏈表中的任意結點或者NULL。結點的C++定義如下:
struct ComplexListNode
{
int m_nValue;
ComplexListNode* m_pNext;
ComplexListNode8 m_pSibling;
};
2.題目分析
下圖是一個含有5個結點的複雜鏈表。圖中實線箭頭表示 m_pNext指針,虛線箭頭表示 m_Sibling指針。爲簡單起見,指向NULL的指針沒有畫出。
第一步是根據原始鏈表的每個結點N創建對應的N'。這時,我們把N'鏈接在N的後面。上圖的鏈表經過這一步之後的結構,如下圖所示。
完成這一步的代碼如下:
void CloneNodes(ComplexListNode* pHead)
{
ComplexListNode* pNode = pHead;
while(pNode != NULL)
{
ComplexListNode* pCloned = new ComplexListNode();
pCloned->m_nValue = pNode->m_nValue;
pCloned->m_pNext = pNode->m_pNext;
pCloned->m_pSibling = NULL;
pNode->m_pNext = pCloned;
pNode = pCloned->m_pNext;
}
}
第二步設置複製出來的結點的 m_pSibling。假設原始鏈表上的N的m_pSibling指向結點S,那麼其對應複製出來的N'是N的m_pNext指向的結點,同樣S'也是S的m_pNext指向的結點。設置 m_pSibling之後的鏈表如下圖所示。
下面是完成第二步的參考代碼:
void ConnectSiblingNodes(ComplexListNode* pHead)
{
ComplexListNode* pNode = pHead;
while(pNode != NULL)
{
ComplexListNode* pCloned = pNode->m_pNext;
if(pNode->m_pSibling != NULL)
{
pCloned->m_pSibling = pNode->m_pSibling->m_pNext;
}
pNode = pCloned->m_pNext;
}
}
第三步把這個長鏈表拆分成兩個鏈表:把奇數位置的結點用m_pNext鏈接起來就是原始鏈表,把偶數位置的結點用 m_pNext鏈接起來就是複製出來的鏈表。上圖中的鏈表拆分之後的兩個鏈表如下圖所示。
要實現第三步的操作,也不是很難的事情。其對應的代碼如下:
ComplexListNode* ReconnectNodes(ComplexListNode* pHead)
{
ComplexListNode* pNode = pHead;
ComplexListNode* pClonedHead = NULL;
ComplexListNode* pClonedNode = NULL;
if(pNode != NULL)
{
pClonedHead = pClonedNode = pNode->m_pNext;
pNode->m_pNext = pClonedNode->m_pNext;
pNode = pNode->m_pNext;
}
while(pNode != NULL)
{
pClonedNode->m_pNext = pNode->m_pNext;
pClonedNOde = pClonedNode->m_pNext;
pNode->m_pNext = pClonedNode->m_pNext;
pNode = pNode->m_pNext;
}
return pClonedHead;
}
3.code
ComplexListNode* Clone(ComplexListNode* pHead)
{
CloneNodes(pHead);
ConnectSiblingNodes(pHead);
return ReconnectNodes(pHead);
}