複雜鏈表的複製

 題目:實現一個函數來複制複雜鏈表。在複雜鏈表中,每一個節點除了有一個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;}

相關文章
相關標籤/搜索