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

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

思路如下:

在不用辅助空间的情况下实现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)