Sword finger offer(C++)-JZ35: copy of complex linked list (data structure linked list)

Posted by sgarcia on Wed, 15 Dec 2021 06:12:30 +0100

Author: Zhai Tianbao Steven
Copyright notice: the copyright belongs to the author. For commercial reprint, please contact the author for authorization. For non-commercial reprint, please indicate the source

Title Description:

Enter a complex linked list (each node has a node value and two pointers, one pointing to the next node and the other special pointer random pointing to a random node). Please make a deep copy of this linked list and return the copied head node. (Note: please do not return the node reference in the parameter in the output result, otherwise the problem determination program will directly return null). The following figure is a complex linked list with 5 nodes. The solid arrow in the figure represents the next pointer and the dotted arrow represents the random pointer. For simplicity, the pointer pointing to null is not drawn.

Example:

Input: {1,2,3,4,5,3,5, #, 2, #}

Output: {1,2,3,4,5,3,5, #, 2, #}

Analysis: we divide the linked list into two segments. The first half {1,2,3,4,5} is a ListNode, and the second half {3,5, #, 2, #} is a random pointer field representation.

The first half of the above example can represent LISTNODES with a linked list: 1 - > 2 - > 3 - > 4 - > 5

The second half, 3, 5, #, 2, # are represented as

The position of 1 points to 3, the position of 2 points to 5, the position of 3 points to null, the position of 4 points to 2, and the position of 5 points to null

As shown below:

Example:

Input:

{1,2,3,4,5,3,5,#,2,#}

Return value:

{1,2,3,4,5,3,5,#,2,#}

Problem solving ideas:

This topic examines the use of linked lists of data structures. There are two common solutions to this problem.

  1. Hash table. Create a mapping table with hash map, establish sentry to prevent the front pointer from being empty, pre is used to build a new linked list, and cur is used to traverse the original linked list; Traverse the storage mapping relationship, just as the second node of the original linked list corresponds to the second node of the new linked list, one-to-one correspondence, which is a bit like "shadow imitation"; After the mapping is completed, the hash table is traversed. Value corresponds to the new linked list, key corresponds to the original linked list, and the random of value equals m [key - > Random], which is equivalent to connecting the random of the new linked list according to the random of the original linked list (note that the key - > Random here points to the node of the original linked list, and m [key - > Random] is the node pointing to the new linked list); delete the sentry, and the new linked list is copied.
  2. Linked list splitting method. Traverse the linked list for the first time, and create a node behind each node to form a combined linked list; Traverse the combined linked list for the second time, and connect the random of the new linked list node to the next of the original linked list node random to realize synchronous connection; Traverse the combined linked list for the third time and split it. Connecting the pointer next to the next of next is equivalent to splitting the combined linked list into the original linked list and the new linked list. At this time, the new linked list has been completed.

Test code:

Solution 1: hash table

/*
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 it is blank, return
        if(!pHead)
            return pHead;
        // Create hash map
        unordered_map<RandomListNode*, RandomListNode*> m;
        // Set up a sentry to prevent the front pointer from being empty
        RandomListNode* sentry=new RandomListNode(0);
        // Establish pointers to sentinels and headers
        RandomListNode* pre=sentry,*cur=pHead;
        // Traversal storage mapping
        while(cur)
        {
            RandomListNode* temp = new RandomListNode(cur->label);
            pre->next = temp;
            m[cur] = temp;
            pre = pre->next;
            cur = cur->next;
        }
        // Traverse the hash table and connect the random of the new table with the random relationship of the original table
        for(auto&[key,value]:m)
        {
            value->random=key->random==NULL?NULL:m[key->random];
        }
        // Delete Sentinel
        delete sentry;
        return m[pHead];
    }
};

Solution 2: linked list splitting

class Solution {
public:
    RandomListNode* Clone(RandomListNode* pHead) {
        // If it is blank, return
        if(!pHead) return pHead;
        // Traversal linked list
        RandomListNode* cur = pHead;
        // A copy node is created after each node
        while(cur){
            RandomListNode* tmp = new RandomListNode(cur->label);
            tmp->next = cur->next;
            cur->next = tmp;
            cur = tmp->next;
        }
        // Traverse the combined linked list and connect the next of the random of the original linked list with the random of the new linked list node
        RandomListNode *old = pHead, *clone = pHead->next, *ret = pHead->next;
        while(old){
            clone->random = old->random == NULL ? NULL : old->random->next;    // Handle random pointers to copy nodes
            if(old->next) old = old->next->next;    // Note the special null pointer
            if(clone->next) clone = clone->next->next;
        }
        // Traverse again, split, interval split, and tear down the original linked list and the new linked list
        old = pHead, clone = pHead->next;
        while(old){    // Split linked list
            if(old->next) old->next = old->next->next;
            if(clone->next) clone->next = clone->next->next;
            old = old->next;
            clone = clone->next;
        }

        return ret;
    }
};

Topics: C++ data structure linked list