Clone elements of linkedlist to a new list - java

I was asked this question in an interview to clone the elements of linked list A into a new list. This was my approach but I was rejected. I did get it right but I am not sure why the interviewer didn't like my approach. Any tips/advise to what I could have done better? List A has elements [10,12,11,4,5,6] let's assume.
public class CopyLinkedListElements {
public static void main(String[] args) {
LinkedList linkedList = new LinkedList();
linkedList.head = new Node(10);
linkedList.head.next = new Node(12);
linkedList.head.next.next = new Node(11);
linkedList.head.next.next.next = new Node(4);
linkedList.head.next.next.next.next = new Node(5);
linkedList.head.next.next.next.next.next = new Node(6);
cloneOrgList(linkedList.head);
}
public static void cloneOrgList(Node head) {
Node current = head;
Node newHead = new Node(current.data);
Node prev = newHead;
System.out.println(prev.data);
while(current != null && current.next != null) {
current = current.next;
Node newNode = new Node(current.data);
prev.next = newNode;
prev = newNode;
System.out.println(prev.data);
}
}
}

In addition to what was mentioned about return values, the loop is a bit messy. It can be improved like this:
public static Node cloneLinkedList(Node head) {
Node oldCurrent = head;
Node newHead = new Node(oldCurrent.data);
Node newCurrent = newHead;
while ((oldCurrent = oldCurrent.next) != null) {
newCurrent.next = new Node(oldCurrent.data);
newCurrent = newCurrent.next;
}
return newHead;
}

If the interviewer used the word "clone" and not "copy" he or she might have wanted to know if you know how to properly clone objects in Java. IF that was the case, you needed to create a cloneable class. The basic recipe for this is to implement the Cloneable marker interface and override Object's clone method.
public class MyClass implements Cloneable {
// Details of MyClass omitted
// Because Java supports covariant return types, the return type
// for the overridden clone method is the same as the class (i.e. MyClass)
// Also, the method needs to be made public instead of protected.
#Override
public MyClass clone() {
try {
return (MyClass) super.clone();
} catch (CloneNotSupportedException e) {
throw new AssertionError("Something went wrong. This isn't supposed to happen");
}
}
}
If he or she just wanted a copy, an approach like the one you showed should've been OK, except for what has been already mentioned: Your function failed to return the copy. So, in essence, the method is useless.
Lastly, since your original post stated "clone the elements of linked list", you could've done call Linked List clone method
LinkedList<SomeClass> original = new LinkedList<>();
...
LinkedList<SomeClass> clone = (LinkedList<SomeClass>) original.clone();
Again, if the interviewer wanted you to copy the contents, you could've done one of the following:
Collections.copy(dest, source)
dest.addAll(source)
List<String> dest = source.stream().collect(Collectors.toList());
Lastly, the third alternative was the interviewer wanted you to get into cloning vs copying objects in Java, in which case you would've demonstrated both. In the future, ask the interviewer to clarify and restate the question in your own words to get confirmation that you understood the question correctly BEFORE you jump into coding. From your code, it is clear you misunderstood the interviewer.

You need to clone the list such that new references and values are returned. This is not happening in the cloneOrgList method. It doesn't return anything and the scope of the node it operates on is limited to the method itself.
You need to do something like
public LinkedList cloneOrgList(LinkedList orig) {
Node origCurr = orig.head;
LinkedList copy = new LinkedList();
Node newCurr = new Node(origCurr.data);
copy.head = newCurr;
while (origCurr.next != null) {
origCurr = origCurr.next;
newCurr.next = new Node(origCurr.data);
newCurr = newCurr.next;
}
return copy;
}

I think He was expecting to use the clone() method.
Please have a look at the official doc.Javadoc
Sample Code:
package com.raushan.testmind;
import java.util.LinkedList;
public class TestMain {
public static void main(String args[]) {
// Creating an empty LinkedList
LinkedList<Integer> list = new LinkedList<Integer>();
// Use add() method to add elements in the list
list.add(10);
list.add(12);
list.add(11);
list.add(4);
list.add(5);
list.add(6);
// Displaying the list
System.out.println("First LinkedList:" + list);
// Creating another linked list and copying
LinkedList sec_list = new LinkedList();
sec_list = (LinkedList) list.clone();
// Displaying the other linked list
System.out.println("Second LinkedList is:" + sec_list);
}
}

Related

Why doesn't the built-in implementation of LinkedList.add() in Java add elements to ashallow copy of the LinkedList, but custom implementation adds?

In example below, in "main" when after cloning LinkedList l1 to l2, when I add element to l2, I do not get 300 in l1.
However, in the the method "addTwoLists" when I use custom implementation, adding any element to "rohit" adds it to "first" as well.
package hackerrank;
import java.util.LinkedList;
import java.util.concurrent.atomic.AtomicInteger;
class Node1 implements Cloneable{
int data;
Node1 next;
Node1(int x){
this.data=x;
this.next=null;
}
Node1 (){
}
protected Node1 clone() throws CloneNotSupportedException {
return (Node1) super.clone();
}
}
public class MS_linkedlist_copy {
public static void main(String[] args) {
// TODO Auto-generated method stub
LinkedList<AtomicInteger> l1 = new LinkedList<>();
l1.add(new AtomicInteger(100));
l1.add(new AtomicInteger(200));
LinkedList<AtomicInteger> l2 = (LinkedList) l1.clone();
l2.add(new AtomicInteger(300));
System.out.println(l1);
System.out.println(l2);
// change element on first list
l1.get(0).incrementAndGet();
System.out.println();
System.out.println("After change internal state of first element");
System.out.println(l1);
System.out.println(l2);
Node1 first = new Node1(1);
Node1 second = new Node1(2);
first.next= second;
Node1 third = new Node1(3);
Node1 fourth = new Node1(4);
third.next=fourth;
addTwoLists(first, third);
}
static Node1 reverse(Node1 head){
Node1 prev =null;
while(head!=null){
Node1 next_node = head.next;
head.next = prev;
prev=head;
head=next_node;
}
return prev;
}
//
static Node1 addTwoLists(Node1 first, Node1 second){
System.out.println(first.data);
Node1 rohit = null;
try {
rohit = (Node1)first.clone();
} catch (CloneNotSupportedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
rohit.data=1000;
rohit.next.data=1000;
System.out.println(first.data);
System.out.println(rohit.data);
Node1 rohit2= rohit;
while(rohit.next!=null) {
rohit= rohit.next;
}
Node1 rohit_add = new Node1(2000);
rohit.next = rohit_add;
System.out.println(first.data);
System.out.println(rohit2.data);
// rohit = first;
// rohit= reverse(rohit);
// reverse(second);
// System.out.println(first.data);
// System.out.println(rohit.data);
return null;
}
}
I tried to add elements to a shallow copy in custom, which got added to main list successfully. However, after trying to add elements to shallow copy of built-in LinkedList, the elements are not added to original list. I am trying to understand what is going on in the built-in LinkedList.
The difference is that LinkedList.clone also copies all the nodes in the entire linked list, whereas your Node1.clone only copies that one node, and not any of the nodes linked to it.
You can find an implementation of LinkedList.clone here,
public Object clone() {
LinkedList<E> clone = superClone();
// Put clone into "virgin" state
clone.first = clone.last = null;
clone.size = 0;
clone.modCount = 0;
// Initialize clone with our elements
for (Node<E> x = first; x != null; x = x.next)
clone.add(x.item);
return clone;
}
Notice that it calls add on the cloned list (called clone here) in the loop. Each call to add creates a new linked list node.
Note that this is still a shallow copy, in the sense that the data in the nodes are not cloned. For example, if the lists stores String objects, no new strings are created.
So after cloning, you actually get two "chains" with the builtin LinkedList:
O-O-O
O-O-O
whereas with your Node1, since only one node is cloned, you get something like this:
first -> O
\
-O-O
/
rohit2 -> O
The two "heads" of the lists share the same "end", so adding an element to the end of the list adds it to both lists.
You can rewrite your clone so that it copies all the nodes. One simple way is to do it recursively:
protected Node1 clone() throws CloneNotSupportedException {
Node1 newNode = new Node1(this.data);
if (next != null) {
newNode.next = next.clone();
}
return newNode;
}

LinkedList to Array

I implemented a linkedList in Java and now I am working on a new method toArray in order to sort the link list after. I am getting an error when I am trying to print each elements of the ArrayList Cannot resolve method 'toString(java.util.List)'
public class Node {
int value;
Node next;
}
public class LinkedList {
Node head;
public void toArray(LinkedList list){
List<Integer> temp = new ArrayList<>();
Node iterator = head;
while(iterator != null){
temp.add(iterator.value);
iterator = iterator.next;
}
temp.forEach(arr->System.out.println(Arrays.toString(temp)));
}
This expression is wrong:
System.out.println(Arrays.toString(temp))
Because temp is an ArrayList, not an Array. Try this:
System.out.println(temp)
By the way, you still have some errors in your code, this should fix them:
public void toArray() {
List<Integer> temp = new ArrayList<>();
Node iterator = head;
while (iterator != null) {
temp.add(iterator.value);
iterator = iterator.next;
}
temp.forEach(System.out::println);
}
The method Arrays.toString() needs an Array in argument.
You need transform you List an one Array calling the method: toArray().
Like this:
temp.forEach(arr->System.out.println(Arrays.toString(temp.toArray())));

Reverse LinkList whilst preserving original nodes

My teacher has assigned a program where I am to create a linked list of some random numbers. I am to create it from a list and then the second part of the assignment is to reverse it. The actual quote is
Write a Java method called reverseLinkedList() that will generate a
reversed linked-list from the linked-list that you create in problem
1. Your method should accept a linked-list as an input and return another linked list that has the node references in the reversed
order. Please do not print the original list in reverse. The idea is
to manipulate the node references so that the nodes are preserved in
same in order as they were originally created.
The code I have generated so far looks like
import java.util.*;
public class progassignment2
{
public static void main(String args[])
{
List<Integer> myList = new ArrayList<Integer>();
Random ran = new Random();
int ranNum;
for(int x = 0;x<5;x++)
{
ranNum = ran.nextInt(500);
myList.add(x,ranNum);
}
LinkedList<Integer> mylinklist = createLinkedList(myList);
System.out.println(mylinklist);
LinkedList<Integer> mylinklistrev = reverseLinkedList(mylinklist);
}
public static LinkedList createLinkedList(List<Integer> integerList)
{
LinkedList<Integer> linkedlist = new LinkedList<Integer>();
linkedlist.addAll(integerList);
return linkedlist;
}
public static LinkedList reverseLinkedList(LinkedList inputList)
{
for(int y = 0;y < inputList.size();y++)
{
inputList.addLast(inputList.pollFirst());
}
return inputList;
}
}
However I don't think I'm doing the assignment correctly, or that I understand what he is asking of me and unfortunately won't answer any questions and just cites "Read the assignment". Any help is greatly appreciated
What about:
public static LinkedList reverseLinkedList(List<Integer> inputList) {
LinkedList<Integer> reversedLinkedlist = new LinkedList<Integer>(inputList);
Collections.reverse(reversedLinkedlist);
return reversedLinkedlist;
}
Usually, exercises on linked lists do not make use of any built-in Java collection (like ArrayList, LinkedList, etc), but are instead meant to make you build your own collection type.
Your teacher probably wants you to build a very basic element, which would then become the building block of your own collection type: imagine an object where you can store a value and a reference to the following value in the list. In code:
class Node {
private int value;
private Node next;
public Node(int value){
this.value = value;
}
public int getValue(){
return value;
}
public Node getNext(){
return next;
}
public void setNext(Node next){
this.next = next;
}
}
Each element points to the next one, and the end of the list is marked by the last node's next element being null.
By using objects like this, you'll be able to define your own linked list, without using any pre-defined Collection offered by Java.
You've surely heard about the stack data structure: by reading all the elements in your linked list and putting them inside a stack, once the list will be over, you're going to fetch the elements inside the stack; creating a linked list in the order of the elements pulled from the stack will solve your problem of inverting the linked list.
The idea is to manipulate the node references so that the nodes are
preserved in same in order as they were originally created.
You should create your own LinkedList. You are not allowed to use common ways of reversing like using recursion, stack ,modifications or any collections interface methods.
here is the link includes LinkedList reversing ways and solution:
class LinkedList {
Node head; // head of list
/* Linked list Node */
class Node {
int data;
Node next;
Node(int d) {
data = d;
next = null;
}
}
/* Function to print reverse of linked list */
void printReverse(Node head) {
if (head == null)
return;
// print list of head node
printReverse(head.next);
// After everything else is printed
System.out.print(head.data + " ");
}
/* Inserts a new Node at front of the list. */
public void push(int new_data) {
Node new_node = new Node(new_data);
new_node.next = head;
head = new_node;
}
public static void main(String args[]) {
LinkedList llist = new LinkedList();
llist.push(4);
llist.push(3);
llist.push(2);
llist.push(1);
llist.printReverse(llist.head);
}
}

Non-destructive recursive intersect of two singly linked lists

I want to take two singly linked lists (this function is called from within one) and create a third singly linked list that contains all intersections between the two. So if p=[0,1,2,3] and q=[1,3,7,9] then out=[1,3], while leaving the old lists intact.
As you can see I need to declare "out" in two places. But if I hit the declaration by calling the function again, it naturally wipes what I previously wrote to it. I really can't figure out how to avoid it.
Singly linked lists can be generated with http://docs.oracle.com/javase/7/docs/api/java/util/LinkedList.html . first is my header.
public List intersection(List l) {
if(first.data == l.first.data) {
List lTail = new List(l.first.next);
List tail = new List(first.next);
List out = new List(new Node(first.data, null)); //Bad idea #1
// System.out.println(out);
return tail.intersection(lTail);
} else if (first.data > l.first.data && l.first.next != null) {
List lTail = new List(l.first.next);
return intersection(lTail);
} else if (first.data < l.first.data && first.next != null) {
List tail = new List(first.next);
return tail.intersection(l);
} else { //When both lists are at the end position
List out = new List(new Node(0, null)); // Bad idea #2
return out;
}
}
List<T> p = new LinkedList<T>();
p.add...
...
List<T> q = new LinkedList<T>();
q.add...
...
List<T> intersection = new LinkedList<T>(p);
intersection.retainAll(q);
Now intersection contains only elements, which are in both lists, while lists theirselves remain untouched.

Implementing my own HashSet class... my add() logic seems faulty

when scanning a file for words and using the built-in hashset class from the API, my word count returns 349 (which is what it's supposed to be)
Using my home-made hashset class, I get 235... so something in my add() method must be wrong, but I can't understand what it is.
thanks for any help!
public class HashWordSet implements WordSet {
private int size = 0;
private Node[] buckets = new Node[8];
public Iterator<Word> iterator() {
return new WordIterator();
}
//Add word if not already added
public void add(Word word) {
int key = getBucketNumber(word);
Node node = buckets[key];
while (node != null) {
if (node.value.equals(word))
return;
else
node = node.next;
}
node = new Node(word);
buckets[key] = node;
size++;
if (size == buckets.length) rehash();
}
private int getBucketNumber(Word word) {
int hc = word.hashCode();
if (hc < 0) hc = -hc;
return hc % buckets.length;
}
It seems like you override nodes[key] with the new word [only] instead of appending a new node to the list, so you lose all old data that was already in this node.
It should work fine if there are no elements in there before add() was invoked, but if there are - you will lose some data.
node = new Node(word);
buckets[key] = node;
Though it is hard to be 100% sure about it without the actual implementation of Node.
node = new Node(word);
buckets[key] = node;
If there are any nodes already in the bucket you have just thrown them away. Try something like:
node = new Node(word);
node.next = buckets[key];
buckets[key] = node;

Categories