I know this question's been asked a couple times before, but none of the other topics seem to discuss exactly what I'm trying to do.
public void add(int Value) {
DListNode previous = null;
DListNode current = first;
while ((Integer)current.getValue() < Value) {
previous = current; //move previous up to current
current = current.getNext(); //advance current one node ahead
if (current == null) { //if current is the very last node in the list
break;
}
}
if (previous == null) { //if the previous object is null, the value should be inserted at the front
first = new DListNode(Value, first, null);
}
else { //if not, the value should be inserted between current and previous
previous.setNext(new DListNode(Value, current, previous));
}
getLast(); //updates the last field (Not important)
}
DListNode is a class that contains an integer variable, the Next DListNode, and the previous DListNode (along with the standard getter and setter methods). It's initialized with the arguments DListNode(value, next node, previous node). The value stored is of type Object.
What I'm trying to do is insert a new node between current and previous. The new node should be set as the next node of previous, with current being set as the next node of the new one, while setting previous as the previous node of the new node, and the new node as the previous node of current. This should only happen if the value is greater than the value contained in the first node. However, the nodes only become linked forwards, and I have no idea why.
I can post the entire class if necessary, any help or ideas would be greatly appreciated.
edit: I figured it out with the help of Archer. In case anyone's wondering, this is my final method (i had to add another if/else statement to deal with nullPointerErrors).
public void add(int Value) {
DListNode previous = null;
DListNode current = first;
while ((Integer)current.getValue() < Value) {
previous = current; //move previous up to current
current = current.getNext(); //advance current one node ahead
if (current == null) { //if current is the very last node in the list
break;
}
}
if (previous == null) { //if the previous object is null, the value should be inserted at the front
DListNode insert = new DListNode(Value, current, previous);
current.setPrevious(insert);
first = insert;
}
else { //if not, the value should be inserted between current and previous
if (current == null) {
DListNode insert = new DListNode(Value, current, previous);
previous.setNext(insert);
}
else {
DListNode insert = new DListNode(Value, current, previous);
current.setPrevious(insert);
previous.setNext(insert);
}
}
getLast(); //updates the last field
}
There's a problem in these lines:
first = new DListNode(Value, first, null);
and
previous.setNext(new DListNode(Value, current, previous));
You're just adding the node without updating the refereces of nearby nodes.
First line should look like:
first = new DListNode(Value, first, null);
first.getNext().setPrevious(first)
second line should look like:
previous.setNext(new DListNode(Value, current, previous));
current.setPrevious(previous.getNext())
Something like that.
Related
My current implementation of the removal operation of linked lists only works when the Node to be removed is not at the end of the list. I need the previous Node to now point to null, instead of pointing to the last Node, in order for it to be deleted. Instead of throwing a NullPointerException, the remove operation for the last Node just keeps the list as is. How would I change the else if condition to reflect this?
public Book remove(Book bookToRemove){
Node current = head; //each Node stores a Book
if(isEmpty()){
System.out.println("No books to remove!");
}
//what happens if the next next one is null?
while(current.getNext() != null && !isEmpty()){
if(current.getNext().getBook().equals(bookToRemove)){
Node temp = current.getNext();
current.setNext(temp.getNext());
return bookToRemove;
}
else if(current.getNext() == null){ //
//if the next node is null, it cannot be removed, or the previous node will have nothing to point to
current.setNext(null);
return bookToRemove;
}
current = current.getNext();
}
return bookToRemove;
}
Modified the initial suggestion, just check the head node first and if that is the one to be removed, make the change to the head and exit the function. The rest of the flow will take care of removing at any other location in the list.
public Book remove(Book bookToRemove)
{
Node current = head; //each Node stores a Book
if(isEmpty())
{
System.out.println("No books to remove!");
return bookToRemove; //no need to continue
}
if(current.getBook().equals(bookToRemove))
{
//found in head itself, make new head and exit
head = current.getNext();
return bookToRemove;
}
while(current.getNext() != null && !isEmpty())
{
if(current.getNext().getBook().equals(bookToRemove))
{
Node temp = current.getNext();
current.setNext(temp.getNext());
return bookToRemove;
}
current = current.getNext();
}
return bookToRemove;
}
I am having a lot of difficulty figuring out the add method of a linked list. My assignment says to:
Implement this method, public void add(E item), inside MoveToFront
class. The method behaves like this: when the input does not exist in
the linked list, add it at the front; otherwise remove the existing
one from the list and reinsert it to the front.
What I have done so far is create a contains and delete method that will search for the existing item in the list and then delete it. Then it will add the item to the front of the list.
public int getLength() {
Node<E> curNode = first;
int count = 0;
while (curNode != null) {
curNode = curNode.next;
count++;
}
return count;
}
public boolean Contains(E item) {
if (first == null) {
return false;
}
Node<E> currentNode = first;
while (currentNode.next != null) {
containCount++;
if (currentNode.item.equals(item)) {
return true;
}
currentNode = currentNode.next;
}
return false;
}
public E Delete(int kth) {
if (kth <= getLength()) {
Node<E> currentNode = first;
for (int i = 1; i < kth; i++) {
currentNode = currentNode.next;
}
currentNode.next = currentNode.next.next;
return currentNode.item;
} else {
return null;
}
}
public void add(E item) {
if (!Contains(item)) {
Node<E> myNode = new Node<E>(item, null);
first = myNode;
} else {
Delete(containCount);
Node<E> myNode = new Node<E>(item, null);
first = myNode;
}
}
I think you aren't properly linking the nodes. Before you set the node you're inserting as the first node, set the node's next to the old first, like this:
myNode.next = first;
first = myNode;
A couple of things:
Instead of going through the list twice to first check if it contains the item, then to find and delete it, you can rewrite delete() to just go through the list and delete if a matching item is found. You can then call this method at the beginning of your add() method.
You should keep track of the size of the list with a simple instance variable that is updated whenever an item is added or removed, and then just let getLength() return this. Going through the whole list each time is way too expensive.
First of all I see a getLength() method in your code. It is a linked list, if you are trying to get the length of it for this problem then you didn't get the data structure.
Now if we get to implementation I see from the requirement you have to add new element to the front one way or another. This is how I will do that-
Create a node and link its next to the first element of current list. This will be add method.you can do this method in the end too, it will not make much difference.
Then start searching for element in the list and if you find a match delete it. Make sure you don't match with the element you just added int the front.
my question is about a exercise in lintcode which requires delet node, but for some reason my simple program won't work.
For example, input (1->2->3->4->null, 3) should output (1->2->4->null), my idea is delete next node and "copy" its value to input THIS node.
/**
* Definition for ListNode.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int val) {
* this.val = val;
* this.next = null;
* }
* }
*/
public class Solution {
/**
* #param node: the node in the list should be deleted
* #return: nothing
*/
public void deleteNode(ListNode node) {
// write your code here
ListNode pnext;
if (node != null) {
if (node.next != null) {
ListNode tempnode = node.next;
if (node.next.next != null) {
pnext = node.next.next;
}
else {
pnext = null;
}
node.next = null; //delete next node
node = tempnode; // give next node to THIS node
node.next = pnext; // link next
}
}
else node = null;
}
}
I am very confused about giving value to node, does node1 = node2 even work? I know node.val can. Can anyone simply guide me please?
You did not include in your post what actually happens, and you did not include the part where you create your list, so I can only assume what happens is that you do not delete 3, but delete 4? Or does it not delete anything at all?
So you have a method that should delete a Node, and the Node you want to delete is given as a parameter. But as your list is only linked one way you have no way of determining the node before it (which holds the reference to the node you want to delete). Actually the delete method should be as easy as this:
public void deleteNextNode(ListNode node) {
if(node == null || node.next == null) return; //nothing to delete
if(node.next.next == null){
node.next = null;
return;
} else{
node.next = node.next.next;
}
}
Although I did not test it. As long as you don't store any other references to your nodes this is sufficient, otherwise you need to call next.null explicitely in the else part.
Edit: My function deletes the Node that follows the Node you pass, but you want a function that deletes the Node you pass it. The problem here is that the previous node stores the reference to the Node that you want to delete, but you have no way of determining that Node with only the reference to the Node you want to delete. So either you use this function and always pass the previous node, or you make a wrapper function and run through the list and always safe the previous Node and call the function with that node:
public ListNode deleteNode(ListNode start, ListNode deleteMe)
{
ListNode prev = start;
if(start == deleteMe) return start.next;
while(prev.next != null) {
if(prev.next == deleteMe)
deleteNextNode(prev);
prev = prev.next;
}
return start;
}
Note that I made the function return a ListNode, this is always the first Node of the List (in case you decide to delete the first node).
I hope this helps
You are complicating it unnecessarily and it is not that tough. As I see, you are just taking the ListNode as the parameter and not the data which you want to delete. Also, since you are using if and not while or for, you'll never end up iterating the whole list.
You should modify your function to take both the node as well as the data and start using a loop to iterate the complete list.
Here is the code snippet:
private void deleteNode(ListNode node, int data) {
while(node != null && node.data != data) {
node = node.next;
}
if(node != null) {
System.out.println("Deleted Node With Data: " + node.data);
node = node.next;
}
}
I think by:
node = tempNode; // give next node to THIS node.
You meant:
node.val = tempNode.val; // give next node value to THIS node.
That way, the next node's value is copied into the current node.
Next you would want to also do:
node.next = tempNode.next;
This way, the node effectively becomes the tempNode. I think this was your intention.. ?
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 am trying to make an add method for a linked list, but for some reason (that is not obvious to me, in fact I came here to get help finding the error) it goes into an infinite loop every time.
EDIT: I found the error, and I will keep my original code with a comment with the corrected code
public void insert(String majorName)
{
MajorNode newNode = new MajorNode(majorName, 1);
boolean inList = false;
MajorNode current = first;
if(isEmpty())
{
first = newNode;
// inList = true;
}
else
{
while(current.next != null)
{
if(current.majorName.equalsIgnoreCase(majorName))
{
current.frequency++;
inList = true;
break;
}
else
{
current = current.next;
}
}
}
if(!inList)
{
newNode.next = first;
first = newNode;
}
}
Here is my node class if it is needed:
public class MajorNode
{
public String majorName;
public int frequency;
public MajorNode next;
public MajorNode(String majorName, int frequency)
{
this.majorName = majorName;
this.frequency = frequency;
}
public String toString()
{
return majorName + " " + frequency;
}
}
On the first call to insert(), one assumes isEmpty() returns true and consequently first is set to the newNode before newNode's next field is set to the previous (null) value of first. Thus, when the list is non-empty, the loop iterates indefinitely on the last element in the list whose next field points to itself.
Out of curiosity, why are you trying to implement your own linked list functionality rather than build upon available packages (such as java.util.LinkedList<E>)?
When you create the first node you do this:
if(!inList)
{
newNode.next = first;
first = newNode;
}
This points the first nodes next at itself... hence a loop
You should be leaving the newNode.next as null for the first node, so that when you insert the second item, you reach the end of the chain..
You will have an wrong frequency if you add a node which is similar to the last node of your List. Consider this situation (adding 2 similar nodes in the empty list)
You will add a node1 in a blank list. So first & current will point to node1. (but node1.next will be null)
If you add the same node (or a node with a same majorName), you will reach to while loop (because List is not empty now). And also, you will not enter into a while loop as well. (as your current.next is still null)
and you will end up with two noes with same majorName in your list.
I would suggest to use
while(current != null)
instead of
while(current.next != null)