Clone a linked list with next and random pointer | Set 1

You are given a Double Link List with one pointer of each node pointing to the next node just like in a single link list. The second pointer however CAN point to any node in the list and not just the previous node. Now write a program in O(n) time to duplicate this list. That is, write a program which will create a copy of this list.

Let us call the second pointer as arbit pointer as it can point to any arbitrary node in the linked list.

Arbitrary pointers are shown in red and next pointers in black

Figure 1

Method 1 (Uses O(n) extra space)
This method stores the next and arbitrary mappings (of original list) in an array first, then modifies the original Linked List (to create copy), creates a copy. And finally restores the original list.

1) Create all nodes in copy linked list using next pointers.
3) Store the node and its next pointer mappings of original linked list.
3) Change next pointer of all nodes in original linked list to point to the corresponding node in copy linked list.
Following diagram shows status of both Linked Lists after above 3 steps. The red arrow shows arbit pointers and black arrow shows next pointers.

Figure 2

4) Change the arbit pointer of all nodes in copy linked list to point to corresponding node in original linked list.
5) Now construct the arbit pointer in copy linked list as below and restore the next pointer of nodes in the original linked list.

6) Restore the next pointers in original linked list from the stored mappings(in step 2).

Time Complexity: O(n)
Auxiliary Space: O(n)

Method 2 (Uses Constant Extra Space)
Thanks to Saravanan Mani for providing this solution. This solution works using constant space.
1) Create the copy of node 1 and insert it between node 1 & node 2 in original Linked List, create the copy of 2 and insert it between 2 & 3.. Continue in this fashion, add the copy of N afte the Nth node
2) Now copy the arbitrary link in this fashion

This works because original->next is nothing but copy of original and Original->arbitrary->next is nothing but copy of arbitrary.
3) Now restore the original and copy linked lists in this fashion in a single loop.

4 Start from head of copy list, corresponding to this copy list node we have the original list node in map. We can access it using an iterator.
map::iterator i
i = map_hash.begin()
copy_node->arbit = map_hash.at((*i).first->arbit)

What we are doing is for each copy_List node we take its corresponding original_List node then find its arbit node, next we use our map to find the node in our copy_List corresponding to this arbit node and assign it to the arbit pointer of the copy_List node

Hope this will help!!!

darkpassenger

if we don’t want to modify the original list the with the help of 2 hash maps u can clone it……….

neelabhsingh

This problem can be done in two scan Linked List

1st Scan: In first scan change change next pointer of original LL to the corresponding same node in the new LL. and change random pointer of new LL to the corresponding same node of the original linked list.

current1 is pointing to the start node of the originalLL.

current2 is pointing to the start node of the newLL

current1=root1;// root node of the original node

current2=roott2// root node of the original node

while(current1!=NULL)

{

temp=current1->next;

current1->next=current2;

current2->random=current1;

current2=current2->next;

current1=temp;

}

// Scan2

current1=root1;// root node of the original node
current2=roott2// root node of the original node

@d4868dd64c637016efc578852ad7cd68:disqus where do you need to insert copy element in original list ??
we can do it just first copy the whole list using next pointers … then copy the arbitrary pointers of original list in copyid list using using a loop till end and picking one element of each LL ??
this will help in reduing two step first insert in between and second to separate them
correct me if i m wrong…..

Neha Garg

@3544658edbd8b32cd82d8c035a2ba74f:disqus @d4868dd64c637016efc578852ad7cd68:disqus where do you need to insert copy element in original list ??
we can do it just first copy the whole list using next pointers … then copy the arbitrary pointers of original list in copyid list using using a loop till end and picking one element of each LL ??
this will help in reduing two step first insert in between and second to separate them
correct me if i m wrong…..

Note: initially new list arbitrary links points to the original list’s corresponding nodes.

Please correct if I’m wrong..

anshul.chauhan

yes you are wrong…try it with an example…you can’t point any node to anywhere until whole list traversal is done because node can point to previous nodes as well and u’ve already lost the pointer to that

@WgpShashank:1. if wen can’t modify the original linked list e.g. its read only
If we can’t modify the list then we can create a copy in more than O(n) time complexity by storing everything and creating copy from the stored data.2. if elements are duplicate or all the elements are same.
There should not be any problem when there are duplicates as both of the approaches given above do not compare data.

@Ruonan Zhao, @Ishan and @Elijah:
Thanks for pointing this out. We have renmoved method 1 from the original post.

This doesnt work …In the last step of recursion you are trying to point to the old list arbitrary pointer !!!but it should to point to the new list …

Ruonan Zhao

Hi, I think the restriction assumption is wrong for the first solution. The restriction here is that a node will be pointed by only one arbit pointer in a linked list. Even if we obey this restriction, there still have some cause we can not restore the original list.

For example?
In this case
original_Node1->arbit=original_Node3
original_Node2->arbit=original_Node1
original_Node3->arbit=original_Node2

the original_node2-next cannot be restore by original_node2->next = original_node2->next->next->arbit, because original_node2->next->next is copy_node1 and it’s arbit has being change to copy_node3 already in the first loop.

So the restriction assumption should be:
The node’s arbit will point to the node which is after that node.

Ishan

Yes, I also came across the same thing, the 1st approach only works if the arbit pointer points to a node which is after the current node in the list.

If the node is before the current node , the next pointer of that pointer has already been modified and no longer points to its corresponding node in the duplicated list, thereby producing a wrong result.

How can you write a function, deep_equal, that:
1) Traverse all the nodes at least once and check that the corresponding node in another given list has the same value
2) Terminates?

My approach has been the following:
Given n1, n2:
1) Call on n1.next and n2.next (not n1 and n2) recursively
2) if you are at n1 and n2, return True

This does NOT guarantee to stop because you can simply construct a list where 1=>2=>3 and then 2 and 3’s arbit pointer points at 2 and 3 respectively and then this recursion will never stop.

How do I go about it?

disappearedng

Note the method of doing the following:

I came up with a two pass algorithm which involves:
1st pass: check both l1 and l2 by traversing next
2nd pass: check both l1 and l2’s arbit pointers pointing to nodes with the same value and continue traversing the list via next (NOT via the arbit pointers to avoid cycles).

This does **not** work.

Look at the scenario below:

l1: 1->2->3->2
there is only 1 arbit pointer and it’s from 3 to the first 2

l2: 1->2->3->2
there is only 1 arbit pointer and it’s from 3 to the SECOND 2.

The first algo does not make sense. If you change all arbit pointers first and then try to change the next pointers you cannot.. as the arbit have been modified and vice versa.

Even if you modify arbit pointer of a node and then restore the next pointer of corresponding node in orig list.. then also the last node’s back pointer shows problem. The next has been modified to point to 3.

Pls explain if i am missing something!!

guest

i don’ tthink u read the algo carefully… it first modifies the arbit pointer of copy list and then modifies the next pointer of corresponding node in orig list.
and for the last node how can the next point to 3??
for last node :
orig->next=orig->next->next->arbit;
but for last node : orig->next->next==NULL so we can set the next of last node in orig to NULL by checking this condition….

kevalvora

About the 1st algorithm, either I have not understood it or it is incomplete and does not work properly.

In the example given, after 1st iteration, arbit of 1 in copy-list will point to 3 in copy-list. Also, 1 in original-list will point to 2 in original-list. In 2nd iteration, arbit of 2 in original-list is pointing to 1 in original-list but next of 1 in original-list is pointing back to 2 in original-list (due to the change in 1st iteration). So following statement will fail:

copy_list_node->arbit = copy_list_node->arbit->arbit->next

I might not have understood the algorithm, in that case, please explain where I am going wrong.

kevalvora

Now I have understood the algorithm and yes, it works properly.

In 1st loop we change the arbit nodes of copy-list and in a separate loop we change the next of nodes in original-list.

A wonderful algorithm

Stiju

1st method doubt :
1st loop we change the arbit nodes of copy-list
————————————-
it will work fine

separate loop we change the next of nodes in original-list.
—————————————–
“orig_list_node->next =
orig_list_node->next->next->arbit”

since orig_list_node->next links to sibling node in copy list, now arent we dependent on copy_list_node->arbit which we changed in 1st loop.
wouldn’t orig_list_node->next be replaced with arbit’s of corresponding copy_list_node , which now points to its actual arbit than its sibling on orig_list

Parthsarthi

the first method is incorrect.I think we will have to store the next pointers in first case too.

http://processmanagerforwindows.blogspot.com/ Arif Ali Saiyed

After reading the question i tried solving it myself…
and came up with the method list below, then i looked into the three solution mentioned here, I liked the solution 3 most.
it’s really beautiful.

My solution is worst considering the space complexity,
but does not modifies the original list while on other hand all three solutions listed above does that…

2) Now traverse the second list ( copied one) , and store the prevPtr link using 3 hash tables that we created in pass 1.

list2Ptr1->prePtr = a) Refer the hash table 2 and get the counter part pointer in list 1.
say list1ptr1
b) find the prevPtr of list1ptr1 in list 1 itself
c) use the hash table 2, to find the counter part node in list 2

Time Complexity : O(2n)
Space Complexity : O(2n)

Raja

do u have code for this?

Sri1

Algo:
This solution can be made much simpler with just one Hash Table. (Key, value) = (pointer, pointer) or (node_list1, node_list2). The hash table takes a list1 node as key and returns the corresponding list2 node.

First iteration through original list1:
// Create new link list node
// After creating each node, add old and new nodes to HashMap
// If previous node is present, assign the next node for new list.

Second iteration through both list1 and list 2:
node_list2->arbit = HashMap(node->arbit);
//Move current nodes to node_list2->next; node_list1->next

Done! No need for array, index adjustment etc.

Sri1

Complexity = O(n)
Storage is 2n storage of memory pointers, so still O(n)

Of course, if this is a very large data structure and it is a memory constrained device, then the Hashmap implementation, collisions, chaining etc. [if retrieval is actually in O(1) time] will come into play.

@sambasiva …hi can you explain your code..particularly second for loop inside the copyist Function is not giving clear understanding

..Please Try to Reply ASAP.

Thanks
Shashank

http://ashutosh7s.blogspot.com/ wgpshashank

@sambasiva..hi ur program is correct but you forget to initialize the arbitrary pointer of duplicate node inside your dup method…to avoid null pointer /memory error ..we have to take care of such situation

@Saravanan Mani: Good work, we have included your algorithm to the original post. Keep it up!!

@GT & Goli: We still believe that we cannot set the next of original list and arbit of copy list with auxiliary space O(1) using first two approaches. Please try your algorithm step by step for figure 3 and check if you can set the next of 4 in original list and arbit of 4 in copy list. If you still believe that it can be done with auxiliary space O(1) with a variation of solution 1 and 2, please do write complete algorithm. We will modify the post.

Saravanan Mani

create the copy of 1 and insert between 1 & 2, create the copy of 2 and insert between 2 & 3.. continue in this fashion add the copy of N to Nth node

Now copy the arbitrary link in this fashion Original->next->arbitrary = Original->arbitrary->next; TRAVERSE TWO NODES;

This works because original->next is nothing but copy of original and Original->arbitrary->next is nothing but copy of arbitrary.

now restore the Original and copy linked lists in this fashion in a single loop.
Original->next = Original->next->next;
copy->next = copy->next->next;

Make sure that last element of original->next is NULL.

Arun

@Saravanan Mani : Good creative solution. But I am not sure how the Time Complexity is O(n). It looks like it is O(n^3) : First pass to create the copy, second pass to set the arbitrary pointers and 3rd pass to restore the original next pointers. Am I missing something here ?