How to delete a node from a linked list - java

Hey guys I wrote this deleteNode() method that works if I used numbers(int) but doesn't when I try to pass a string in. I'm printing out a String[] list of names and I'm trying to delete a certain name off the list. When I enter a name, it prints "Node not found". Like I said, if I print out a list of numbers it works great but if I change up and print a string it doesnt. Any help is appreciated.
public class BigNode {
public String dataitems;
public BigNode next;
BigNode front ;
public void initList(){
front = null;
}
public BigNode makeNode(String number){
BigNode newNode;
newNode = new BigNode();
newNode.dataitems = number;
newNode.next = null;
return newNode;
}
public boolean isListEmpty(BigNode front){
boolean balance;
if (front == null){
balance = true;
}
else {
balance = false;
}
return balance;
}
public BigNode findTail(BigNode front) {
BigNode current;
current = front;
while(current.next != null){
//System.out.print(current.dataitems);
current = current.next;
} //System.out.println(current.dataitems);
return current;
}
public void addNode(BigNode front ,String number){
BigNode tail;
if(isListEmpty(front)){
this.front = makeNode(number);
}
else {
tail = findTail(front);
tail.next = makeNode(number);
}
}
public void deleteNode(BigNode front, String value) {
BigNode curr, previous = null; boolean found;
if (!isListEmpty(front)){
curr = front;
found = false;
while ((curr.next != null) && (!found)) {
if(curr.dataitems.equals(value)) {
found = true;
}
else {
previous = curr;
curr = curr.next;
}
}
if (!found) {
if(curr.dataitems.equals(value)) {
found = true;
}
}
if (found) {
if (curr.dataitems.equals(front.dataitems)){ // front.dataitems may be wrong .dataitems
front = curr.next;
} else {
previous.next = curr.next;
}
} else {
System.out.println("Node not found!");
//curr.next = null; // Not sure If this is needed
}
}
showList(front);
}
public void printNodes(String[] len){
int j;
for (j = 0; j < len.length; j++){
addNode(front, len[j]);
} showList(front);
}
public void showList(BigNode front){
BigNode current;
current = front;
while ( current.next != null){
System.out.print(current.dataitems + ", ");
current = current.next;
}
System.out.println(current.dataitems);
}
public static void main(String[] args) {
String[] names = {"Billy Joe", "Sally Mae", "Joe Blow", "Tasha Blue"};
BigNode x = new BigNode();
x.printNodes(names);
Scanner in = new Scanner(System.in);
String delete = in.next();
x.deleteNode(x.front, delete);
}
String[] names = {name1, name2, name3, name4}
-First it prints the list, then ask what name to delete.

EDIT: Okay, I've found out what's wrong with the sample code you've posted.
You're calling Scanner.next() which reads a single word. All of your node values are two words. So if I type in "Sally Mae" it's actually just looking for "Sally".
This has nothing to do with the majority of the code in BigNode (although that could certainly be made more elegant). Basically this:
String delete = in.next();
should be
String delete = in.nextLine();
Now I would strongly suggest that you don't just change the code, but instead think about the ways you could have diagnosed this for yourself:
Add logging to your code to show value you were looking for, and each value as you tested it
Use a debugger to step through the code, watching variables
Use unit tests to test the code - those wouldn't have shown you the problem (as it wasn't in code you'd usually write tests for) but they would have given you greater confidence that the problem wasn't in the tested code.
If you try some or preferrably all of those approaches, you'll have learned a lot more from this question than just how to use Scanner...
In various places, you're comparing string references by using the == operator. That will only find your node if you pass in a reference to one of the actual string objects which exists in the list - not a reference to an equal string object.
You want something like:
if (curr.dataitems.equals(value))
(but with careful null checking).

You should be using String.equals comparison instead of == comparison,.
if(curr.dataitems == value) {
should be:
if(curr.dataitems.equals(value) {

You do comparisons with ==. For int this compares the values, but for String only the references. So is you want to remove a String with the same value but in different objects this will fail.
Use String.equals() instead.

You should always use equals() for comparing object values, not == . For instance, in your code this line:
curr.dataitems == value
should have been written as:
curr.dataitems.equals(value)

Related

How can I delete a value from a Linked List?

I am working on a project for my Data Structures class that asks me to write a class to implement a linked list of ints.
Use an inner class for the Node.
Include the methods below.
Write a tester to enable you to test all of the methods with whatever data you want in any order.
I have to create a method called "public boolean delete(int item)". This method is meant to "Delete an item from the list and return a Boolean indicating whether or not the item was deleted" I have my code for this method down below. However, when I try to delete an item from my list nothing changes. The item that I tried to delete is still there but it returns true that an item was deleted. Does someone know what I did wrong in my code and how to fix it?
import java.util.Random;
import java.util.Scanner;
public class LinkedListOfInts {
Node head;
Node tail;
private class Node {
int value;
Node nextNode;
public Node(int value, Node nextNode) {
this.value = value;
this.nextNode = nextNode;
}
}
public LinkedListOfInts(LinkedListOfInts other) {
Node tail = null;
for (Node n = other.head; n != null; n = n.nextNode) {
if (tail == null)
this.head = tail = new Node(n.value, null);
else {
tail.nextNode = new Node(n.value, null);
tail = tail.nextNode;
}
}
}
public LinkedListOfInts(int[] other) {
Node[] nodes = new Node[other.length];
for (int index = 0; index < other.length; index++) {
nodes[index] = new Node(other[index], null);
if (index > 0) {
nodes[index - 1].nextNode = nodes[index];
}
}
head = nodes[0];
}
public LinkedListOfInts(int N, int low, int high) {
Random random = new Random();
for (int i = 0; i < N; i++)
this.addToFront(random.nextInt(high - low) + low);
}
public void addToFront(int x) {
head = new Node(x, head);
}
public int deleteFromFront() {
int headValue = -1;
if (head == null)
return headValue;
else {
if (head == tail) {
head = null;
tail = null;
} else {
headValue = head.value;
head = head.nextNode;
}
}
return headValue;
}
public boolean delete(int item) {
Node previous = null;
for (Node ptr = head; ptr != null; ptr = ptr.nextNode) {
if (ptr.value == item) {
if (previous != null) {
previous = ptr;
} else
deleteFromFront();
return true;
}
previous = ptr;
}
return false;
}
public String toString() {
String result = " ";
for (Node ptr = head; ptr != null; ptr = ptr.nextNode)
result += ptr.value + " ";
return result;
}
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
LinkedListOfInts list = new LinkedListOfInts(10, 1, 20);
LinkedListOfInts copy = new LinkedListOfInts(list);
boolean done = false;
while (!done) {
System.out.println("1. Delete an Item in the Array");
System.out.println("2. toString");
switch (input.nextInt()) {
case 11:
System.out.println("Delete an Item in the Array");
System.out.println(list.delete(input.nextInt()));
break;
case 12:
System.out.println("toString");
System.out.println(list.toString());
break;
}
}
}
}
Because local variable is local. Let's go through your delete method:
Node previous = null;
This declares a new local variable named previous, which currently points at nothing. Like all local variables, and like all non-primitive variables, [A] this thing will poof out of existence once the method terminates, and [B] it's a pointer. (in java parlance, a reference). It's like an address on a slate, it's not a house. It's the address to a house.
previous = ptr;
This erases what is on your slate and copies over the house address. It doesn't copy the house, nor does it have any effect on the house whose address was on your slate before wiping out that address and copying the address of whatever the 'ptr' slate's got on it.
... method ends
... and there previous goes. In the trashcan.
a.b is java-ese for: Drive over to the address on slate 'a', and ask the house to 'b' (or change something about the house, if you're messing with fields instead of calling methods).
So, pointer = foo accomplishes nothing. head.something = foo, that does something, now you're driving. You have to drive somewhere, or change one of your fields, for this code to do anything.
previous.nextNode = ptr.nextNode; is more what you're looking for. previous is a copy of the address of the node you visited before. Changing the address on your little note isn't going to accomplish anything, you want to drive over there. previous.nextNode is: Find the scribbled address on the piece of paper named 'previous' and drive over there. Go in the house and find the box labelled 'nextNode'. Open the box, you'll find a note with an address in it. Take that address, scratch it out, and write a new address on it.
Now if somebody else, with a different piece of paper with the same address on it, drives on over and pulls that box out, they'll see what you changed.
In java, just about everthing is an address scribbled on a note and not the object itself. (the only exceptions are primitives: int, long, double, float, boolean, char, short, byte).

remove function in my linked list not working

I am supposed to build a method that will remove the first instance of a given value in a singly-linked list. However, whenever I try to test this method it will get stuck and I have to force the code to terminate.
edit: following advice, I have made a modified version method Contains that now works well and eliminates pointless repetition of Contains. so happily now the code works as it should!
Here is my code for the method:
public boolean remove(Anything m) {
//INCOMPLETE
if (this.first==null) {
System.out.println("there are no values in the list");
return false;
}
boolean returnValue;
returnValue=false;
if (this.contains(m)==true) {
Node temp=first;
while(temp.next!=null) {
if (temp.next.data==m) {
temp=temp.next.next;
temp.next=null;
returnValue=true;
}
else
returnValue=false;
}
}
return returnValue;
}
Here is my code for testing the method:
list13.addFirst("node5"); list13.addFirst("node4"); list13.addFirst("node3"); list13.addFirst("node2"); list13.addFirst("node1");
System.out.println("5-element list: " + list13);
System.out.println("Testing remove...");
System.out.println(list13.remove("node3"));
and just in case, here is the prebuilt code my assignment came with, if needed:
public class CS2LinkedList<Anything>
{
// the Node class is a private inner class used (only) by the LinkedList class
private class Node
{
private Anything data;
private Node next;
public Node(Anything a, Node n)
{
data = a;
next = n;
}
}
private Node first;
private Node last;
public CS2LinkedList()
{
first = null;
}
public boolean isEmpty()
{
return (first == null);
}
public void addFirst(Anything d)
{
Node temp = first;
first = new Node(d,temp);
}
public void clear()
{
first = null;
}
public boolean contains(Anything value)
{
for (Node curr = first; curr != null; curr = curr.next)
{
if (value.equals(curr.data)) {
return true;
}
}
return false;
}
public String toString()
{
StringBuilder result = new StringBuilder(); //String result = "";
for (Node curr = first; curr != null; curr = curr.next)
result.append(curr.data + "->"); //result = result + curr.data + "->";
result.append("[null]");
return result.toString(); //return result + "[null]";
}
```
Some issues:
At a match, you are reassigning to temp the node that follows after the node to be deleted, and then you clear temp.next. That is breaking the list after the node to be deleted.
The while loop does not change the value of temp when the if condition is not true. So the loop can hang.
You can stop the search when you have identified the node to delete. By consequence you don't need the else inside the while loop.
while(temp.next!=null) {
if (temp.next.data==m) {
// skip the node by modifying `temp.next`:
temp.next = temp.next.next;
returnValue=true;
break; // we removed the targeted node, so get out
}
temp = temp.next; // must move to next node in the list
}
It is a pity that you first iterate the list with this.contains(m), only to iterate it again to find the same node again. I would just remove that if line, and execute the loop that follows any way: it will detect whether the list contains the value or not.
Be aware that your function has no provision for removing the first node of the list. It starts comparing after the first node. You may want to cover this boundary case.

Whats wrong with my delete method in LinkedList (generic)?

I changed the LinkedList class, but it still does not work
LinearNode class
public class LinearNode<T>{
private LinearNode<T> next;
private T element;
public LinearNode()
{
next = null;
element = null;
}
public LinearNode (T elem)
{
next = null;
element = elem;
}
public LinearNode<T> getNext()
{
return next;
}
public void setNext (LinearNode<T> node)
{
next = node;
}
public T getElement()
{
return element;
}
public void setElement (T elem)
{
element = elem;
}
}
I can't figure out the problem with delete method in my java generic class
public void delete(T element){
LinearNode<T> previous = list;
LinearNode<T> current = list;
boolean found = false;
while (!found && current != null)
{
if (current.getElement ().equals (element)) {
found = true;
}
else {
previous = current;
current = current.getNext();
}
}
//found loop
if (found)//we fount the element
{
if(current == this.list){
previous.setNext (null);
this.last = previous;
}
else
if(current == this.last){
this.last.setNext(null);
this.last.equals(previous.getElement());
}
else{
previous.setNext(current.getNext());
current.setNext (null);
}
this.count--;
}
}
I have also my driver class which will delete the element from the linked list
also here the part of driver class
public void delete(){
Teacher aTeacher;
Scanner scan = new Scanner(System.in);
String number;
aTeacher = new Teacher();
System.out.println("Now you can delete teachers from the programme by their number.");
System.out.println("Please input number:");
number = scan.nextLine();
if (aTeacher.getNumber().equals(number)){
teachers.delete(aTeacher);
}
else {
System.out.println("There are no any teacher with this number.");
}
}
I can see a few problems in your code.
This loop is a little odd
while (current != null && !current.getElement().equals(element))
{
previous = current;
current = current.getNext();
found = true;
}
You shouldn't be setting found = true inside the loop on every iteration, because then you will always believe that you found the element after the loop is done. If you pass in values that you know exist in the list, then you wouldn't notice a problem. If you pass in values that are not in the list, then you will likely see current set to null later in your code.
I might write this instead
while (! found && current != null)
{
if (current.getElement ().equals (element)) {
found = true;
}
else {
previous = current;
current = current.getNext();
}
}
This block is a little odd too
if(current == this.last){
this.last.setNext(null);
this.last.equals(previous.getElement());
}
Neither of these statements seem like they would have any effect. The value of last.getNext () should already be null. this.last.equals(previous.getElement()) is merely testing whether the last node is equal to the element held in the next to last node; that evaluation should always be false and hopefully has no side-effects.
I might write this instead
if(current == this.last){
previous.setNext (null);
this.last = previous;
}
Finally, though it's not a problem for the delete per se, I would still be thorough here and make sure that the node being removed doesn't retain any references into the list.
So this
previous.setNext(current.getNext());
might become this
previous.setNext(current.getNext());
current.setNext (null);

Doubly Linked Lisl keeps getting null pointer error

I looked at all of the previous examples and cant see anything that I am doing wrong. I really struggle with null pointer exceptions for some reason and I just cant wrap my head around them.
public class DLBDictionary implements DictionaryInterface {
//Store Strings in an Node
public DLBNode firstNode;
public class DLBNode
{
public char value;
public DLBNode nextValue;
public DLBNode nextLetter;
public DLBNode(){
this.value = '/';
this.nextValue = null;
this.nextLetter = null;
}
public DLBNode(char value){
this.value = value;
this.nextValue = null;
this.nextLetter = null;
}
}
public DLBDictionary() {
DLBNode firstNode = new DLBNode('/');
}
// Add new String to end of list. If String should come before
// previous last string (i.e. it is out of order) sort the list.
// We are keeping the data sorted in this implementation of
// DictionaryInterface to make searches a bit faster.
public boolean add(String s) {
int charIndex = 0;
while(charIndex<=s.length())
{
char currentChar = s.charAt(charIndex);
boolean added = false;
while(!added)
{
if(firstNode.value == '/')
{
firstNode.value = currentChar;
added = true;
}
else if(firstNode.value == currentChar)
{
if(firstNode.nextLetter == null)
{
DLBNode newNode = new DLBNode();
firstNode.nextLetter = newNode;
firstNode = firstNode.nextLetter;
}
else
{
firstNode = firstNode.nextLetter;
}
added = true;
}
else
{
firstNode = firstNode.nextValue;
}
}
charIndex++;
}
DLBNode tempNode = new DLBNode('^');
firstNode.nextLetter = tempNode;
return true;
}
I left off the rest of my code but that last if statement is where I get the exception. It makes no sense to me! Didn't I initialize firstNode's value to '/' in the constructor? So firstNode.getValue should return '/' not a null pointer exception.
You should do
this.firstNode = new DLBNode();
in the constructor of DLBDictionary. You are actually creating a new object rather initializing your firstNode. Hope it helps.
You reset firstNode with several statements in the loop:
firstNode = firstNode.nextValue;
So it will happen that firstNode == null and this causes the NPE. The char value has nothing to do with it, it will be initialised to a character with value 0x00 anyway.

Passing object in Dlist.

The line "if (l.head.item != 9" gave me the error it said something like object is not compatible with int. I am really confused on why is that? How to fix it?
/DListNode1/
/* DListNode1.java */
public class DListNode1 {
public Object item;
// public short[][] colorVal;
public DListNode1 prev;
public DListNode1 next;
DListNode1() {
item = 0;
prev = null;
next = null;
}
DListNode1(Object i) {
item = i;
prev = null;
next = null;
}
}
//////////////
/* Double linked list */
public class DList1 {
protected DListNode1 head;
protected DListNode1 tail;
protected long size;
public DList1() {
head = null;
tail = null;
size = 0;
}
public DList1(Object a) {
head = new DListNode1();
tail = head;
head.item = a;
size = 1;
}
public DList1(Object a, Object b) {
head = new DListNode1();
head.item = a;
tail = new DListNode1();
tail.item = b;
head.next = tail;
tail.prev = head;
size = 2;
}
public void insertFront(Object i) {
DListNode1 temp = new DListNode1(i);
if (size == 0) {
head = temp;
tail = temp;
}
else {
temp.next = head;
head.prev = temp;
head = temp;
} size++;
}
public void removeFront() {
if (size == 0) {
return;
}
else if (size == 1) {
head = null;
tail = null;
size--;
}
else {
head = head.next;
head.prev = null;
size--;
}
}
public String toString() {
String result = "[ ";
DListNode1 current = head;
while (current != null) {
result = result + current.item + " ";
current = current.next;
}
return result + "]";
}
/////////////
public static void main(String[] args) {
DList1 l = new DList1();
l.insertFront(9);
if (l.head.item != 9) {
System.out.println("head.item is wrong.");
As others have pointed out, the problem is that the type of l.head.item is Object, and you can't compare that with an int using != or ==.
Options:
Cast l.head.item to Integer or int:
// This could be done in one step if you wanted
int headValue = (int) l.head.item;
if (headValue != 9)
Or
// This could be done in one step if you wanted
Integer headValue = (Integer) l.head.item;
if (headValue != 9)
Or you could do it inline:
if ((int) l.head.item != 9)
Use equals instead, which will automatically box the int to an Integer.
if (!head.equals(9))
Make your type generic instead, so you'd have a DListNode1<Integer>, and you could then be certain that all node values were Integer references (or null), and the != check would automatically unbox the Integer to an int and work.
Personally I'd definitely make this generic, but my guess is that you're relatively new to Java, and might not want to start with generics just yet.
Note that there's a difference between using equals and performing the unboxing: if the value of l.head.item is a reference to a non-Integer object, the first approach will throw a ClassCastException and the second will just go into the body of the if statement (as a string is not equal to 9, for example). Which of those is preferable depends on what you're trying to achieve in your bigger program: if it's entirely reasonable for your list to contain non-integers, you should use the equals check; if it actually indicates a programming error, then an exception is preferable as it alerts you to the error more quickly and stops your program from proceeding with invalid assumptions.
In both cases if l.head.item is null, you'll get a NullPointerException. This could be "fixed" using:
if (!Integer.valueOf(9).equals(l.head.item))
... but again it depends on what you want your code to do if the value is null.
Because a DListNode1.item is an Object not an Integer. Try casting to a Integer and compare to an Integer (9)
Compare using equals method.'==' will compare the refrence.
if(l.head.item.equals(new Integer(9))==false)
It will give you error because int is primitive:
Incompatible operand types Object and int
Change your code to:
if (!l.head.item.equals(new Integer(9))) {
Hope this helps.

Categories