I saw some solutions, but I am still unable to resolve the error in my code. My deleteFromStart method is not removing any elements from the list. Both invocations of ob.display() produce the same output. Can you tell me what I am missing, or where the error is?
LikedList:
package lab5;
public class LinkedList {
public static void main(String argsp[]){
List ob = new List();
ob.addAtStart("y", 6);
ob.addAtStart("w", 4);
ob.addAtStart("z", 3);
ob.addAtEnd("a",3);
ob.addAtEnd("b",4);
ob.addAtEnd("c",5);
ob.display();
ob.deleteFromStart();
System.out.println("\n");
ob.display();
}
}
List:
package lab5;
public class List {
Node head;
public List(){
head=null;
}
public List(Node e){
head=e;
}
Node oldfirst=null;
Node lasthead=null;
public void addAtStart(String name, int age){
Node newObject= new Node(name,age);
newObject.next=head;
if (oldfirst==null) {
oldfirst = newObject;
}
head = newObject;
lasthead = head;
}
public void display() {
Node store = head;
while (store != null) {
store.display();
store=store.next;
System.out.println();
}
}
public void addAtEnd(String name, int age){
Node atEndValue = new Node(name, age);
oldfirst.next = atEndValue;
oldfirst = atEndValue;
}
public void deleteFromStart() {
while (lasthead != null) {
lasthead = lasthead.next;
}
}
public boolean isEmpty() {
return head == null;
}
Node:
package lab5;
public class Node {
String name;
int age;
Node next;
public Node(){
name="Abc";
age=10;
next=null;
}
public Node(String name, int age ){
this.name=name;
this.age=age;
next = null;
}
public void display(){
System.out.println("Name: " + name + " Age: " + age);
}
}
tl;dr To remove the first element in a linked-list:
head = head.next
When you're implementing a singly-linked list, you really only need to keep a single pointer: head (i.e. a reference to the first node in the list. In practice, it's also useful to keep track of the last element in the list (commonly referred to as tail). This allows constant-time operations at the end of the list, which are useful if you're frequently adding elements at the end. So, with this basic implementation, you end up with something like this:
class LinkedList {
private Node head = null;
private Node tail = null;
public LinkedList() {}
public LinkedList(Node e) {
head = e;
tail = e;
}
}
class Node {
Node next = null;
// other data
}
Adding and removing elements in a linked list boils to down to updating what the head and tail variables are referring to. Consider a singly-linked list with three elements, [A, B, C]. The values head and tail values align like this:
A -> B -> C -> null
^ ^
| |
head tail
If you want to insert a new element, X, there are two steps:
1) Tell X.next to refer to A:
X -> A -> B -> C -> null
^ ^
| |
head tail
2) Update head to refer to X:
X -> A -> B -> C -> null
^ ^
| |
head tail
You move head and tail around in similar fashion, depending on whether you're adding or removing, and whether or not the operation is at the beginning or end of the list.
Removing an element from the start (assuming that the list is not empty) is as simple as updating head to refer to the next element. In our example above, this would mean moving head to refer to X.next, which is A:
X -> A -> B -> C -> null
^ ^
| |
head tail
Now remember, the linked list is only directly aware of head and tail, so once you update head to refer to A there is nothing referencing X anywhere in your application, and it has effectively been deleted (in Java this will cause it to be garbage-collected).
Effectively what we did above was simply head = head.next. Again, you'll have to ensure the list isn't empty first, since head.next will cause a null pointer exception if the list is empty.
I'd also suggest removing oldfirst and lasthead, and updating your add* methods based on the theory above.
This actually is not a Linked List it is more of a Queue where you have rear and front pointers.
While displaying the items in the list you are using the "head" pointer where as while deleting from start you are using "lasthead". This would move the lasthead but wont assign the value to head again.
public void deleteFromStart(){
while(lasthead!=null){
this.lasthead=lasthead.next;
}
head = this.lasthead;
}
Well i tried this code and it delete's all the elements from the start (I hope this is what you wanted)
For deleting first element:
public void deleteElementAtStart()
{
if(lasthead != null)
{
this.lasthead = lasthead.next;
}
else
{
System.out.println("List is already empty!");
}
head = lasthead;
}
Editted it.
Thank you everyone! I realize my mistakes I am using extra objects that's why during solution I got these two method.
public void deleteFromStart(){
while(lasthead.next!=null){
lasthead=lasthead.next;
head=lasthead;
break;
}
}
or
public void deleteFromStart(){
while(head.next!=null){
head=head.next;
break;
}
}
Related
When given an array of integers, I'm trying to change each element with the product of the integers before it.
For example, int[] array = {2,2,3,4}; is now: {2, 4, 12, 48};
I added each element to a LinkedList, and I'm trying to do this recursively.
This is what I have:
Node curr = list.getFirst();
product(curr);
public static void product(Node curr)
{
if(curr == null)
{
return;
}
else
{
int data = curr.getData() * curr.getNext().getData();
Node newNode = new Node(data);
curr.setNext(newNode);
// product(curr);
}
}
The first product works: {2,4}, but when I try to put in the recursion, I get a stackoverflow. Any suggestions??
Edit: So the reason that I'm either getting a stackoverflow or null pointer exception is because I'm updating the list, and then trying to get the next integer(but since there's only two elements in the list, there isn't a getNext()). I'm not sure how to fix this.
It looks like you were getting a bit tied up in the recursion. I modified your method to accept a Node along with the product from the previous iteration. At each step of the iteration I update the value in the already-existing List, so there is no need for using the new operator.
public static void product(Node curr, int value) {
if (curr == null) {
return;
}
else {
int data = value * curr.getData(); // compute current product
curr.setData(data); // update Node
product(curr.getNext(), data); // make recursive call
}
}
There are actually two issues with the code.
The recursion never ends, i.e. it is not actually moving to a smaller "subproblem" as the recursion is calling the same node again
and again.
After creating a new node and modifying the next we also need to connect the node "after" the next node otherwise the link will be
lost. Please check the below method which addresses both the issues.
Although I didn't do an excessive testing it is working for simple dataset.
Original List:
2->4->5->6->8->null
Multiplied List:
2->8->40->240->1920->null
public void product(Node curr) {
if (curr.getNext() == null) {
return;
} else {
int data = curr.getData() * curr.getNext().getData();
Node newNode = new Node();
newNode.setData(data);
Node nodeAfterNextNode = curr.getNext().getNext();
newNode.setNext(nodeAfterNextNode);
curr.setNext(newNode);
product(newNode);
}
}
It is because you call recursive method on the current node, so it is actually never move forward in the LinkedList. You can simply update the next node's data and call the recursive method on it. See the code below:
Node curr = list.getFirst();
product(curr);
public static void product(Node curr)
{
Node next = curr.getNext();
if(next == null)
{
return;
}
else
{
int data = curr.getData() * next.getData();
next.setData(data);
product(next);
}
}
I have been making an implementation of a Linked List to manipulate it to do various things so I could better learn it and I have come across something which I don't understand.
I have made three classes: Node, LinkedListExample, LinkedListTest
My node class looks like:
public class Node {
Node next;
Object data;
// Node constructor
public Node(Object dataValue) {
next = null;
data = dataValue;
}
public Object getData() {
return data;
}
public void setData(Object dataValue) {
data = dataValue;
}
public Node getNext() {
return next;
}
public void setNext(Node nextValue) {
next = nextValue;
}
}
My Linked List looks like:
public class LinkedListExample {
private Node head;
private int listCount;
public LinkedListExample() {
head = new Node(null);
listCount = 0;
}
public void add(Object data) {
Node temp = new Node(data);
Node current = head;
while (current.getNext() != null) {
current = current.getNext();
}
current.setNext(temp);
}
public int size() {
for (Node n = head; n.next != null; n = n.next) {
listCount++;
}
return listCount;
}
public String toString() {
String result = "";
Node current = head;
while (current.getNext() != null) {
current = current.getNext();
result += current.getData() + " ";
}
return result;
}
public String headString() {
String result = "";
Node current = head;
//current = current.getNext();
result = current.getData() + ""; /* Returns null currently */
/* If previous line replaced by result = current.getData().toString() it would result in NULL POINTER EXCEPTION */
return result;
}
}
Finally, my Linked List Test class looks like:
public class LinkedListTest {
public static void main(String[] args) {
LinkedListExample example = new LinkedListExample();
example.add(1);
example.add(2);
example.add(3);
System.out.println("The list looks like: " + example.toString());
System.out.println("The size is: " + example.size());
System.out.println("The list head is: " + example.headString());
}
}
My question is in my constructor, I create a Node object, head, and set it to null. I later go on to add three objects, 1 2 and 3 to my Linked List. I am now confused as to what is in my Linked List? Is the null value included or not? Why or why not?
When I run the program as is, my print statement would say The list looks like 1 2 3. But if I was to flip the lines within the while loop in my toString() method in LinkedListExample to look like:
current = current.getNext();
result += current.getData() + " ";
Then the output would be The list looks like null 1 2.
Does null never get replaced?
The same goes for headString(). It currently outputs The list head is: null but if I were to uncomment the previous line, I would get The list head is: 1.
On a side note, what is also the difference between using "" and toString() because as commented out in the code above, in one situation it prints out null while the other throws a null pointer exception?
Sorry if these questions are simple, I just am lost on this concept.
This is one particular way of implementing a linked list. The "head" node is not counted as part of the list.
If you counted the head node as part of the list, then when you add an item, you will find that you need to add it differently depending on whether it's the first node or not. Removing also works differently depending on whether the node is the first node.
To simplify the code, you can create a "header node" that is not used to store a value. If you do this, then you don't need to think about how to insert or remove nodes at the start of the list. Nodes with data are always after the head node, so they're never at the start.
you create a new Node and set the data value to null. So in your c'tor you create a new Node with next=null and data=dataValue=null.
So your LinkedListExample head is an element:
Node: next=null, data=null
Your add()-method creates a temporary node and sets a (temporary) current node.
Temp: next=null, data=1
Current=head: next=null, data=null
As current has no next you replace it:
Head: next=1, data=null
Next: next=null, data=1
And so on.
You head stays the same, but output null wont have an effect, it's just empty.
So, your null-head never get's replaced and the change in output is because of your
while (current.getNext() != null) {
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.
private Node back isn't used yet, and enqueue (which was push) and dequeue (which was pop) haven't really been modified except for renaming some things. Again, this was originally a stack but I'm trying to modify it into a queue. I've done non-linked list queues and stacks before with ints, but with objects and linked lists I'm sort of lost.
public class DogQueue
{
private Node front = null;
private Node back = null;
private Node element = null;
private int counter = 0;
The above is just setting up variables.
private class Node //This sets up the Linked List
//Data Structure with nodes.
{
private Dog doggy;
private Node nextNode;
private Node firstNode;
Node(Dog newDog)
{
doggy = newDog;
}
}
Node stuff which I don't quite understand is above.
public void enqueue(Dog aDog) //This should enqueue
//an object of type Dog.
{
Node dogNode = new Node(aDog);
dogNode.nextNode = front;
counter++;
front = dogNode;
}
The above here is unmodified from the push method, just renamed.
public Dog dequeue() //This should output
//the first entry in the list.
{
Dog firstDog = front.doggy;
element = front.firstNode;
counter--;
return firstDog;
}
The above here is where I'm having the most trouble- currently it behaves like pop (getting and removing the last entered element in the list).
public boolean isFull() //Checks to see if List is Full.
{
return ( counter == 5 );
}
I set up the counter to just go up to 5 so I can debug isFull.
public boolean isEmpty() //Checks to see if List is empty
{
if ( counter == 0 )
{
return true;
} else {
return false;
}
}
This just says if counter is zero, then isEmpty is true (otherwise false).
}
I suck at data structures but I believe your enqueue and dequeue are still behaving like pop and push.
The front should point to the head of the queue and the tail one past the last valid object. So the tail should eventually point to null..
I think it should be something like this:
public void enqueue(Dog aDog)
{
Node dogNode = new Node(aDog);
counter++;
if (front == null)
front = back = dogNode;
else
{
back.nextNode = dogNode;
back = dogNode;
}
}
public Node dequeue()
{
if(front == null) return null;
Dog firstDog = front ;
front = front.nextNode;
counter--;
return firstDog;
}
Here's the main issue. Queues are FIFO (first in, first out), and Stacks are LIFO (last in, first out). For a queue, the first element you enqueue is the first one you receive, and the most recent element you push onto a stack is the first one you receive.
To that end, let's examine your code a bit.
public void enqueue(Dog aDog) { //This should enqueue an object of type Dog.
Node dogNode = new Node(aDog);
dogNode.nextNode = front;
counter++;
front = dogNode;
}
You're setting the next node of your new dog element to the front. You would have to go to the end of your queue, set your most recent node to be the new node, and the new node to be null. Using your code, it would look something like this:
public void enqueue(Dog aDog) {
if(front == null) {
front = new Node(aDog);
back = front; // back will move later
} else {
Node tmp = new Node(aDog);
tmp.setFirstNode(back);
back.setNextNode(tmp);
back = tmp;
}
}
public Dog dequeue() { //This should output the first entry in the list.
Dog firstDog = front.doggy;
element = front.firstNode;
counter--;
return firstDog;
}
At least, this does actually show the first thing in the queue. But it doesn't actually move the head pointer! Using your code, to do that, it would look something like this:
public Dog dequeue() {
if(head == null) {
return null;
} else {
Dog tmp = front.getDoggy()
front = front.getNextNode(); //move the front to point to the next location
front.getFirstNode().setNextNode(null); //sever the link to the first element
front.setFirstNode(null); //sever the link to the first element
return tmp;
}
}
I'm trying to figure out how to write a method that would modify the last node in a linkedlist and change it from null to the first node when passed the first pointer from the linked list.
I tried this which turned into a error:
public void blah()
{
Node p = first;
while (p != null)
{
p = p.link;
}
p.x = p.first;
}
Try this:
public void blah() {
Node p = first;
while (p.link != null) {
p = p.link;
}
p.link = first;
}
Be aware that this will create a circular list, that's what you intend, right? Also, I'm assuming that first is an attribute of the class where blah() resides.
This would do the job for you.
public void blah(Node list){
Node firstNode = list;
while (list.link != null){
list = list.link;
}
list.link = firstNode;
}
The 'first' reference you've used in the code suggests that its a member variable. If you want to read more on Singly Linked lists in Java thoroughly, follow this link.