I was supposed to make a Double Linked List in Java in a given exercise. Is it a good practice to use temporary variables to store values in order to sort the list ascending/descending? Is it possible to sort it ascending/descending without using these temporary/auxiliary variables? I've been trying to do it for the last couple hours but haven't succeeded.
This is how I declared my list:
private static class List {
public int num;
public List next;
public List previous;
}
In my main method, I declared the starting and ending points:
List start = null;
List end = null;
List current;
Then, the exercise demanded that it was allowed to add numbers both at the beginning and at the end of the list. This is how I add it at the beginning of the list:
List newElement = new List();
newElement.num = input.nextInt();
if (start == null) {
start = newElement;
end = newElement;
newElement.next = null;
newElement.previous = null;
} else {
newElement.next = start;
start = newElement;
start.next.previous = start;
}
And at the end of the list:
newElement.num = input.nextInt();
if (start == null) {
start = newElement;
end = newElement;
newElement.next = null;
newElement.previous = null;
} else {
end.next = newElement;
end.previous = end;
end = newElement;
newElement.next = null;
}
Finally, how I sort it ascending:
current = start;
int tmp = 0; //temporary variable that I do not know wether I'm supposed to use or not
while (current.next != null) {
if (current.num > current.next.num) {
tmp = current.next.num;
current.next.num = current.num;
current.num = tmp;
}
current = current.next;
}
current = end;
tmp = 0;
while (current.previous != null) {
if (current.num < current.previous.num) {
tmp = current.previous.num;
current.previous.num = current.num;
current.num = tmp;
}
current = current.previous;
}
Sometimes it scrambles some numbers, depending on the other, so I suppose it's not correct. To fix that, I tried checking the list both forward and reverse, as you can see in the code above, but apparently that's not the problem.
Is there a way to sort it ascending without using a temporary variable? I've already tried at least 20 times but it always lost reference to either next or previous addresses. I'm a beginner.
Do you know there is a well known problem to swap two numbers without using temporary variable.Look for that and the temporary variable will be gone.
Related
Can anyone help on what's wrong with my code? Only the first input number shows up when I run it (it doesn't create a sorted list), the delete command isn't working, and the 'true' 'false' in exists command doesn't show up. My output should match the given sample I put at the end.
The areas I had to fill in to make the code work are the areas after the TODOTODOTODO symbols which would be 44-61, 75-83, 97-105. I'm not sure where I went wrong in those areas and why it is not working correctly to give the desired output?
import java.util.Scanner;
// Defines the a Sorted Set collection and implements a driver program in main
public class SortedSet {
// Define a basic element of a linked list
private class LinkedNode {
int x; // Value stored in the node
LinkedNode next; // Reference to the next node in the list
}
LinkedNode front = null; // Reference to the front of the singly linked list
// Adds the integer x to the collection.
// The resulting collection is sorted in increasing order and
// does not contain any duplicate values.
public void add(int x) {
// Initialize a new node to be added to the collection
LinkedNode newNode = new LinkedNode();
LinkedNode cur = front;
newNode.x = x;
// Check if list is empty
if (cur == null) {
front = newNode;
}
// If list is not empty, check if node should be placed in front
else if (front != null) {
if (newNode.x < front.x) {
newNode.next = front;
front = newNode;
}
// If not in front, check for the middle or the end, or duplicate.
else {
// <TODO><TODO><TODO>
LinkedNode temp = cur;
LinkedNode prev = cur;
int middle = x;
while (temp != null) {
if(temp.x > newNode.x) {
middle = 1;
newNode.next = temp;
prev.next = newNode;
}
prev = temp;
temp = temp.next;
}
if (middle == 0) {
prev = newNode;
}
}
}
}
// Deletes the integer x from the sorted set.
// The remaining collection remains sorted and without duplicates.
public void delete(int x){
// Declare a new reference and initialize it to the front of the list
LinkedNode cur = front;
// Check if list is empty
if (front == null) {
System.out.print("There is nothing to delete!");
} else { // Not empty
// Go through list, checking whether node is in the list, and delete if found
// <TODO><TODO><TODO>
LinkedNode prev = new LinkedNode();
while (cur.x != x && cur != null) {
prev = cur;
cur = cur.next;
}
if (cur != null)
prev.next = cur.next;
}
}
// Returns true if the integer x exists in the sorted set and false otherwise.
public void exists(int x) {
// Declare a new reference and initialize it to the front of the list
LinkedNode cur = front;
// Check if list is empty.
if (front == null) {
System.out.println("false");
}
// If not empty, check for the node.
// <TODO><TODO><TODO>
else {
while (cur != null) {
if (cur.x==x)
return;
cur=cur.next;
}
return;
}
}
// Returns a string representing the sorted set as a space separated list.
public String toString() {
String s = "";
LinkedNode cur = front;
while (cur!=null) {
s+= cur.x + " ";
cur = cur.next;
}
return s;
}
// Driver method
public static void main(String[] args) {
// Declare variables
SortedSet sortedSet = new SortedSet();
Scanner scan = new Scanner(System.in);
String[] tokens;
String command;
int num;
// Print header info
System.out.println("Programming Fundamentals\n"
+ "NAME: Andres Reyes\n"
+ "PROGRAMMING ASSIGNMENT 4\n");
// Enter command loop
while (true) {
// Prompt the user for a command
System.out.print("Enter command: ");
String input = scan.nextLine();
// Parse input
if (input.equals("q")) break; // user quits
tokens = input.split("\\s");
if (tokens.length < 2) continue; // invalid input
command = tokens[0];
num = Integer.parseInt(tokens[1]);
// Execute command
if (command.equals("add")){
sortedSet.add(num);
System.out.println(sortedSet);
} else if (command.equals("del")) {
sortedSet.delete(num);
System.out.println(sortedSet);
} else if (command.equals("exists")) {
sortedSet.exists(num);
} else {
System.out.print("Command does not exist");
}
}
System.out.println("\nGood bye!");
}
}
I made following changes in the add-function and they got it working for me:
// If not in front, check for the middle or the end, or duplicate.
else {
// <TODO><TODO><TODO>
LinkedNode temp = cur.next; // start at cur.next as your temp-variable
LinkedNode prev = cur;
int middle = 0; // set middle to 0
while (temp != null) {
if(temp.x > newNode.x) {
middle = 1;
newNode.next = temp;
prev.next = newNode;
}
prev = temp;
temp = temp.next;
}
if (middle == 0) {
// add node to the end
prev.next = newNode;
}
}
}
You have to start at cur.next as your temp-variable.
As far as I can see, you're not yet checking if there are any duplicate values in your list.
Edit: I didn't work on the exists-method, which is not giving you any output at the moment. The problem is simply that you're generating any output while you're checking if a value exists in your list. You could either write a System.out.print which prints "true" in case the value was found or "false" in case if wasn't. Or you change the return type of the exists-function to boolean, return a boolean according to the result and print the return value.
It might also help you to visualize a linked list to unterstand why you have to change the temp-variable to cur.next. I think https://www.tutorialspoint.com/data_structures_algorithms/linked_lists_algorithm.htm gives a good explaination of the insertion process.
I can give you some hints. The main problem I see with this code is that you really need a reference to the start of the LinkedList (the head) would be the only way to print the list and check for duplicates.
The following should be added to your class
LinkedList head = null; //start of the list
Then you have to update your toString() or you will never print the correct elements in your list no matter what you do. Try this:
public String toString(){
StringBuilder output = new StringBuilder();
LinkedNode current = head;
while(current != null){
output.append(current.x).append(" ");
current = current.next;
}
return output.toString();
}
You have to be really careful when you are appending to a String in a loop because Strings are immutable. Everytime you are appending to a list you are creating a new String. Instead, use StringBuilder.
//s+= cur.x + " ";
Your add method should handle the following cases:
Case 1: List is empty: ( don't forget to set ref to head)
Case 2: new element is great than front of list
Case 3: new element is less than current head
Case 4: new element is less than current and greater than head
Given, a linked-list, I'm trying to partition it into so that the even nodes come before the odd nodes. My approach is to create two different linked-list (even and odd) to store even numbers and odd numbers. However, I'm running into a problem when I want to add to the even or odd linked list (I commented the part that I think is giving me problem in my code below). Thanks!
public class SeperateOddEven {
static Node head;
static int count;
public static class Node {
int data;
Node next;
private Node(int data) {
this.data = data;
next = null;
count++;
}
}
public void seperate() {
Node even = null;
Node odd = null;
Node temp;
// go through each linked-list and place node in new list depending on whether they are even or odd
while(head != null) {
// if even, place in even linked-list
if(head.data % 2 == 0) {
temp = new Node(head.data);
even = temp; // Problem here
even = even.next; // and here
} else { // if head.data % 2 != 0
temp = new Node(head.data);
odd = temp;
odd = odd.next;
}
head = head.next;
}
toString(even);
//toString(odd);
}
public void toString(Node node) {
while (node != null) {
System.out.print(node.data + " ");
node = node.next;
}
}
public static void main(String[] args) {
SeperateOddEven s = new SeperateOddEven();
head = new Node(8);
head.next = new Node(12);
head.next.next = new Node(10);
head.next.next.next = new Node(5);
head.next.next.next.next = new Node(4);
head.next.next.next.next.next = new Node(1);
head.next.next.next.next.next.next = new Node(6);
System.out.println("original list: ");
s.toString(head);
s.seperate();
}
}
I believe you identified exactly where the problem is. Let's go line by line:
temp = new Node(head.data);
The extra temp variable is unnecessary but fine.
even = temp;
A problem arises on the next line however. You assign even to temp (making temp unnecessary). If something was previously stored in even, it is now lost to the garbage collector because you now have no reference to it. even and temp are now both references to the same Node object.
What I think you might have wanted to do was to say even.next = temp. This would start to create a list, but with only a single reference you would have to use that reference to point to the head of the list. Each time you wanted to append to the list, you would need to loop through it until you found the end. If you instead tried to make this single reference point to the tail of the list, you would no longer have any way to get back to the head because your Nodes only have next references, and not prev references (a list with bidirectional references is called a doubly linked list).
even = even.next;
Because even (and temp) both point to the newly created Node object, the even.next property is null. So when this line executes, even now points to null. The work inside the loop has accomplished nothing because you immediately lose references to every Node you create.
Try something like this:
// Must keep track of head reference, because your Nodes can only go forward
Node evenHead = null;
Node evenTail = null;
Node oddHead = null;
Node oddTail = null;
while (head != null) {
if(head.data % 2 == 0) {
if (evenHead == null) {
// The even list is empty, set the head and tail
evenHead = new Node(head.data);
evenTail = evenHead;
} else {
// Append to the end of the even list
evenTail.next = new Node(head.data);
evenTail = evenTail.next;
}
} else {
// similar code for odd, consider creating a method to avoid repetition
}
}
You can also try this :
while (head != null) {
// if even, place in even linked-list
temp = new Node(head.data);
if (head.data % 2 == 0) {
if(even == null) {
even = temp;
} else{
Node insertionNode = even;
while(insertionNode.next != null)
insertionNode = insertionNode.next;
insertionNode.next = temp;
}
} else { // if head.data % 2 != 0
if(odd == null) {
odd = temp;
} else{
Node insertionNode = odd;
while(insertionNode.next != null)
insertionNode = insertionNode.next;
insertionNode.next = temp;
}
}
head = head.next;
}
I am trying to convert a C# code to Java. I have almost converted every thing except the three lines within if condition.
the C# code
LinkedList<T> buk = new LinkedList();
LinkedListNode<T> current = buk.First;
LinkedListNode<T> previous = null;
if (fooCondition) {
previous = current.Previous;
} else {
previous = current;
current = current.Next;
}
The equivalent Java code
LinkedList<T> buk = new LinkedList<>();
T current = buckets.getFirst();
T previous = null;
if (fooCondition) {
? //previous = current.Previous;
} else {
? //previous = current;
? //current = current.Next;
}
As there is no LinkedListNode class in the Java, can any one suggest what would be the equivalent code in Java?
EDIT
It seems like the full code is important to get help. Here is the C# function from the link
protected void MergeBuckets()
{
LinkedListNode<Bucket> current = buckets.First;
LinkedListNode<Bucket> previous = null;
int k = (int)Math.Ceiling(1 / epsilon); // k=1/eps as integer
int kDiv2Add2 = (int)(Math.Ceiling(0.5 * k) + 2); // k/2 as integer
// at this point 1/k <= eps, k >= 2, hence requires eps >= 0.5
// number of concecutive buckets with same count causing a
// merge of the oldest two of those buckets
int numberOfSameCount = 0;
// traverse buckets from first to last, hence in order of
// descending timestamp and ascending count
while (current != null)
{
// previous and current bucket have same count, increment counter
if (previous != null && previous.Value.Count == current.Value.Count)
numberOfSameCount++;
// current is first with that count, reset counter to 1
else
numberOfSameCount = 1;
// detect need for a merge
if (numberOfSameCount == kDiv2Add2)
{
// merge buckets into current and remove previous
current.Value.Timestamp = previous.Value.Timestamp; // take most recent timestamp
current.Value.Count = previous.Value.Count + current.Value.Count; // sum the counts of the buckets,
// i.e. next power of two
buckets.Remove(previous);
// note that a merged bucket might cause a cascade of merges due to its new count,
// hence the new current node should point to the merged bucket otherwise the
// cascade might go unnoticed, temporarily violating the invariant!
previous = current.Previous; // merged bucket's previous, since old previous is removed
//current = current; // trivial, merged bucket is new current
// at this iteration, the traversal stays in place
}
// no merge required, continue normally
else
{
previous = current; // old current bucket or merged bucket
current = current.Next; // current's or merged's next
// at this iteration, the traversal moves to the next (older) bucket
}
}
}
can't you use the listIterator provided by the LinkedList and use its provided methods to browse the Linked list
ListIterator<T> listIterator = linkedListNode.listIterator(0);
if(yourCondition && listIterator.hasNext()){
T next = listIterator.next();
}
else if (listIterator.hasPrevious()){
T previous = listIterator.previous();
}
Hope it helps
The Java class java.util.LinkedList has an inner class LinkedList.Node which is private. The Nodes in a LinkedList cannot be acccessed directly. Instead, refer to methods like List.indexOf(E) and List.add(E, int) or a ListIterator in order to insert elements at specific positions.
final LinkedList<T> list = new LinkedList<>();
list.add(object1);
if (cond) {
list.add(object2, list.indexOf(object1));
} else {
list.addFirst(object2);
}
A frequently used idiom for dealing with LinkedList in Java is to create the LinkedList but primarily operate on it using a ListIterator.
final LinkedList<T> list = new LinkedList<>();
final ListIterator<T> iterator = list.listIterator();
if (!cond && list.hasNext()) {
list.next();
}
list.add(object2);
You can't make a LinkedList without nodes for it. Your code doesn't make sense, unfortunately.
A LinkedList node (in this case doubly linked) consists of the next node, the previous one, and the data in the node, as well as accessor methods. It's pretty simple to implement as it's simply a data storage structure.
class LinkedListNode<T> {
LinkedListNode prevNode, nextNode;
T data;
public LinkedListNode getNext() {
return nextNode;
}
public LinkedListNode getPrev() {
return prevNode;
}
public T getValue() {
return data;
}
public void setNext( LinkedListNode n ) {
nextNode = n;
}
public void setPrev( LinkedListNode n ) {
prevNode = n;
}
public void setValue( T data ) {
data = n;
}
}
You can write the own version of LinkedListNode class which contains the previous and next as it's property/field. For example -
class LinkedListNode{
LinkedListNode previous;
LinkedListNode next;
}
Then add some getter and setter method to access the property/field. You may add another property/field to store the value of the node. This is the basic structure.This might help you.You may have a look at this link also.
Thanks
LinkedList<T> buk=new LinkedList<T>();
//make list
T current=buk.getFirst();
T previous=null;
if (fooCondition) {
previous = current.previous;
} else {
previous = current;
current = current.next;
}
and the structure of T :
Class T{
public T previous;
public T next;
//rest
}
I have ran into some difficulties. I want to adapt this piece of code below to sort a singly linked list of type Person. for example, I have:
class Person{
private String fn = "NN";
private String ln = "NN";
private Date dob = new Date(1, 1, 1970);
}
I would like to sort the linked list of Persons by firstname, last name and date of birth. At the same time I have been given a piece of code to adapt it but, I can't seem to find a way around it. Any help will be highly appreciated. Here is the code to adapt below:
public void sort() {
TextIO.putln("sorting...");
if (head == null)
return;
Node max, t, out = null, h = new Node();
h.next = head;
while (h.next != null) {
// display();
TextIO.putln("max=" + (max = findmax(h)).next);
t = max.next;
max.next = t.next;
t.next = out;
out = t;
}
head = out;
}
private Node findmax(Node h) {
char max = '\0';
Node maxNode = h;
for (Node tmp = h; tmp.next != null; tmp = tmp.next) {
if (tmp.next.data.c >= max) {
max = tmp.next.data.c;
maxNode = tmp;
}
}
return maxNode;
}
If not, a detailed advice will be highly helpful thanks. Mind you, I cannot use collection.sort or any other ready function, it has to be implemented.
Thanks
First of all I would like you to look at this link. It will give you idea of how Node class is implemented and generally how to implement list.
Assuming you read content from the link here are some comments;
public void sort() {
//this method does ascending sort of the list
TextIO.putln("sorting...");
if (head == null)
return;
Node max, t, out = null, h = new Node();
h.next=head; //make new list node let him point to beginning of the list(head)
while (h.next != null) { //until we get to the end of the list
// display();
TextIO.putln("max="+(max = findmax(h)).next);
//after findmax is finished we know reference
//to the node that contains max value
//and we need to bring that node to the beginning of the list
//that requires some reference rewiring
//first set t to point to next node from max
t = max.next;
//than max node will point to the next node from t
//this way max node becomes detached from list
max.next = t.next;
// now max node will point to some node that will represent new list head
// not new list just new list head
t.next = out;
out = t;
}
//after we complete sorting just point list head to the sorted list
head = out;
}
//find node that contains max value starting from some node
private Node findmax(Node h) {
//declare that max is null char
char max = '\0';
// set maxNode to be current node
Node maxNode = h;
//go through all nodes starting from current which is h
for (Node tmp = h; tmp.next != null; tmp = tmp.next) {
//if the data of some node in the list is bigger then our max value
if (tmp.next.data.c >= max) {
//then we are going to set that new value to be max
max = tmp.next.data.c;
// and set maxNode to be the node that has max value
maxNode = tmp;
}
}
return maxNode;
}
My advice is to look at provided link and start using good old pen an paper. That is the best way to understand what is going on with list pointers and nodes.
But if you do not want pen and paper you could go to this link that will show you animation of basic list operations.
Q: Every node of the linked list has a random pointer (in addition to the next pointer) which could randomly point to another node or be null. How would you duplicate such a linkedlist?
A: Here's what I have, I just wanted to ratify if this was the optimal way of doing it.
Since there's no space constraints specified, I'm going to use a LinkedHashSet and a LinkedHashMap (I can imagine people nodding their head in disagreement already ;) )
First Iteration: Do the obvious - read each node from the list to be copied and create nodes on the new list. Then, read the random node like so: this.random.data and insert into the LinkedHashSet.
Second Iteration: Iterate through the new list and add each node's data as the first column and the node itself as the second column into the LinkedHashMap (doesn't have to be Linked, but I'm just going with the flow).
Third Iteration: Iterate over the LinkedHashSet (this is the reason why this needs to be Linked - predictable ordering) and the new list simultaneously. For the first node, read the first entry of the LinkedHashSet, look up the corresponding object in the LinkedHashMap and add as the random node to the current node in the new list.
3 iterations does seem a little crazy, but the attempt was to keep the complexity as O(N). Any solution that improves on the O(3N) space requirement and O(3N) runtime complexity would be great. Thanks!
Edit: The entry from the LinkedHashSet can be removed when making an entry into the LinkedHashMap, so this would only take O(2N) space.
As pointed out by MahlerFive, I think you can do this with O(2N) runtime complexity, and O(N) space complexity.
Let's assume you have
public class Node {
private Node next;
private Node random;
private String data;
// getters and setters omitted for the sake of brevity
}
I would do a deep copy of a linked list of Nodes as:
private Node deepCopy(Node original) {
// We use the following map to associate newly created instances
// of Node with the instances of Node in the original list
Map<Node, Node> map = new HashMap<Node, Node>();
// We scan the original list and for each Node x we create a new
// Node y whose data is a copy of x's data, then we store the
// couple (x,y) in map using x as a key. Note that during this
// scan we set y.next and y.random to null: we'll fix them in
// the next scan
Node x = original;
while (x != null) {
Node y = new Node();
y.setData(new String(x.getData()));
y.setNext(null);
y.setRandom(null);
map.put(x, y);
x = x.getNext();
}
// Now for each Node x in the original list we have a copy y
// stored in our map. We scan again the original list and
// we set the pointers buildings the new list
x = original;
while (x != null) {
// we get the node y corresponding to x from the map
Node y = map.get(x);
// let x' = x.next; y' = map.get(x') is the new node
// corresponding to x'; so we can set y.next = y'
y.setNext(map.get(x.getNext()));
// let x'' = x.random; y'' = map.get(x'') is the new
// node corresponding to x''; so we can set y.random = y''
y.setRandom(map.get(x.getRandom()));
x = x.getNext();
}
// finally we return the head of the new list, that is the Node y
// in the map corresponding to the Node original
return map.get(original);
}
Edit: I found that this question is a duplicate of the one asked here: there you find an answer that shows how to solve this problem in O(3N) runtime complexity with no extra space: very ingenious! But it uses a trick with C pointers, and I'm not sure how to do the same in java.
You can do this with 2N steps and a map with N elements.
Walk the old list following the 'next' pointers. For each node you visit, add a node to your new list, connect the previous node in your new list to the new node, store the old node random pointer in the new new node, then store a mapping of the old node pointer to the new node pointer in a map.
Walk the new list, and for each random pointer, look it up in the map to find the associated node in the new list to replace it with.
I too was asked this question in interview recently.
Here is what i proposed.
Create a map of original list nodes where addreess of each node will be key and the offset of random pointer will be the value.
Now create a new linked list with random pointer =null from the original map.
In the end, iterate through the original list , with the help of map get offset of original pointer and use that offset to link random pointer in newly created map.
Interviewer was not happy in the end.May be looking for some better approach or he had the set answer in his mind and unable to grasp new way of solving it.
in O(n) time and with constant space
public class CloneLinkedListWithRandomPointer {
public static void main(String[] args) throws Exception {
SpecialLink link = new SpecialLink(1);
SpecialLink two = new SpecialLink(2);
SpecialLink three = new SpecialLink(3);
SpecialLink four = new SpecialLink(4);
SpecialLink five = new SpecialLink(5);
link.next = two;
two.next = three;
three.next = four;
four.next = five;
link.random = four;
two.random = five;
three.random = null;
four.random = five;
five.random=link;
SpecialLink copy = cloneSpecialLinkedList(link);
System.out.println(link);
System.out.println(copy);
}
public static SpecialLink cloneSpecialLinkedList(SpecialLink link) throws Exception{
SpecialLink temp = link;
while(temp != null){
temp.next = (SpecialLink) temp.clone();
temp = temp.next==null?temp.next:temp.next.next;
}
temp = link;
while(temp != null){
temp.next.random = temp.random!=null?temp.random.next:null;
temp = temp.next==null?temp.next:temp.next.next;
}
SpecialLink copy = link.next;
temp = link;
SpecialLink copyTemp = copy;
while(temp.next!= null && copyTemp.next != null){
temp.next = temp.next.next;
copyTemp.next = copyTemp.next.next;
temp = temp.next;
copyTemp = copyTemp.next;
}
return copy;
}
}
class SpecialLink implements Cloneable{
enum Type{
ORIGINAL,COPY
}
int val;
SpecialLink next;
SpecialLink random;
Type type;
public void setValue(int value){
this.val = value;
}
public SpecialLink addNode(int value){
return next = new SpecialLink(value);
}
public SpecialLink(int value) {
super();
this.val = value;
this.type = Type.ORIGINAL;
}
#Override
public String toString() {
SpecialLink temp = this;
StringBuilder builder = new StringBuilder();
while(temp != null){
builder.append(temp.val).append("--").append(temp.type.toString()).append("->").append(temp.random == null? null:temp.random.val).append("--").append(temp.random == null? null:temp.random.type);
builder.append(", ");
temp = temp.next;
}
return builder.toString();
}
#Override
public Object clone() throws CloneNotSupportedException {
// TODO Auto-generated method stub
SpecialLink clone = (SpecialLink) super.clone();
clone.type = Type.COPY;
return clone;
}
}
Walk the list and use clone()?
I wrote code for #MahlerFive 's solution, which works without mapping.
Here's the code:
private static class Node {
private String item;
private Node next;
private Node random;
}
public static Node cloneLinkedStructure(Node head) {
// make holes after each original node
for (Node p = head; p != null;) {
Node pnext = p.next;
Node hole = new Node();
hole.item = ".";
p.next = hole;
hole.next = pnext;
p = pnext;
}
Node fakeHead = new Node(); // fake new head
Node q = fakeHead;
Node p = head;
while (p != null) {
// build the new linked structure
Node oldq = q;
q = new Node();
q.item = p.item;
oldq.next = q;
q.random = p.random.next; // link to a hole
Node hole = p.next;
hole.random = q; // use link RANDOM as a backward link to new node
p = hole.next;
}
q.next = null;
Node newHead = fakeHead.next; // throw fake head
// build random links for the new linked structure
for (q = newHead; q != null; q = q.next)
q.random = q.random.random;
// delete holes to restore original linked structure
for (p = head; p != null; p = p.next)
p.next = p.next.next;
return newHead;
}
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
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.
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.
Time Complexity: O(n)
Auxiliary Space: O(1)
source
Here is the Java implementation:
public static <T> RandomLinearNode<T> clone(RandomLinearNode<T> head) {
if (head == null) {
return head;
}
RandomLinearNode<T> itr = head, temp;
// insert copy nodes after each original nodes
while (itr != null) {
temp = new RandomLinearNode<T>(itr.getElement());
temp.next(itr.next());
itr.next(temp);
itr = temp.next();
}
// copy the random pointer
itr = head;
while (itr != null && itr.next() != null) {
if (itr.random() != null) {
itr.next().random(itr.random().next());
}
itr = itr.next().next();
}
// break the list into two
RandomLinearNode<T> newHead = head.next();
itr = head;
while (itr != null && itr.next() != null) {
temp = itr.next();
itr.next(temp.next());
itr = temp.next();
}
return newHead;
}
Here is the unit tests
#Test
public void cloneLinkeListWithRandomPointerTest() {
RandomLinearNode<Integer> one = new RandomLinearNode<Integer>(1, null, null);
RandomLinearNode<Integer> two = new RandomLinearNode<Integer>(2, one, null);
RandomLinearNode<Integer> three = new RandomLinearNode<Integer>(3, two, null);
RandomLinearNode<Integer> four = new RandomLinearNode<Integer>(4, three, null);
RandomLinearNode<Integer> five = new RandomLinearNode<Integer>(5, four, four);
RandomLinearNode<Integer> six = new RandomLinearNode<Integer>(6, five, two);
RandomLinearNode<Integer> seven = new RandomLinearNode<Integer>(7, six, three);
RandomLinearNode<Integer> eight = new RandomLinearNode<Integer>(8, seven, one);
RandomLinearNode<Integer> newHead = LinkedListUtil.clone(eight);
assertThat(eight, not(sameInstance(newHead)));
assertThat(newHead.getElement(), equalTo(eight.getElement()));
assertThat(newHead.random().getElement(), equalTo(eight.random().getElement()));
assertThat(newHead.next().getElement(), equalTo(eight.next().getElement()));
assertThat(newHead.next().random().getElement(), equalTo(eight.next().random().getElement()));
assertThat(newHead.next().next().getElement(), equalTo(eight.next().next().getElement()));
assertThat(newHead.next().next().random().getElement(), equalTo(eight.next().next().random().getElement()));
assertThat(newHead.next().next().next().getElement(), equalTo(eight.next().next().next().getElement()));
assertThat(newHead.next().next().next().random().getElement(), equalTo(eight.next().next().next().random().getElement()));
}