I have these code:
Class File:
public class LinkedListCustom<T> implements AbstractList<E>
{
private int numElements; private Node head, tail;
...
...
public Node(T element)
{
T data;
Node next, prev;
}
...
...
private Node getNthElem(int index)
{
Node temp = head;
for(int i=0; i<index; i++)
{
temp = temp.next;
}
return temp;
}
public T getNthVal(int index)
{
Node n = getNthElem(index);
return n.data;
}
}
Test file:
public class Tester extends TestCase
{
public void testGetN()
{
MyCustomLinkedList<Integer> myList = new MyCustomLinkedList<Integer>();
myList.add(1);
myList.add(2);
assertEquals("index 0 is 1", new Integer(2), myList.getNthValue(1);
}
}
However, this does not run properly. May I know what I could have done wrongly? If there is anything unclear I'll clarify it immediately.
EDIT: It compiles but there is a NullPointerException.
EDIT 2: SOLVED Sorry about the vague question and unclear code, but I just wanted to find out what I might not have implemented, and it turns out that #JaviFernandez was correct by asking whether I have implemented the add() method, which I didn't. I was just looking for an answer like that... Sorry if I have troubled anyone...
When you say getNthValue(1), this returns you the value at index 1, which is the second element since indices are 0-based. So in your linked list, you have the value 1 at index 0, and the value 2 and index 1.
private Node getNth(int index)
is missing a return:
return temp;
Related
I'm trying to figure out how to create a sublist of a linked list without using the standard library for a practice exercise.
I have a solution coded but I'm not sure if this is working properly. I don't have any compile errors that are coming up but wanted a second opinion if there is a better way to do this or if corrections should be made.
LinkedList class basic instance variables
public class LinkedList<E> implements DynamicList<E> {
LLNode<E> head;
LLNode<E> tail;
int llSize;
LinkedList(){
this.head = null;
this.tail = null;
this.llSize =0;
}
get method addressing LinkedList index
#Override
public E get(int index) {
LLNode<E> current = this.head;
while(current.nextPointer != null){
if(index == current.getIndex()){
return current.getObj();
}else{
current = current.nextPointer;
}
}
return null;
}
Node class
public class LLNode<E>{
E obj;
LLNode<E> previousPointer;
LLNode<E> nextPointer;
int index;
public LLNode(E obj){
this.obj = obj;
this.index=0;
}
public E getObj() {
return obj;
}
public LLNode<E> getPreviousPointer() {
return previousPointer;
}
public LLNode<E> getNextPointer() {
return nextPointer;
}
public int getIndex() {
return index;
}
public void setIndex(int index) {
this.index = index;
}
}
Sublist method
#Override
public DynamicList<E> subList(int start, int stop) {
DynamicList<E> newDynamicList = new LinkedList<>();
for(int i = start; i<stop; i++){
newDynamicList.add(get(i));
}
return newDynamicList;
}
As I'm seeing, that is a double linked list. As is suggested in comments, avoid using an index as part of the node itself, the index is part of the List, because the list controls the way each node is traversed to perform any operation (add, remove, find, etc)
My suggestion (for sublist):
Check if the sublist is within the size of your list (you can throw some exception or return some default data, it depends on your design)
Move the index control to the list
For getting the sublist, you might have something like get the start node of the sublist, and then, use the nextPointer to traverse through the next nodes. You can calculate the size of the sublist and use that to control when you have to stop
public DynamicList<E> subList(int start, int stop) {
DynamicList<E> newDynamicList = new LinkedList<>();
//here, you can validate the subList conditions to work (size, boundaries, etc)
//an exception may be thrown if parameters do not meet some criteria
int subListSize = stop - start;
LLNode<E> current = get(start);
while(newDynamicList.size() < subListSize){
//Consider cloning the node and add it to the sublist
newDynamicList.add(current);
current = current.nextPointer;
}
return newDynamicList;
}
The main reason for not using the get method for retrieve each node is that get operation search for the node from the beginning each time you call it. It is better to get the start node and start traversing the nodes from there.
Don't forget that created Sublist will contain a reference to the original list nodes. I suggest to clone the elements for avoiding affect the original node
I am trying to remove the second appearance of specific object in singly linked list.
I have this code for my Node:
public class Node {
Node next;
Object data;
public Node(Object _data)
{
next = null;
data = _data;
}
public Node(Object _data, Node _next)
{
next = _next;
data = _data;
}
public Object getData()
{
return data;
}
public void setData(Object _data)
{
data = _data;
}
public Node getNext()
{
return next;
}
public void setNext(Node _next)
{
next = _next;
}
}
And this is my function to remove:
public void removeSecondAppear(Object data)
{
Node temp = new Node(data);
Node current = head;
boolean found = false;
for(int i = 1; i < size(); i++)
{
current = current.getNext();
if(current.getData().equals(temp.getData()))
{
if(found == true)
{
// remove element
current.setNext(current.getNext().getNext());
listCount--;
break;
}
else if(found == false)
{
found = true;
}
}
}
}
For some reason it won't remove the element. The method to find it works fine, but I don't know why it won't remove the element. I have a similar function to remove element of specific index which works fine:
public boolean remove(int index)
{
if(index < 1 || index > size())
{
return false;
}
Node current = head;
for(int i = 1; i < index; i++)
{
if(current.getNext() == null)
{
return false;
}
current = current.getNext();
}
current.setNext(current.getNext().getNext());
listCount--;
return true;
}
I'm using the same methood, but it won't work in my method to remove the second appearance. Any help what I'm doin wron??
public int indexOf(Object data)
{
Node temp = new Node(data);
Node current = head.getNext();
for(int i = 0; i < size(); i++)
{
if(current.getData().equals(temp.getData()))
{
return i;
}
current = current.getNext();
}
return -1;
}
My implementation:
LinkedList LL = new LinkedList();
LL.add(1);
LL.add(2);
LL.add(3);
LL.add(4);
LL.add(4);
LL.add(5);
LL.removeSecondAppear("4");
My add method:
public void add(Object data)
{
Node temp = new Node(data);
Node current = head;
while(current.getNext() != null)
{
current = current.getNext();
}
current.setNext(temp);
listCount++;
}
My constructor:
public LinkedList()
{
head = new Node(null);
listCount = 0;
}
Your issue is going to be found here (in a couple places):
As you loop through, you will keep advancing current until you find two instances where the data is equal and then remove it. Your remove won't work because you're not actually removing the node you want, it's the next node you're removing, which won't necessarily be equal because you've already iterated over the list and lost the previous equal node.
current = current.getNext();
if(current.getData().equals(temp.getData()))
{
if(found == true)
{
// remove element
current.setNext(current.getNext().getNext()); // this isn't actually removing 'current'...
listCount--;
break;
}
else if(found == false)
{
found = true;
}
}
First thing, you're not resetting found after not finding an equal node.
After the if (equals) block, add:
else {
found = false;
}
Assuming you fix that, here's where you'd end up.
Take the following example:
[3] -> [4] -> [4] -> [5] -> [6]
In your algorithm you will iterate over each element in this list like so:
Pass 1:
found = false
[3] -> [4] -> [4] -> [5] -> [6]
^
current
found = false
Pass 2:
found = false
[3] -> [4] -> [4] -> [5] -> [6]
^
current
found = true
Pass 3:
found = true
[3] -> [4] -> [4] -> [5] -> [6]
^
current
When you get here, you are setting current.next to current.next.next, which is effectively removing [5] from the list, not 4. (consequently, this is also causing your NPE... consider the effects when you get to the end of the list and there is no next.next)
What you want to do is either find the index of your duplicate node and call your existing method to remove an element by the index, or keep a previous node to hold the value of the node that comes before current and when you remove, set previous.setNext(current.getNext()) which will effectively delete current.
Second, you've made use of the equals method for Object, which uses the most discriminating method for determining equality, in that it will only return true for cases where the two compared objects refer to the same object. While this isn't necessarily a problem this can lead to issues depending on the type of data you store. Calling equals on any object will default to the closest implementation of equals for the actual type of data being represented by that object, so if it can't find one, it will default to Objects implementation, which will almost always give a false result if the objects are not the same.
The equals method for class Object implements the most discriminating
possible equivalence relation on objects; that is, for any non-null
reference values x and y, this method returns true if and only if x
and y refer to the same object (x == y has the value true).
Barring that, you might want to change how you compare object data, but I don't think that will really cause you too much of an issue.
Lastly, you will probably want to do some null checking and work your looping algorithm a bit, since this one will have problems if the duplicates are at the head of the list, but this should get you pointed in the right direction.
Here's a cut at a method that can help shed some light on what I've said:
public void removeSecondAppear(Object data)
{
Node temp = new Node(data);
Node current = head;
Node previous = null;
boolean found = false;
while(current != null)
{
// for the sake of argument, let's say this will return true if you find equal data
if( current.getData() != null && current.getData().equals(temp.getData()))
{
if(found)
{
// remove element
previous.setNext(current.getNext());
listCount--;
break;
}
else
{
found = true;
}
}
else {
found = false;
}
previous = current;
current = current.getNext();
}
}
Edit: I've written a small subset of a LinkedList implementation using the OP's Node class definition and used a small test to make sure my removeSecondAppear method works.
public class LinkedList {
private Node head;
public LinkedList() {
head = new Node(0);
}
public LinkedList(Node node) {
head = node;
}
public void add(Node node) {
Node ptr = head;
while ( ptr.getNext() != null ) {
ptr = ptr.getNext();
}
ptr.setNext(node);
}
... /// added removeSecondAppear here, but left out to keep it short(er)
// provided a print() method
}
Using this test:
public class Test {
public static void main(String[] args) {
LinkedList list = new LinkedList(new Node(1));
list.add(new Node(2));
list.add(new Node(4));
list.add(new Node(4));
list.add(new Node(5));
list.print();
list.removeSecondAppearance(4);
list.print();
}
}
My output is:
1 2 4 4 5
1 2 4 5
Adding to pmac89's answer, it would be better if you genericized your node class so that you can use the proper .equals() method for the type of your data:
public class Node<T> {
Node<T> next;
T data;
...
}
From that point essentially you can replace Object with T and Node with Node<T>. When you create a node, you specify its type. Then, say you make a Node<String>. When you call .equals() on the data, it will use String.equals() instead of Object.equals().
The reason you don't want to call Object.equals() is, as pmac89 said, because you are checking if they are the same object. What you really want to check is whether they have the same value.
Edit:
As Ryan J mentioned, if your data is a subclass of Object, it will default to the equals() implementation for that type, if there is one.
Here's the generics tutorial if you aren't familiar with them:
http://docs.oracle.com/javase/tutorial/java/generics/
So the problem is your Node class....
In
public class Node {
...
Object data;
....
}
So when you are calling
if(current.getData().equals(temp.getData()))
in your removeSecondAppear, they will not equal. Remember, Object.equal() on an object is comparing memory locations. None of the list items will equal each other, only the item itself.
EDIT: Also you would want
previous.setNext(current.getNext()) //Oops, fixed a mistake here too!!!
EDIT 2:
Also you are not excluding the thing you are looking for, so you are finding itself. To elaborate on this, think of it this way;
I have the list 1, 2, 3, 4, 4, 5. How many times does it find 4? I am guessing once. The reason being is that each of the list items has an address that does not match the other, as this is saying data is an Object which is assigned a place in memory. So when you call the Object.equals(someOtherObject) you are asking if they have the same location in memory. They do not have the same location in memory. The reason why you are only finding 1 second appearance in your check during the removeSecondAppear is because you are going through the whole list again and not excluding the node that you are looking for.
I have been implementing this interview question in Java . A fairly simple problem with an additional constraint of size :
Find the Nth Node from the end of a Linked List where the size of the Linked List is unknown?
I am not concerned with the solution to this problem,because I have already figured that out.
Instead, I want to know whether my implementation maintains the coding conventions which experienced coders maintain while coding a problem related to Linked Lists and it's implementation?.Here is my implementation of the above problem:
import java.io.*;
class NthNodeFromEnd<AnyType>
{
private Node<AnyType> head;
private Node<AnyType> pointer;
private class Node<AnyType>
{
protected AnyType item;
protected Node<AnyType> next;
}
void push(AnyType item)
{
if(isEmpty())
{
head = new Node<AnyType>();
head.item = item;
head.next = null;
pointer = head;
}
else
{
Node<AnyType> newNode = new Node<AnyType>();
newNode.item = item;
newNode.next = null;
pointer.next = newNode;
pointer = pointer.next;
}
}
boolean isEmpty()
{
return head == null;
}
AnyType printNthLastNode(int n)
{
Node<AnyType> ptr1 = head;
Node<AnyType> ptr2 = head;
for(int i =0;i<n;i++)
{
ptr1 = ptr1.next;
}
while(ptr1!=null)
{
ptr1 = ptr1.next;
ptr2 = ptr2.next;
}
return ptr2.item;
}
public static void main(String args[])
{
NthNodeFromEnd<Integer> obj = new NthNodeFromEnd<Integer>();
obj.push(1);
obj.push(2);
obj.push(3);
obj.push(4);
obj.push(5);
obj.push(6);
obj.push(7);
System.out.println("The nth item is = "+obj.printNthLastNode(5));
}
}
P.S. - I am aware of the fact that there is an inbuilt implementation of Linked List in Java, but I don't want to use that.I want to know whether this implementation of the problem is good enough or is there a better way to tackle Linked List related problems?
Regarding the code conventions:
generic types are typically defined as a single uppercase letter: E or T, but not AnyType, which looks like a concrete type.
operators should be surrounded by spaces, semi-colons followed by a space, etc. For example, for(int i =0;i<n;i++) should be for (int i = 0; i < n; i++)
A method printNthLastNode() should print the nth last node, not return it. A method returning it should be named getNthLastNode() or findNthLastNode(). BTW, this method doesn't return a node, but a value stored in the list.
methods should generally not be package-private. They should be public or private generally.
the usual convention in Java is to have opening curly braces at the end of the line, and not at the beginning of the next line.
your method printNthLastNode() will fail with a NPE if the list is empty or not large enough. A better exception type should be used to signal this problem.
the class should not import java.io.*, since it doesn't use any class from java.io. packages should generally not be imported. Classes should.
String[] args is more readable than String args[], and is more conventional.
the Node class should be static: it doesn't use any instance member of its enclosing type.
That said, the interviewer should see, with the code posted, that you understand how a linked list works and how pointers work, as well as generic types.
I am creating a chained hash table that uses my own LinkedListclass to handle collisons. Here is where my issue is occuring: I start with an array of LinkedLists, my "hash table", intially set to null. When i wish to add a word, if the desired location is null, I create a new LinkedList, place it in that array index. I then create a new LinkedListNode and set the head of the new LinkedList to the new node.
My issue is occuring here: Whenever I set the head of my new LinkedList to my new LinkedListNode all of my previously created linkedlists also have their head changed to the new node.
My debugger shows that I am truly creating new linkedlists every time. I was afraid each array index was just pointing to a single array, but that is evidently not the issue. Below is all the relevant code
public class SetOfStrings {
private int arraySize;
private LinkedList[] mainArray;
private int totalCount;
//other methods here
public boolean add(String toAdd)
{
int hashToAdd = hash(toAdd);
int wasFound = contains(toAdd);
if(wasFound> 0)
{
return false; // means its already in the table
}
if(mainArray[hashToAdd]== null)
{
mainArray[hashToAdd] = new LinkedList();
ListNode newHead = new ListNode(toAdd);
mainArray[hashToAdd].setHead(newHead);
totalCount++;
return true;
}
ListNode currentHead = mainArray[hashToAdd].getHead();
ListNode newNode = new ListNode(toAdd);
newNode.setNext(currentHead);
mainArray[hashToAdd].setHead(newNode);
totalCount++;
return true;
}
public class ListNode {
private String thisString;
private ListNode next;
public ListNode(String setString)
{
thisString = setString;
next = null;
}
public class LinkedList {
private static ListNode head;
private static int count;
private static ListNode currentPosition;
// other methods here
public void setHead(ListNode newNode)
{ head = newNode;}
SUMMARY: Whenever I set the head of a Linked List to a new node, it changes the head of all my linked lists to point to the same new node
You are declaring your head as static. This means that it is shared between all instances of the LinkedList class. Removing the static keyword should fix the issue you described.
I have a question regarding the output of the following program. The output is null. This is what I thought as well. Im thinking its because the methods called before display simply modify a copy of head and not head itself. Im assuming that I could get around this using a this.head= something right?
Heres the code:
public class List {
private Node head;
public List (){
int max=3;
int i;
head=null;
Node aNode=new Node(0);
for (i=0; i<max; i++) {
aNode.setNum(i);
add (aNode);
aNode.setNext(null);
}
}
public void add(Node aNode) {
Node temp;
if(head==null)
head=aNode;
else {
temp=head;
while(temp.getNext()!=null)
temp=temp.getNext();
temp.setNext(aNode);
}
}
public void display() {
Node temp=head;
while(temp!=null) {
System.out.println(temp.getNext());
temp=temp.getNext();
}
}
}
public class Node {
private int num;
private Node next;
public Node (int n) {num=n; next=null;}
public int getNum() {return num;}
public void setNum(int n) {num=n;}
public void setNext(Node n) {next=n;}
public Node getNext() {return next;}
}
public class Driver {
public static void main(String args[]) {
List aList=new List();
aList.display();
}
}
The add relies on receiving a new Node with next being null. So move Node aNode = new Node(); inside the for-loop.
Some sanitary remarks.
(Unimportant) Use current instead of temp, or anything else.
Fields in classes are by default null/0/0.0/false.
Before I answer your question, here is a side note...
Im thinking its because the methods called before display simply modify a copy of head and not head itself.
This is NOT correct.
Here is why...
public void display() {
// Basically, this says, make temp a REFERENCE of head...NOT A COPY!!!!
Node temp=head;
while(temp!=null) {
System.out.println(temp.getNext());
temp=temp.getNext();
}
}
Now, to answer your question, the reason temp is null is because head is null. And the reason head is null is because you never initialize it.
From you constructor...
public List (){
int max=3;
int i;
// Here you're saying "set head to null".
// So when you call display, head is NULL. You MUST initialize this.
head=null;
Node aNode=new Node(0);
for (i=0; i<max; i++) {
aNode.setNum(i);
add (aNode);
aNode.setNext(null);
}
}
Look at this code from the constructor:
Node aNode=new Node(0);
for (i=0; i<max; i++) {
aNode.setNum(i);
add (aNode);
aNode.setNext(null);
}
You create one new node, and then keep trying to add that node to the list. You need the first line to be inside the for loop, so you create lots of nodes. After the constructor completes, your list only contains one node, with the value 3. Then later, in display():
System.out.println(temp.getNext());
You start by calling getNext() on the first node. Since there's only one node, getNext() returns null, which is what you print out. You should replace this line with
System.out.println(temp);
The error is nothing to do with the this keyword at all. You only need this.foo (when foo is some data member of your class) to disambiguate when you have a both a member and a local variable or parameter with the same name.