程序员面试题精选100题(49)-复杂链表的复制

本文介绍了一种不使用辅助空间,在O(n)时间内复制复杂链表的方法,包括节点复制、设置兄节点链接和拆分链表三个步骤。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

略有所悟:不一定总是从头到尾一气呵成,像这样的一个节点一个节点的复制,先合成一个整体,之后在分开也是复制。关键是这样省去了寻找复制节点的时间(因为每当复制当前节点时一定要找到原来父节点所在的位置)。

思路如下:

在不用辅助空间的情况下实现O(n)的时间效率。第三种方法的第一步仍然是根据原始链表的每个结点N,创建对应的N’。这一次,我们把N’链接在N的后面。实例中的链表经过这一步之后变成了:

                

                这一步的代码如下:

                /////////////////////////////////////////////////////////////////////////////////

// Clone all nodes in a complex linked list with headpHead,

// and connect all nodes with m_pNext link

/////////////////////////////////////////////////////////////////////////////////

void CloneNodes(ComplexNode* pHead)

{

    ComplexNode* pNode = pHead;

    while(pNode!= NULL)

    {

        ComplexNode* pCloned = new ComplexNode();

        pCloned->m_nValue = pNode->m_nValue;

        pCloned->m_pNext = pNode->m_pNext;

        pCloned->m_pSibling = NULL;

 

        pNode->m_pNext = pCloned;

 

        pNode = pCloned->m_pNext;

    }

}

                第二步是设置我们复制出来的链表上的结点的m_pSibling。假设原始链表上的N的m_pSibling指向结点S,那么其对应复制出来的N’是N->m_pNext,同样S’也是S->m_pNext。这就是我们在上一步中把每个结点复制出来的结点链接在原始结点后面的原因。有了这样的链接方式,我们就能在O(1)中就能找到每个结点的m_pSibling了。例子中的链表经过这一步,就变成如下结构了:

             

 这一步的代码如下:

                /////////////////////////////////////////////////////////////////////////////////

// Connect sibling nodes in a complex link list

/////////////////////////////////////////////////////////////////////////////////

void ConnectSiblingNodes(ComplexNode* pHead)

{

    ComplexNode* pNode = pHead;

    while(pNode!= NULL)

    {

        ComplexNode* pCloned = pNode->m_pNext;

        if(pNode->m_pSibling != NULL)

        {

            pCloned->m_pSibling =pNode->m_pSibling->m_pNext;

        }

 

        pNode = pCloned->m_pNext;

    }

}

                第三步是把这个长链表拆分成两个:把奇数位置的结点链接起来就是原始链表,把偶数位置的结点链接出来就是复制出来的链表。上述例子中的链表拆分之后的两个链表如下:

                

                要实现这一步,也不是很难的事情。其对应的代码如下:

                /////////////////////////////////////////////////////////////////////////////////

// Split a complex list into two:

// Reconnect nodes to get the original list, and itscloned list

/////////////////////////////////////////////////////////////////////////////////

ComplexNode* ReconnectNodes(ComplexNode* pHead)

{

    ComplexNode* pNode = pHead;

    ComplexNode* pClonedHead = NULL;

    ComplexNode* 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;

}

                我们把上面三步合起来,就是复制链表的完整过程:

/////////////////////////////////////////////////////////////////////////////////

// Clone a complex linked list with head pHead

/////////////////////////////////////////////////////////////////////////////////

ComplexNode* Clone(ComplexNode* pHead)

{

    CloneNodes(pHead);

    ConnectSiblingNodes(pHead);

    return ReconnectNodes(pHead);

}

// 程序员面试题精选100题(49)-复杂链表的复制.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include <iostream>
using namespace std;
#define N 6
struct ComplexNode
{
	char m_nValue;
	ComplexNode* m_pNext;
	ComplexNode* m_pSibling;
};
ComplexNode* constructList()//according to the next
{
	char ch;
	int i=0;
	ComplexNode* head=NULL,*p=NULL,*q=NULL;
	cout<<"construct list next"<<endl;
	while(i<N)
	{
		cin>>ch;
		if (head==NULL)
		{
			head = new ComplexNode;
			head->m_nValue=ch;
			head->m_pNext=NULL;
			head->m_pSibling=NULL;
			p=head;
		}
		else
		{
			q = new ComplexNode;
			q->m_nValue=ch;
			q->m_pNext=NULL;
			q->m_pSibling=NULL;
			p->m_pNext=q;
			p=p->m_pNext;
		}
		i++;
	}
	return head;
}
ComplexNode* constructListSibling(ComplexNode* head)// build the list need o(n*n) time. how to build the complex list within time of o(n),
{
	char ch1,ch2;
	int i=0;
	ComplexNode *p,*q;
	cout<<"construct list sibling"<<endl;
	while(i<N)
	{
		cin>>ch1;cin>>ch2;
		p=head;q=head;
		while(p&&p->m_nValue!=ch1)p=p->m_pNext;
		while(q&&q->m_nValue!=ch2)q=q->m_pNext;
		if (p&&q)//both are not Null
		{
			p->m_pSibling=q;
		}
		i++;
	}
	return head;
}
void printListNext(ComplexNode* head)
{
	ComplexNode* p=head;
	cout<<" printListNext: "<<endl;
	while(p!=NULL)
	{
		cout<<p->m_nValue<<" ";
		p=p->m_pNext;
	}
	cout<<endl;
}
void printListSibling(ComplexNode* head)
{
	ComplexNode* p=head;
	cout<<" printListSibling: "<<endl;
	while(p!=NULL)
	{
		cout<<p->m_nValue<<" ";
		p=p->m_pSibling;
	}
	cout<<endl;
}
ComplexNode* copyNext(ComplexNode* head)
{
	ComplexNode* p=head,*q,*cp,*cq;
	while(p!=NULL)
	{
		q=p->m_pNext;
		cp = new ComplexNode;
		cp->m_nValue=p->m_nValue;
		cp->m_pSibling=NULL;
		p->m_pNext=cp;
		cp->m_pNext=q;
		p=q;
	}
	return head;
}
ComplexNode* copySibling(ComplexNode* head)// for all the copy element are closely near to the last element
{
	ComplexNode* p=head,*q,*cp,*cq;
	while(p!=NULL)
	{
		if (p->m_pNext&&p->m_pSibling)
		{
			p->m_pNext->m_pSibling=p->m_pSibling->m_pNext;	
		}
		p=p->m_pNext->m_pNext;
	}
	return head;
}
void divideList(ComplexNode* head,ComplexNode* &head1,ComplexNode* &head2)
{
	ComplexNode*p=head,*q;//,*pt,*qt;
	if (head)
	{
		head1=head;
		head2=head->m_pNext;
	}
	else
		return ;
	p=head1;q=head2;
	while(p->m_pNext&&q->m_pNext)
	{
		p->m_pNext=q->m_pNext;
		p=p->m_pNext;

		q->m_pNext=p->m_pNext;
		q=q->m_pNext;
	}
	p->m_pNext=NULL;
	q->m_pNext=NULL;
	return;
}
int _tmain(int argc, _TCHAR* argv[])
{
	ComplexNode* head,*head1,*head2;
	head = constructList();
	head = constructListSibling(head);
	printListNext(head);
	printListSibling(head);
	//cout<<"after copy next"<<endl;
	//head = copyNext(head);
	//head = copySibling(head);
	//printListNext(head);
	//printListSibling(head);
	divideList(head,head1,head2);
	cout<<"head1 is"<<endl;
	printListNext(head1);
	printListSibling(head1);
	cout<<"head2 is"<<endl;
	printListNext(head2);
	printListSibling(head2);
	system("pause");
	return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值