題目:實現一個函數來複制複雜鏈表。在複雜鏈表中,每一個節點除了有一個pNext 指針指向下一個節點外,還有一個pSibling 指向鏈表中的任意節點或者NULL。ios
下圖是一個含有5 個節點的複雜鏈表,圖中實線箭頭表示pNext 指針,虛線箭頭表示 pSibling 指針。爲簡單起見,指向 NULL的指針沒有畫出。函數
注:在複雜鏈表的節點中,除了有指向下一個節點的指針,還有指向任意節點的指針。spa
typedef struct LNode
{
ElemType data;
struct LNode *pNext;
struct LNode *pSibling;
}ListNode, *LinkList;指針
(一)對該問題的第一反應是把複製過程分紅兩部分,第一步是複製原始鏈表上的每個節點,並用 pNext 指針鏈接起來;第二步是設置每個節點的 pSibling指針。假設原始鏈表中的某個節點 N 的 pSibling指向節點 S,因爲 S 的位置在鏈表中可能在 N 的前面,也可能在 N 的後面,因此要定位 S 的位置須要從原始鏈表的頭結點開始找。若是從原始鏈表的頭結點開始沿着 pNext 通過 s 步找到節點 S,那麼在複製鏈表上節點 N' 的 pSibling 離複製鏈表的頭結點的距離也應該是 s 步。用着總辦法能夠爲複製鏈表上的每個節點設置 pSibling 指針。然而,時間複雜度爲 O(N^2)。io
(二)可使用輔助空間:一樣分爲兩步:第一步仍然是複製鏈表,同時將<N , N'>的配對信息放到一個哈希表中。第二步仍是設置複製鏈表的 pSibling 指針。若是在原始鏈表中節點 N 的 pSibling 指向節點 S, 那麼在複製鏈表中,對應的 N' 應該指向 S'。因爲有了哈希表,能夠用 O(1) 的時間根據 S 找到 S'。效率
這種方法至關於用空間換取時間。即,以 O(n) 的空間消耗來獲得 O(n) 的時間複雜度。stream
(三)在不使用輔助空間的狀況下實現 O(n) 的時間效率。List
1)該方法的第一步仍然是根據原始鏈表的每一個節點 N 建立對應的 N'。此時,咱們將 N' 鏈接在 N 的後面。以下圖所示。方法
//1. 複製原始鏈表的任意節點N 並建立新節點 N',再把 N' 鏈接到 N 的後面
void CopyNode(LinkList complexList)
{
ListNode *pNode = complexList->pNext;
while(pNode != NULL)
{
ListNode* pCopy = new ListNode();
pCopy->data = pNode->data;
pCopy->pNext = pNode->pNext;
pCopy->pSibling = NULL;im
pNode->pNext = pCopy;
pNode = pCopy->pNext;
}
}
2)第二步設置複製出來的節點的 pSibling。假設原始鏈表上的 N 的pSibling 指向節點 S, 那麼其對應複製出來的 N' 是 N 的pNext 指向的節點,一樣 S' 是 S 的pNext 指向的節點。設置的 pSibling 如上圖的紅色虛線。
//2. 調整複製節點 N' 的pSibling 的指向
void ConnectSiblingNodes(LinkList complexList)
{
ListNode *pNode = complexList->pNext;
while(pNode != NULL)
{
ListNode *pCopy = pNode->pNext;
if(pNode->pSibling != NULL)
pCopy->pSibling = pNode->pSibling->pNext;
pNode = pCopy->pNext;
}
}
3)第三步是將這個長的鏈表拆分紅兩個複雜鏈表:把奇數位置的節點用 pNext 鏈接起來就是原始的複雜鏈表;把偶數位置上的節點用 pNext 鏈接起來就是複製出來的複雜鏈表。
//3. 將第二步獲得的鏈表拆分紅兩個鏈表
ListNode* ReConnectNodes(LinkList complexList)
{
ListNode *pNode = complexList->pNext;
ListNode *pCopyHead = NULL; //複製後獲得的複雜鏈表的頭結點
ListNode *pCopyNode = NULL; //複製後的複雜鏈表的各個節點,用於鏈接複製後的鏈表
if(pNode != NULL)
{
pCopyHead = pCopyNode = pNode->pNext;
pNode->pNext = pCopyHead->pNext;
pNode = pNode->pNext;
}
while(pNode != NULL)
{
pCopyNode->pNext = pNode->pNext;
pCopyNode = pCopyNode->pNext;
pNode->pNext = pCopyNode->pNext;
pNode = pNode->pNext;
}
return pCopyHead;
}
4)將上面的三步合起來,就是複製複雜鏈表的完整過程。
//4. 將前面的三步整合起來就是複製複雜鏈表的完整過程
ListNode* CopyLinkList(LinkList pHead)
{
CopyNode(pHead);
ConnectSiblingNodes(pHead);
return ReConnectNodes(pHead);
}
完整代碼:
//複雜鏈表的複製
#include<iostream>
using namespace std;
typedef char ElemType;
typedef struct LNode
{
ElemType data;
struct LNode *pNext;
struct LNode *pSibling;
}ListNode, *LinkList;
ListNode* InsertLinkList(LinkList L, ElemType e)
{
if(L == NULL)
{
L = new ListNode();
L->pNext = NULL;
L->pSibling = NULL;
}
ListNode *pTempt = L;
while(pTempt->pNext != NULL)
{
pTempt = pTempt->pNext;
}
ListNode *pNode = new ListNode();
pNode->data = e;
pNode->pSibling = NULL;
pNode->pNext = NULL;
pTempt->pNext = pNode;
return L;
}
//複雜鏈表的建立
ListNode* CreateComplexList()
{
ListNode *pHead = NULL;
for(char a = 'A'; a < 'F'; a++)
pHead = InsertLinkList(pHead, a);
ListNode *pNode = pHead->pNext;
ListNode *pTemp = NULL;
while(pNode != NULL)
{
if(pNode->data == 'A')
pNode->pSibling = pNode->pNext->pNext;
if(pNode->data == 'B')
{
pTemp = pNode;
pNode->pSibling = pNode->pNext->pNext->pNext;
}
if(pNode->data == 'D')
pNode->pSibling = pTemp;
pNode = pNode->pNext;
}
return pHead;
}
void PrintComplexList(LinkList L)
{
ListNode *pNode = L->pNext;
while(pNode != NULL)
{
cout << "節點:"<< pNode->data << " next: ";
if(pNode->pNext != NULL)
cout << pNode->pNext->data << " sibling: ";
else
cout << "NULL" << " sibling: ";
if(pNode->pSibling != NULL)
cout << pNode->pSibling->data << endl;
else
cout << "NULL" << endl;
pNode = pNode->pNext;
}
}
//1. 複製原始鏈表的任意節點N 並建立新節點 N',再把 N' 鏈接到 N 的後面
void CopyNode(LinkList complexList)
{
ListNode *pNode = complexList->pNext;
while(pNode != NULL)
{
ListNode* pCopy = new ListNode();
pCopy->data = pNode->data;
pCopy->pNext = pNode->pNext;
pCopy->pSibling = NULL;
pNode->pNext = pCopy;
pNode = pCopy->pNext;
}
}
//2. 調整複製節點 N' 的pSibling 的指向
void ConnectSiblingNodes(LinkList complexList)
{
ListNode *pNode = complexList->pNext;
while(pNode != NULL)
{
ListNode *pCopy = pNode->pNext;
if(pNode->pSibling != NULL)
pCopy->pSibling = pNode->pSibling->pNext;
pNode = pCopy->pNext;
}
}
//3. 將第二步獲得的鏈表拆分紅兩個鏈表
ListNode* ReConnectNodes(LinkList complexList)
{
ListNode *pNode = complexList->pNext;
ListNode *pCopyHead = NULL; //複製後獲得的複雜鏈表的頭結點
ListNode *pCopyNode = NULL; //複製後的複雜鏈表的各個節點,用於鏈接複製後的鏈表
if(pNode != NULL)
{
pCopyHead = pCopyNode = pNode->pNext;
pNode->pNext = pCopyHead->pNext;
pNode = pNode->pNext;
}
while(pNode != NULL)
{
pCopyNode->pNext = pNode->pNext;
pCopyNode = pCopyNode->pNext;
pNode->pNext = pCopyNode->pNext;
pNode = pNode->pNext;
}
return pCopyHead;
}
//4. 將前面的三步整合起來就是複製複雜鏈表的完整過程
ListNode* CopyLinkList(LinkList pHead)
{
CopyNode(pHead);
ConnectSiblingNodes(pHead);
return ReConnectNodes(pHead);
}
int main()
{
ListNode *pHead = NULL;
ListNode *pCopyHead = new ListNode();
pCopyHead->pNext = NULL;
pCopyHead->pSibling = NULL;
pHead = CreateComplexList();
cout << "原始列表爲:" << endl;
PrintComplexList(pHead);
pCopyHead->pNext = CopyLinkList(pHead);
cout << "複製的列表爲:" << endl;
PrintComplexList(pCopyHead);
system("pause"); return 0;}