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