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.
Related
I've been struggling to figure out why this code is stuck in an infinite loop. The back story is I have found the solution, I changed the constructor to assign head is equal to null and that fixed it.
I wonder why this code is NOT working.
When I add different nodes, it is working. The code works as expected.
Issues arise when adding the same node.
public class Main {
public static void main(String[] args) {
Node one = new Node(1);
Node two = new Node(2);
LinkedList list = new LinkedList(one);
// this gives error, if i add the same nodes
list.add(two);
list.add(two);
System.out.println("Printing out:\n" + list.toString() +"\n");
}
}
public class LinkedList {
Node head;
int length = 0;
public boolean isEmpty() {
return (head==null);
}
public String toString() {
Node current = head;
String string = "Head: ";
while(current.next != null) {
string += current.toString() + " --> ";
current = current.next;
}
string += current.toString() + " --> " + current.next;
return string;
}
public LinkedList(Node node) {
// if were to set head to null and no arg, it works fine
head = node;
length = 1;
}
public void add(Node node) {
if(isEmpty()) {
System.out.println("Empty list, adding node...");
head = new Node(node.data); ++length;
return;
}
else {
Node current = head;
while(current.next != null) {
current = current.next;
}
//current.next = new Node(node.data);
current.next = node;
++length;
return;
}
}
The error is, it never terminates, hence why I think it is forever looping.
I think in your add(Node node) code. When you adding same node twice, it will point the next to itself. Therefore it would be infinite loop.
Its going in infinte loop because of while loop in toString() method of LinkedList class.
you are validating on condition
while(current.next != null) { .....}
after reaching on last node, you are not setting next of last node to null, so the condition will never terminate.
To resolve this where you are adding node point node.next = null;
current.next = node;
node.next = null;
++length;
return;
It will terminate and will not go in infinte loop
The line in your code not fine is in add method ‘current.next=node’ . Try to change it to ‘current.next=new Node(node.data)’
I am creating an implementation of a linked list and am having trouble with the add method. After testing it with several entries, my size() method always returns 1. what am i doing wrong.
public class Node {
public int data;
public Node next;
public Node(int data){
this.data = data;
}
}
public class LinkedList {
public Node first;
public Node last;
public LinkedList(){
first = null;
last = null;
}
public void add(int data){
Node newNode = new Node(data);
if(first == null){
first = newNode;
} else {
add(first, newNode);
}
}
public void add(Node currentNode, Node newNode){
if(currentNode.next != null){
add(currentNode.next, newNode);
}
currentNode.next = newNode;
}
public int size(){
if(first == null){
return 0;
}
else{
return size(first);
}
}
public int size(Node currentNode){
//Count Starts At One Because First = 1.
int count = 1;
if(currentNode == null){
return count;
}
else {
count++;
return size(currentNode.next);
}
}
}
You forgot the else in the 2-arg form of add. As it stands,
if(currentNode.next != null){
add(currentNode.next, newNode);
}
currentNode.next = newNode;
will always add the new node to first and to all the other nodes in the list. If currentNode.next = newNode appears in an else clause, it will be added correctly only to the end.
Additionally, your size method always returns 1 because the final branch always returns 1. To fix this, change
count++;
return size(currentNode.next);
to
return 1 + size(currentNode.next);
Also, replace return count; with return 1;.
Basically, your implementation is almost correct. size(Node) should return the size of the list starting with that node. If the node does not have a next, the size is 1. Otherwise, its the current node (1) + the size of the remaining tail.
You should make the 2-arg versions of add and the 1-arg version of size private since you don't want to expose the internals of your list to the public (in fact, the Node class should be a private class as well).
Additionally, you never use the last field of your class. You can either remove it, or use it to avoid the need for recursion completely in add. In the latter case, you will have to update it correctly with every new addition.
In place of return size(currentNode.next); try this return count + size(currentNode.next);
It will fix the count problem given that, the list is fine. But checking your code at a glance looks like the list addition code is also buggy.
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);
I'm working on an assignment for my Data Structures class. We have to create an address book using our own sorted linked based list adt. Right now the add method works, but it seems to make all the nodes point to the first node. Whenever I try to output the the list using getEntry() in a for loop, it gives me the last added entry each time. I've tried using toArray but it does the same thing. Can you see any problems?
public class GTSortedLinkedBasedList implements GTListADTInterface {
private Node firstNode;
private int numberOfEntries;
public GTSortedLinkedBasedList(){
//firstNode = new Node(null);
numberOfEntries = 0;
}
public void setNumberOfEntries(int x){
numberOfEntries = x;
}
public void add(ExtPersonType newEntry){
//firstNode = null;
Node newNode = new Node(newEntry);
Node nodeBefore = getNodeBefore(newEntry);
if (isEmpty() || (nodeBefore == null))
{
// Add at beginning
newNode.setNextNode(firstNode);
firstNode = newNode;
}
else
{
// Add after nodeBefore
Node nodeAfter = nodeBefore.getNextNode();
newNode.setNextNode(nodeAfter);
nodeBefore.setNextNode(newNode);
} // end if
numberOfEntries++;
}
private Node getNodeBefore(ExtPersonType anEntry){
Node currentNode = getFirstNode();
Node nodeBefore = null;
while ((currentNode != null) &&
(anEntry.getFirstName().compareTo(currentNode.getData().getFirstName()) > 0))
{
nodeBefore = currentNode;
currentNode = currentNode.getNextNode();
} // end while
return nodeBefore;
}
private class Node {
private ExtPersonType data;
private Node next;
public Node(ExtPersonType dataValue) {
next = null;
data = dataValue;
}
public Node(ExtPersonType dataValue, Node nextValue) {
next = nextValue;
data = dataValue;
}
public ExtPersonType getData(){
return data;
}
public void setData(ExtPersonType newData){
data = newData;
}
public Node getNextNode(){
return next;
}
public void setNextNode(Node newNode){
next = newNode;
}
}
public ExtPersonType getEntry(int givenPosition) {
if ((givenPosition >= 1) && (givenPosition <= numberOfEntries)){
assert !isEmpty();
return getNodeAt(givenPosition).getData();
}
else{
throw new IndexOutOfBoundsException("Illegal position given to getEntry operation.");
}
}
public void loadData(GTSortedLinkedBasedList contacts) throws FileNotFoundException{
//int index = 0;
ExtPersonType person = new ExtPersonType();
DateType tempDate = new DateType();
AddressType tempAddress = new AddressType();
Scanner file = new Scanner(new FileInputStream("Programming Assignment 1 Data.txt"));
while(file.hasNext()){
person.setFirstName(file.next());
person.setLastName(file.next());
tempDate.setMonth(file.nextInt());
tempDate.setDay(file.nextInt());
tempDate.setYear(file.nextInt());
person.setDOB(tempDate);
tempAddress.setStreetAddress(file.nextLine());
if(tempAddress.getStreetAddress().isEmpty()){
tempAddress.setStreetAddress(file.nextLine());
}
tempAddress.setCity(file.nextLine());
tempAddress.setState(file.nextLine());
tempAddress.setZipCode(file.nextLine());
person.setAddress(tempAddress);
person.setPhoneNumber(file.nextLine());
person.setPersonStatus(file.nextLine());
if(person.getPersonStatus().isEmpty()){
person.setPersonStatus(file.nextLine());
}
contacts.add(person);
System.out.println(contacts.getEntry(contacts.getLength()).getFirstName());
//index++;
}
}
public static void main(String[] args) throws FileNotFoundException {
AddressBook ab = new AddressBook();
ab.loadData(ab);
ExtPersonType people = new ExtPersonType();
//people = ab.toArray(people);
System.out.println(ab.getLength());
for(int cnt = 1; cnt <= ab.getLength(); cnt++){
people = ab.getEntry(cnt);
System.out.println(people.getFirstName());
}
}
EDIT: The add method is overwriting each previous object with the newly added one. It also doesn't seem to matter if I do a sorted list or just a basic list.
I'm not going to lie here, I'm not totally sure I understand your code but I think I see what's wrong. In your getNodeBefore() method's code, you set currentNode() always to firstNode(). I believe that is causing the problem. I see that you are trying to recursively move through the list to find the proper node but I don't think each recursive call is causing movement through the list. I suggest you add properties to the object that represent the forward and backward nodes.
Something like this...
private T data;
private Node nodeBefore;
private Node nodeAfter;
As you create objects, you assign the properties before and after and then all the information you need is contained in the object itself.
To move recursively through the list you would then just add a statement like currentNode = currentNode.nodeAfter.
Your getNodeBefore() method would simply return currentNode.nodeBefore and getNodeAfter() would return currentNode.nodeAfter.
You don't have code that handles the situation where the node being added will be the first node in the list, but the list is also not empty. In this case, getNodeBefore returns null, and your code overwrites the root node.
Try
if (isEmpty() && (nodeBefore == null))
{
// Add at beginning
newNode.setNextNode(firstNode);
firstNode = newNode;
}
else if(nodeBefore == null)
{
Node temp = new Node();
temp.setNextNode(first.next);
temp.setData(first.data);
newNode.setNextNode(temp);
firstNode = newNode;
}
I am looking at examples getting ready for an exam, and frankly, I am not very good with either recursion or lists, but particularly lists.
A node class is given, it will hold strings (not generic) write a recursive java function called concat that takes a node representing the head of a linked list and returns a string representing the concatenation of all the elements of the list if the list is empty the string should be as well.
Any help would be appreciated.
(The following is what I had type before I asked the question:)
public static String FindConcat(Node head) {
String s = "";
if(head == null) return s;
else if(head.next = null) {
s += head.data;
return s;
}
else {
}
}
Thanks for the repsonses.
In this case what recursion is finding the base case and how to "devide" the data down to this base case. So first define your "base case".
Base case: argument to the function is null
Till you get the the base case, append the text of the node and skip the first element
This is your method:
public static String FindConcat(Node head) {
if (head == null)
return ""; // base case
// devide it down (run recursive FindConcat on the _next_ node)
return head.data + FindConcat(head.next);
}
This simple example will print hello this is a linked list:
public class Test {
// this is a very basic Node class
static class Node {
String text;
Node next;
public Node(String text) {
this.text = text;
}
// used for building the list
public Node add(String text) {
next = new Node(text);
return next;
}
}
// this is the recursive method concat
public static String concat(Node node) {
if (node == null)
return "";
return node.text + " " + concat(node.next);
}
public static void main(String[] args) {
// build the list
Node head = new Node("hello");
head.add("this").add("is").add("a").add("linked").add("list");
// print the result of concat
System.out.println(concat(head));
}
}
If your node is null, return an empty string.
Otherwise, get the string, make a recursive call (to get the concatenated result for the rest of the nodes), and append that to the string and return the result.
since this sounds like homework, i'll make a suggestion.
start by writing the method that will work if the list only has one element (ie there is no next node). use that as the basis for your recursive call.
Recursive traversal of a linked list generally looks like seeing if you're at the end of the list (the reference you got was null), and if you're not, doing something to a recursive call upon the next element of the list, and if you are, doing the base case thing. Assuming that nodes look like this from the outside:
public class Node{
public Node getNext();
public String toString();
}
...your method looks like this (inside the class you're using to run this out of):
public String concatList(Node head){
if(head == null){
return ""; //empty list is a null pointer: return empty string
}
return head.toString() + concatList(head.getNext());
}
The end of the list, or no list at all, looks the same- a null pointer- and returns the blank string, as specified; everything else takes the current node and concatenates it to the list created by getting the concatenated version of the entire remainder of the string.
Be careful: if something's corrupted your list so it's actually a loop, this has no checks for that and will run forever until it runs out of stack memory, unless Java correctly detects the loop optimization of this recursive function and it will simply run forever.
Here is a very complete example:
import java.util.Arrays;
import java.util.List;
import java.util.UUID;
public class RecurisveLinkedListExample
{
public static String concat(final Node node)
{
if (node == null)
{
return "";
}
else
{
return node.getData() + concat(node.getNext());
}
}
public static void main(String[] args)
{
final List<String> input = Arrays.asList("A", "B", "C", "D");
final Node head = new Node(null, input.get(0));
Node previous = head;
for (int i = 1; i < input.size(); i++)
{
previous = previous.addNext(input.get(i));
}
System.out.println(concat(head));
}
public static class Node
{
private final UUID id;
private final Node previous;
private final String data;
private Node next;
public Node(final Node previous, final String data)
{
this.previous = previous;
this.data = data;
this.next = null;
this.id = UUID.randomUUID();
}
public Node getPrevious()
{
return previous;
}
public String getData()
{
return data;
}
public Node addNext(final String data)
{
this.next = new Node(this, data);
return this.next;
}
public Node getNext()
{
return next;
}
#Override
public String toString()
{
return String.format("%s:%s:%s",
this.previous == null ? "HEAD" : this.previous.id,
this.data,
this.next == null ? "TAIL" : this.next.id);
}
}
}