复杂链表的复制

 题目:实现一个函数来复制复杂链表。在复杂链表中,每一个节点除了有一个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;}

相关文章
相关标签/搜索