数据结构之复杂链表复制

数据结构之复杂链表的复制

1. 什么是复杂链表?

所谓复杂链表,指的是个链表的每个节点,有一个指向next指针指向下一个节点,还有一个random指针指向这个链表中的一个随机节点或者NULL。

什么意思呢?我们来看图说话

如图,每个结点都用next指针指向下一个结点的同时,还用random指针指向任意的结点,注意这里的random指针的指向是随心所欲的,可以指向任何结点(包括NULL)。

2. 怎样复制?

那么我们怎么样对这样的链表进行复制呢?很多人的第一反应是先将每个结点的random指针所指向的信息记录下来,然后再根据记录下的信息进行复制。
这就会有一个问题:既然是复制链表,那么复制得来的链表的每个结点都是新开辟的,有着自己的空间——这个空间一定不是原链表相应结点的空间。我们怎么找到random指针所指向的新空间的地址呢?有一种方法:开辟一个N*N的数组,用来存放原链表每个结点的之间的关系。然而这种方法的时间和空间开销是巨大的。

这里提供一种对复杂链表复制的方案。一共分为三步:
1. 给原链表每个结点后插入值相同的新结点
2. 给新插入结点的随机指针域赋值
3. 将新结点从原来表上重新拆下来

第一步:给原链表每个结点后插入值相同的新结点:

第二步:给新插入结点的随机指针域赋值。以值为1的结点为例,它的结点记为p,由p结点复制过来的结点记为pC。关键代码为:pC->random = p->random->next; 需要注意的一点就是当一个结点的random指针指向NULL时,由该结点复制得来的结点的random指针直接置为NULL。

第三步:将新结点从原来表上重新拆下来。以值为1的结点为例,它的结点记为p,由p结点复制过来的结点记为pC。关键代码为:p->next = pC->next; pC->next = p->next->next;


最终效果为:

假设链表长度为n,那么总的时间复杂度为O(n),空间复杂度为O(1)。

typedef struct PNode{
    DataType data;
    struct PNode *next;
    struct PNode *random;
}*PNode, Node;

PNode AddNode(DataType data)        //增加结点
{
    PNode p = (PNode)malloc(sizeof(Node));
    if (p != NULL)
    {
        p->data = data;
        p->next = NULL;
        p->random = NULL;
        return p;
    }
    assert(p);
    return NULL;
}

PNode CopyComplexList(PNode pHead)   // 复杂链表复制
{
    PNode pHead2 = NULL;
    PNode pNext = NULL; //原链表的当前结点
    PNode pCur = NULL;  //原链表当前结点的下一个结点
    if (pHead == NULL)
    {
        return NULL;
    }

//给原链表每个结点后插入值相同的新结点 
    pCur = pHead;
    pNext = pHead->next;    
    while(pNext)
    {
        pCur->next = AddNode(pCur->data);   //在当前结点后插入值相同的新结点
        pCur->next->next = pNext;           //修改新结点的next指针,使其指向原链表当前结点的下一个结点
        pCur = pNext;                       //移动pCur指针
        pNext = pNext->next;                //移动pNext指针
    }
    pCur->next = AddNode(pCur->data);       //对于最后一个结点,其next为NULL。需单独处理
    pCur->next->next = pNext;

//给新插入结点的随机指针域赋值
    pCur = pHead;
    pNext = pHead->next;
    while(pNext->next)  //复制原链表中前n-1个结点的random指针指向
    {
        if (pCur->random == NULL)
        {
            pNext->random = NULL;
        }
        else
        {
            pNext->random = pCur->random->next;
            pCur = pNext->next;
            pNext = pCur->next;
        }    
    }
    if (pCur->random == NULL)   //对最后一个结点,特殊处理
        pNext->random = NULL;
    else
        pNext->random = pCur->random->next;

//将新结点从原来表上重新拆下来
    pCur = pHead;
    pNext = pHead->next;
    pHead2 = pHead->next;
    while(pNext->next)  //将原链表中的前n-1个结点拆下来
    {
        pCur->next = pNext->next;
        pNext->next = pCur->next->next;
        pCur = pCur->next;
        pNext = pNext->next;
    }
     pCur->next = pNext->next;  //最后一个结点特殊处理

     return pHead2;
}

猜你喜欢

转载自blog.csdn.net/neverwa/article/details/80015200
今日推荐