面试题26:复杂链表的复制

本文介绍了如何复制一个复杂链表,该链表中的每个节点包含一个指向下一个节点的指针和一个随机指针,可以指向链表中的任意节点。复制过程分为三步:创建副本节点、连接副本节点的随机指针、断开并重新连接节点,实现时间复杂度为O(n)。并通过示例代码展示了具体实现。
1.给定一个复杂的链表的数据结构,复制这个链表,在这个数据结构中,每个节点有两个指针,一个指针指向下一个结点,另一个指针指向链表中的任意结点。
数据结构:
struct ComplexListNode
{
	int                 m_nValue;
	ComplexListNode*    m_pNext;
	ComplexListNode*    m_pSibling;//随机指针
};

分析:
如下图所示是一个复杂链表的示意图,实现标志指向下一节点的指针,虚线表示指向任意结点的m_pSibling指针。如果m_pSibling为空的话,则并没有指出。

第一步:根据原始链表的每个结点在对应的位置后面复制一个节点N‘ ,如下:

第二步:将复制的节点部分的随机指针按照原始链表的对应关系连接起来

第三步:将整个长的链表拆分成两个链表,奇数位置的节点为复制的结点,偶数位置的接点是原始的结点。整个时间复杂度是O(n)。


源码:
#include<iostream>
using namespace std;
//复杂链表结构
struct ComplexListNode
{
	int                 m_nValue;
	ComplexListNode*    m_pNext;
	ComplexListNode*    m_pSibling;//随机指针
};
//创建结点
ComplexListNode* CreateNode(int nValue);
//链接结点
void BuildNodes(ComplexListNode* pNode, ComplexListNode* pNext, ComplexListNode* pSibling);
//打印链表
void PrintList(ComplexListNode* pHead);

//复制结点并插入
void CloneNodes(ComplexListNode* pHead);
//链接复制结点的随机指针
void ConnectSiblingNodes(ComplexListNode* pHead);
//断开重连接
ComplexListNode* ReconnectNodes(ComplexListNode* pHead);
ComplexListNode* Clone(ComplexListNode* pHead);

int main()
{
	//          -----------------
	//         \|/              |
	//  1-------2-------3-------4-------5
	//  |       |      /|\             /|\
	//  --------+--------               |
	//          -------------------------
	ComplexListNode* pNode1 = CreateNode(1);
	ComplexListNode* pNode2 = CreateNode(2);
	ComplexListNode* pNode3 = CreateNode(3);
	ComplexListNode* pNode4 = CreateNode(4);
	ComplexListNode* pNode5 = CreateNode(5);

	BuildNodes(pNode1, pNode2, pNode3);
	BuildNodes(pNode2, pNode3, pNode5);
	BuildNodes(pNode3, pNode4, NULL);
	BuildNodes(pNode4, pNode5, pNode2);

	printf("The original list is:\n");
	PrintList(pNode1);

	ComplexListNode* pClonedHead = Clone(pNode1);

	printf("The cloned list is:\n");
	PrintList(pClonedHead);

	system("PAUSE");
	return 0;
}
//创建结点
ComplexListNode* CreateNode(int nValue)
{
	ComplexListNode* pNode = new ComplexListNode();

	pNode->m_nValue = nValue;
	pNode->m_pNext = NULL;
	pNode->m_pSibling = NULL;

	return pNode;
}
//连接结点
void BuildNodes(ComplexListNode* pNode, ComplexListNode* pNext, ComplexListNode* pSibling)
{
	if(pNode != NULL)
	{
		pNode->m_pNext = pNext;
		pNode->m_pSibling = pSibling;
	}
}
//打印
void PrintList(ComplexListNode* pHead)
{
	ComplexListNode* pNode = pHead;
	while(pNode != NULL)
	{
		printf("The value of this node is: %d.\n", pNode->m_nValue);

		if(pNode->m_pSibling != NULL)
			printf("The value of its sibling is: %d.\n", pNode->m_pSibling->m_nValue);
		else
			printf("This node does not have a sibling.\n");

		printf("\n");

		pNode = pNode->m_pNext;
	}
}
//复制链表
ComplexListNode* Clone(ComplexListNode* pHead)
{
	CloneNodes(pHead);
	ConnectSiblingNodes(pHead);
	return ReconnectNodes(pHead);
}
//复制原结点并插入
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;
	}
}
//连接复制结点的随机指针
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;
	}
}
//重新断开连接
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;
}

结果:


评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值