views:

584

answers:

4
+11  Q: 

Copy a linked list

typedef struct Node
{
  int data;
  Node *next;
  Node *other;
};

Node *pHead;

pHead is a singly linked list. The next field points to the next element in the list. The other field may point to any other element (could be one of the previous nodes or one of the nodes ahead) in the list or NULL.

How does one write a copy function that duplicates the linked list and its connectivity? None of the elements (next and other) in the new list should point to any element in the old list.

+6  A: 

Create a new node for every node in the old list, copy the corresponding data and make the next pointer of the nodes in the new list point to their successor in the new list, forgetting the other pointer for time being. At the time of creating a new node remember the mapping of node address something like:

Old_list   New_list
------------------- 
0x123      0x345     [ addresses of the first node]
0xabc      0xdef     [ addresses of the second node]
...

In the second pass pass for every node in the new list consider its other pointer and find its corresponding node in the new list from the map and use it as the other pointer of this node (node in the new list).

codaddict
How do you find the corresponding node in hour second pass? What if the data isn't unique?
Sam Post
Provided the map is sorted, I *think* this algorithm would be O(n logn).
dreamlax
Just curious, how safe is it to use memory locations? might they change between iterations?
NomeN
+4  A: 

Came across this. Hope it helps!

Citing one solution from this link, below.

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

2) Now copy the arbitrary link in this fashion

 if original->arbitrary is not NULL
   original->next->arbitrary = original->arbitrary->next;  /*TRAVERSE TWO NODES*/
 else
   original->next->arbitrary=NULL;

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.

 original->next = original->next->next;
 copy->next = copy->next->next;

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

Sample code, Time Complexity O(N), Space Complexity O(1)

pNode copy_list(pNode head) {
  // pre-condition: node->other either points into the list or NULL
  if (!head) return NULL;

  pNode node = head, copied = NULL, cnode = NULL;
  for ( ; node; node = node->next->next) {
    // make copy
    cnode = newnode(node->next, node->data);
    cnode->other = node->other;
    if (node == head)
      copied = cnode;

    // insert the copy between originals    
    node->next = cnode;    
    // node -> cnode -> (orig)node->next
  }

  for (node = head; node && node->next; 
       node = node->next->next /* only original nodes */) 
    if (node->other)
      node->next->other = node->other->next;
    else
      node->next->other = NULL;    

  // restore lists
  node = head; cnode = copied;
  for ( ; cnode && cnode->next; node = node->next, cnode = cnode->next) { 
    node->next = node->next->next;
    cnode->next = cnode->next->next;
  }
  node->next = NULL;
  return copied;
}

Complete program is at http://gist.github.com/349630

Aviator
Doesn't step two fall down if `arbitrary` is null? The page you are quoting from assumes `arbitrary` always points at a node.
Dominic Cooney
What if other points to the head of another list? I know he didn't mention that, but it might be worth looking at
tzenes
@Dominic: Edited as per your comment@tzenes: In that case, i am going to delete my post :)
Aviator
@tzenes the question pretty clearly states that `arbitrary` points into the list, or is null. I don't think the answer has to handle `arbitrary` pointing into other lists.
Dominic Cooney
@Aviator thanks for the edit.
Dominic Cooney
@Dominic I understand it wasn't mentioned in the original post, I only thought that it made the problem more interesting. Aviator came up with a great solution and I was wondering if he had considered this possibility.
tzenes
@Aviator: I've added C implementation of the algorithm. It works for OP's case.
J.F. Sebastian
@Sebastian:Thanks a lot for the edit Sebastian!
Aviator
A: 

I like the solution of Codaddict, but this would be my answer:

  1. iterate over the linked list.
    a. store the data in an array (position i for the i'th node of course)
    b. replace data with i to create an id (this way you'll definitely know which node you are talking about)

  2. create the 2nd linked list the size of the first (ignore the other pointer for now) *. maybe use a temporary array to find each node quickly

  3. iterate over the first linked list. a. find out which id other points to (which is in that nodes data) b. recreate this link in the 2nd linked list (the temporary array could really help here)

  4. iterate over both linked list simultaneously and replace the ids in data with the stored data

Of course you could collapse some processing and iterating here. But this would roughly be what I would do/think of.

NomeN
A: 

What about something like

while(node != NULL)
{
    Node *duplicate = new Node();
    // copy data
    // add to the new list
    node = node->next;
}

Pretty much straight forward - just iterate them all and link appropriately.

Poni
The problem is to set the *next* and *other* pointers appropriately.
NomeN
It shouldn't be of an issue to create maybe some static function that will add/remove nodes to/from nodes - and set the pointers appropriately. Just try.
Poni
Figuring out which node each pointer is pointing at *is* the issue.
NomeN