剑指offer系列19:复杂链表的复制

这道题是典型的分治法,将一个大问题分解成几小步解决。一定要注意在使用指针的时候指针指向是否为空的问题。在指针指向时,可以将一个指向为空的指针作为赋值来写,但是空指针不能指向任何地方(指向空也不行),这点一定要记住。

#include<iostream>
#include<vector>
using namespace std;
struct RandomListNode {
int label;
struct RandomListNode *next, *random;
/*
RandomListNode(int x) :
label(x), next(NULL), random(NULL) {
}
*/
};

class Solution {
public:
    RandomListNode* Clone(RandomListNode* pHead)
    {
        if (pHead == NULL)
            return NULL;
        //3步
        //第一步,将复杂链表复制成double
        nodeclone(pHead);
        connect(pHead);
        return reconnect(pHead);
    }
    void nodeclone(RandomListNode* Head)
    {
        RandomListNode*p = Head;
        while (p != NULL)
        {
            //插入节点
            //cur = p->next;
            RandomListNode *curnode = new RandomListNode();
            curnode->label = p->label;
            curnode->next = p->next;
            curnode->random = NULL;//这一句必须要写?
            p->next = curnode;
            p = curnode->next;//悬浮指针?
        }
    }
    void connect(RandomListNode* Head)
    {
        //第二步:将复制出的结点的随机指针指向该有的位置
        RandomListNode*p = Head;
        while (p != NULL)//在指针访问的时候,时刻注意是否为空
        {
            RandomListNode *curnode = p->next;

            if (p->random != NULL)
            {
                curnode->random = p->random->next;
            }

            p = curnode->next;

        }
    }
    RandomListNode *reconnect(RandomListNode* Head)
    {
        //第三步:将链表拆为两部分
        RandomListNode*p = Head;
        RandomListNode *copy = p->next;
        while (p!= NULL)
        {
            RandomListNode *curnode = p->next;
            if (curnode != NULL)
            {
                p->next = curnode->next;
            }

            p = curnode;
        }
        return copy;
    }
};
int main()
{
    RandomListNode list[5];
    list[0].label = 1;
    list[0].next = &list[1];
    list[0].random = &list[2];

    list[1].label = 2;
    list[1].next = &list[2];
    list[1].random = &list[4];

    list[2].label = 3;
    list[2].next = &list[3];
    list[2].random = NULL;

    list[3].label = 4;
    list[3].next = &list[4];
    list[3].random = &list[1];

    list[4].label = 5;
    list[4].next =NULL;
    list[4].random = NULL;

    Solution solu;
    RandomListNode *re = solu.Clone(list);
    int count=0;
    while (re != NULL)
    {
        //cout << re->label << " "<<re->random->label<<",";
        cout << re->label<<" ";
        if (re->random != NULL)
            cout << re->random->label;
        cout << endl;
        count++;
        re = re->next;
    }
    //cout << endl;
    cout << "number of array:"<<count << endl;
    return 0;
}

 解法2:

如果是一个普通链表,直接可以循环去复制链表。但是复杂链表的问题在于有一个random结点,如果循环的时候给random赋值,random的指向不明确,有可能这个结点还没出现,因为链表不能随机访问。所以难点在于如何去赋值这个随机的random结点。

想到这里,可以利用hash表来解答此题,将原来的节点和拷贝后的节点作为(key,value)存在dict里,第一遍先复制链表中的值和关系,然后再遍历一次去赋值random结点。代码如下:

 1 def Clone(self, head):
 2     if head is None:
 3         return head
 4     # 复制后的链表的头结点
 5     res = RandomListNode(0)
 6     # 建立一个字典,(key,value)是复制前和复制后的节点
 7     mp = dict()
 8     cur = head
 9     pre = res
10     # 复制链表中的lable和next
11     while cur:
12         # 复制lable
13         clone = RandomListNode(cur.label)
14         # 放入hash表中
15         mp[cur] = clone
16         # 复制连接关系
17         pre.next = clone
18         # 循环条件
19         pre = pre.next
20         cur = cur.next
21     # 复制链表中的random
22     for (key, value) in mp.items():
23         if key.random is None:
24             value.random = None
25         else:
26             value.random = mp[key.random]
27     return res.next

 

posted @ 2022-04-30 15:16  妮妮熊  阅读(24)  评论(0)    收藏  举报