please help me to understand how does the method delete (with specifying value) work?
I understood everything except this point.
I wrote method delete but don't understand how changing field next in Link "previous" weigh with Link first, I know that the next Link will be missed, but this Link also will be missed in the first List. (it means that I don't understand how to reference type work)
package Book.LinkedList;
/**
* Created by Сергей on 06.07.2015.
*/
public class Link {
Link(int serial) {
this.serial = serial;
next = null;
}
private int serial;
private Link next;
public void setSerial(int serial) {
this.serial = serial;
}
public int getSerial() {
return serial;
}
public void setNext(Link tmp) {
next = tmp;
}
public Link getNext() {
return next;
}
public void display() {
System.out.print(serial + " ");
}
}
package Book.LinkedList;
public class LinkList {
LinkList() {
first = null;
}
private Link first;
public boolean isEmpty() {
return first == null;
}
public void insertFirst(int serial) {
Link newLink = new Link(serial);
if(first == null ) { newLink.setNext(null); }
else {
newLink.setNext(first);
}
first = newLink;
}
public void deleteFirst(){
if( isEmpty() == false){
first = first.getNext();
System.out.println("The link was successfully deleted!");
}
else {
System.out.println("The LinkList is empty, we can't delete element!");
}
}
public boolean find(int key) {
Link current = first;
if (current == null) {
System.out.println("The list is empty.");
return false;
}
do {
if (current.getSerial() == key) {
return true;
}
else {
current = current.getNext();
}
}
while (current != null);
return false;
}
// delete chosen/ selected element
// пока не понятно как данное удаление влияет именно на first, почему удаляется из first
public void delete(int key) {
Link previous = null;
Link current = first;
if (current == null) {
System.out.println("The list is empty.");
return;
}
do {
if (current.getSerial() == key) {
if(previous == null) { first = first.getNext(); return;}
else {
previous.setNext(current.getNext());
return;
}
}
else {
previous = current;
current = current.getNext();
}
}
while (current != null);
System.out.println("There isn't element with entered serial;");
}
public void displayList() {
Link current = first;
while(current != null) {
current.display();
current = current.getNext();
}
System.out.println("The linkList was successfully displayed");
}
}
You can imagine it better visually:
We make the next link skip a step in the chain, and then we simply remove the no longer needed node. Though in this case we is a bit misleading, as we never invoke deletion directly. We are just removing all references of the node, so the garbage collector will remove it after a while.
Pseudocode for this algorithm
IF the first element is null, then the list empty, DONE
IF the next element is to be removed THEN
IF the element to be removed is the first one: first = first.next() and DONE,
ELSE its not he first: just skip the node and DONE
ELSE GOTO 2.
If we got here, there was no matching element
What you need to see, that in both cases where the done is highlighted, all references are lost to the node.
Related
So I am working on a project involving Linked Lists. We have to make the Nodes and the Linked Lists ourselves (not allowed to use the Java provided ones). As part of the project, I am making a list that will automatically adjust itself upon certain criteria (when the word being entered is the same as one that already exists, move that Node to the front of the list). My code appears to run fine but after a certain amount of time, it just stops running. When I try debugging it, Eclipse just suspends the process at that point and I cannot figure out why as it provides absolutely no feedback at all. It appears to be on one of the while loops but I can't seem to figure out why. Any help would be greatly appreciated. The code is relatively long so I will paste it below this wall of text. I am not super experienced in programming yet so you might notice some mistakes/annoyances.
SelfAdjustingListOne.java
public class SelfAdjustingListOne extends UnsortedList
{
public SelfAdjustingListOne()
{
super();
}
public SelfAdjustingListOne(long timer)
{
super(timer);
}
public void adjustingAdd(Node input)
{
// If there's nothing in the list, make this the first and last node
if (getFront() == null)
{
setFront(input);
setBack(input);
input.setIndex(0);
} else if (sameWord(input) != null)
{
// If the word already exists, increment the word count and send that node to
// the front of the list
Node sameString = sameWord(input), current = getFront(), previous;
try
{
// Will return null if sameString is the first node on the list
previous = getByIndex(sameString.getIndex() - 1);
} catch (NullPointerException e)
{
previous = null;
}
// If sameString is the first node, no link needs to be set
if (previous != null)
previous.setLink(sameString.getLink());
// Link the node we are moving to the front node
sameString.setLink(getFront());
// Set the value of the front node to the node we are moving
setFront(sameString);
// Increment its count
sameString.plusCount();
// While the current node exists and has not surpassed the previous location of
// the node we moved, increment the index value of each node by 1
while (current != null && current.getIndex() != sameString.getIndex())
{
current.plusIndex();
current = current.getLink();
}
// Set the new front node's index to 0 (Beginning of the list)
sameString.setIndex(0);
plusComparisons();
plusComparisons();
} else
{
// If the list has at least one node and the word being added doesn't exist, add
// this node to the front of the list
input.setLink(getFront());
Node current = getFront();
while (current != null)
{
current.plusIndex();
current = current.getLink();
}
setFront(input);
input.setIndex(0);
plusComparisons();
plusNodeChanges();
plusNodeChanges();
}
}
}
UnsortedList.java
import java.text.DecimalFormat;
public class UnsortedList
{
private Node front;
private Node back;
private Long timer;
private int numOfComparisons;
private int nodeChanges;
public UnsortedList()
{
}
public UnsortedList(long timer)
{
this.timer = timer;
}
public void addBack(Node input)
{
if (front == null)
{
setFront(input);
setBack(input);
input.setIndex(0);
} else if (sameWord(input) != null)
{
Node sameString = sameWord(input);
sameString.plusCount();
numOfComparisons += 2;
} else
{
getBack().setLink(input);
input.setIndex(back.getIndex() + 1);
setBack(input);
numOfComparisons++;
nodeChanges += 2;
}
}
public void addFront(Node input)
{
if (front == null)
{
setFront(input);
setBack(input);
input.setIndex(0);
} else if (sameWord(input) != null)
{
Node sameString = sameWord(input);
sameString.plusCount();
numOfComparisons += 2;
} else
{
input.setLink(front);
Node current = front;
while (current != null)
{
current.plusIndex();
current = current.getLink();
}
setFront(input);
input.setIndex(0);
numOfComparisons++;
nodeChanges += 2;
}
}
public void remove(int index)
{
Node current = front;
do
{
if (current.getIndex() == index - 1)
{
if (current.getLink().getLink() != null)
{
current.getLink().setIndex(-1);
current.setLink(current.getLink().getLink());
Node currentIndexNode = current.getLink();
while (currentIndexNode != null)
{
currentIndexNode.minusIndex();
currentIndexNode = currentIndexNode.getLink();
}
} else
{
current.getLink().setIndex(-1);
current.setLink(null);
}
}
current = current.getLink();
} while (!current.isEqual(back));
}
public void setFront(Node input)
{
front = input;
}
public void setBack(Node input)
{
back = input;
}
public Node getFront()
{
return front;
}
public Node getBack()
{
return back;
}
public Node getByIndex(int index) throws NullPointerException
{
Node current = front, currentIndexNode = current.getLink();
while (current != null)
{
do
{
if (current.getIndex() == index)
return current;
current = currentIndexNode;
currentIndexNode = currentIndexNode.getLink();
} while (currentIndexNode != null);
}
return null;
}
public Node getByWord(String word) throws NullPointerException
{
Node current = front, currentIndexNode = current.getLink();
while (current != null)
{
do
{
if (current.getWord().equalsIgnoreCase(word))
return current;
current = currentIndexNode;
currentIndexNode = currentIndexNode.getLink();
} while (currentIndexNode != null);
}
return null;
}
public int totalWords()
{
Node current = front;
int totalWords = 0;
while (current != null)
{
totalWords += current.getCount();
current = current.getLink();
}
return totalWords;
}
public int totalUniqueWords()
{
Node current = front;
int totalUniqueWords = 0;
while (current != null)
{
totalUniqueWords++;
current = current.getLink();
}
return totalUniqueWords;
}
public int totalNumOfComparisons()
{
return numOfComparisons;
}
public int totalNodeChanges()
{
return nodeChanges;
}
public String totalTimeElapsed()
{
if (timer == null)
return "This is an untimed list";
DecimalFormat threePlaces = new DecimalFormat("#0.000");
return threePlaces.format((System.nanoTime() - timer) * Math.pow(10, -9)) + " seconds";
}
public void plusComparisons()
{
numOfComparisons++;
}
public void plusNodeChanges()
{
nodeChanges++;
}
protected Node sameWord(Node input)
{
Node current = front;
while (current != null)
{
if (current.getWord().equalsIgnoreCase(input.getWord()))
return current;
current = current.getLink();
}
return null;
}
}
Node.java
public class Node
{
private Node link;
private String word;
private int count = 1;
private int index = -1;
public Node(String word)
{
this.word = word;
}
public Node getLink()
{
return link;
}
public String getWord()
{
return word;
}
public int getCount()
{
return count;
}
public int getIndex()
{
return index;
}
public void setLink(Node input)
{
link = input;
}
public void setWord(String input)
{
word = input;
}
public void setCount(int input)
{
count = input;
}
public void setIndex(int input)
{
index = input;
}
public void plusCount()
{
count++;
}
public void plusIndex()
{
index++;
}
public void minusIndex()
{
index--;
}
public boolean isEqual(Node input)
{
if (input.getWord().equalsIgnoreCase(this.word))
return true;
return false;
}
}
The code which runs the SelfAdjustingListOne
public static SelfAdjustingListOne salo;
public static void main(String[] args)
{
System.out.println("Running fifth pass...");
System.out.println("Time to execute fifth pass: " + pass5());
}
public static String pass5()
{
salo = new SelfAdjustingListOne(System.nanoTime());
try
{
Scanner scanner = new Scanner(new File(fileDirectory + fileNames[0] + fileExtension));
while (scanner.hasNext())
{
String s = scanner.next();
s.replaceAll("^[^a-zA-Z0-9]+", "");
s.replaceAll("[^a-zA-Z0-9]+$", "");
if (s.length() == 1 || s.length() == 0)
{
if (!Character.isAlphabetic(s.charAt(0)) && !Character.isDigit(s.charAt(0)))
continue;
}
salo.adjustingAdd(new Node(s));
}
scanner.close();
} catch (FileNotFoundException e)
{
System.out.println("No file found matching that name/directory");
}
return salo.totalTimeElapsed();
}
The file it says it's reading in is the A Bee Movie Script which I cannot post because of the max length of a post but any text file should do.
I figured it out with a little help from samabcde.
This block of code right here needed to be changed from this:
if (previous != null)
previous.setLink(sameString.getLink());
// Link the node we are moving to the front node
sameString.setLink(getFront());
// Set the value of the front node to the node we are moving
setFront(sameString);
To this:
if(sameString != getFront())
{
sameString.setLink(getFront());
// Set the value of the front node to the node we are moving
setFront(sameString);
}
It was linking to itself because it never checked to see if the node it was setting the link of WAS ALREADY the first node in the list, therefore setting the link equal to itself.
public class LinkedList<T>
{
private Node head;
private int size;
public LinkedList()
{
}
public void addToHead(T value) // create new node, make new node point to head, and head point to new node
{
if (head == null)
{
head = new Node(value,null);
}
else
{
Node newNode = new Node(value,head);
head = newNode;
}
size++;
}
public boolean isEmpty()
{
return head == null;
}
public int size()
{
return size;
}
public void removeHead()
{
head = head.next;
size--;
}
public void addToTail(T value)
{
if (isEmpty())
{
System.out.println("You cannot addtoTail of a emptyList!");
}
else
{
System.out.println(value);
Node current = head;
System.out.println("we are pointing to head: "+current);
while (current.getNext() != null) // loop till the end of the list (find the last node)
{
System.out.println("we are now pointing to: "+current.getElement());
current = current.getNext();
}
System.out.println("We are at the last node:"+current); // its working
System.out.println("it should point to null:"+current.getNext()); // its working
current.setNext(new Node(value,null)); // make it point to our new node we want to insert
System.out.println(current.getNext()); // it is pointing to the new node.. yet the node is not actually inserted (local variable problem? )
size++;
}
}
public String toString()
{
String output = "";
if (!isEmpty())
{
Node current = head;
output = "";
while (current.getNext() != null)
{
output += current.toString()+ "->";
current = current.getNext();
}
}
return output;
}
protected class Node
{
private T element;
private Node next;
public Node()
{
this(null,null);
}
public Node(T value, Node n)
{
element = value;
next = n;
}
public T getElement()
{
return element;
}
public Node getNext()
{
return next;
}
public void setElement(T newElement)
{
element = newElement;
}
public void setNext(Node newNext)
{
next = newNext;
}
public String toString()
{
return ""+element;
}
}
}
So I have written this linkedlist class, and every method works except addtoTail. For example say I create a instance of my linkedlist class, and call addToHead(5), then addtoTail(6) and use my toString method to print out the linkedlist, it only contains 5->. I debugged the addToTail and everything seems to be pointing to the correct locations, yet for some reason it does not add the new node (6) to the list. Hopefully I explained that clearly. I am probably missing something really simple (I even drew it on paper to visualize it but do not see the problem).
Your addToTail function is probably fine. I think the culprit is your toString function. In particular, in this snippet:
while (current.getNext() != null)
{
output += current.toString()+ "->";
current = current.getNext();
}
Your condition terminates the loop before reaching the end. What you actually want is:
while(current != null) {
....
}
I'm working on a simple program to brush up on my linked list. I'm having a problem with my remove student method. All it is supposed to do is check if two students have the same student id and, if they do, remove that student since students are unique.
I'm having one main problem and that is if the student is at the end of the list it's giving me all sorts of problems. It also seems to be removing the wrong student in general..
The method is as follows
public boolean remove(StudentIF s) {
// TODO Auto-generated method stub
StudentLLNode current = head;
if(s == null){
return false;
}
if(s.getId() == (head.getStd().getId())){
//StudentLLNode top = head;
head = head.getNext();
size--;
return true;
}
else{
while(current != null){
if(s.getId() == (current.getStd().getId())){
current.setNext(current.getNext().getNext());
size--;
return true;
}
current = current.getNext();
}
}
return false;
}
Here is the stub from my interface
// remove StudentIF s *** using its equals method ***
public boolean remove(StudentIF s);
By doing:
current.setNext(current.getNext().getNext());
it seems like you are removing the next element instead of the current one.
When you hit the end of the list, getNext() returns null. And there is no next element after null, which is why you would get an exception if you reach the end of the list.
Other containers are better suited to avoid duplicate elements. For example, Sets or Maps.
Here is complete solution:
package linkedList;
import java.util.Iterator;
public class StudentList {
private int size = 0;
private StudentIF head;
public StudentList(StudentIF studentTobeAdded) {
head = studentTobeAdded;
size++;
}
public void addStudent(StudentIF studentTobeAdded) {
StudentIF curent = head;
while (curent.getNext() != null) {
curent = curent.getNext();
}
size++;
curent.setNext(studentTobeAdded);
}
public boolean removeStudent(StudentIF studentToBeRemoved)
{
int id = studentToBeRemoved.getId();
StudentIF current = head;
if (head.getId() == id) {
head = head.getNext();
size--;
return true;
}
while (current.getNext() != null) {
StudentIF next = current.getNext();
if (next.getId() == id) {
current.setNext(next.getNext());
size--;
return true;
}
current = next;
}
return false;
}
public int getSize() {
return size;
}
public StudentIF getHead() {
return head;
}
public void addListOfStudents(StudentIF... list) {
for (StudentIF studentIF : list) {
this.addStudent(studentIF);
}
}
#Override
public String toString() {
StudentIF current = head;
StringBuilder sb = new StringBuilder();
while (current != null) {
sb.append(current.getId() + " ");
current = current.getNext();
}
return sb.toString();
}
}
Student:
package linkedList;
public class StudentIF {
private int id;
private StudentIF next;
public StudentIF(int id) {
this.id = id;
next=null;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public StudentIF getNext() {
return next;
}
public void setNext(StudentIF next) {
this.next = next;
}
}
In your while loop, you don't handle the case where the student to be removed is at the end of the linked list and hence current.getNext().getNext() is an NPE.
Additionally your code is not removing the student where the Ids are equal, it's actually removing the student AFTER said student.
The following should fix your woes (though hasn't been compiled or tested).
...
else {
// head == current and if we get here, the if branch has not fired
StudentLLNode previous, next;
previous = current;
current = current.getNext();
while(current != null){
next = current.getNext();
if(s.getId() == (current.getStd().getId())){
previous.setNext(next); //doesn't matter if next is null or not
size--;
return true;
}
previous = current;
current = next;
}
...
Okay so this is just a simple program that will receive input from a user and add it to a linked list, and also give them the options to view the list and delete a node. It compiles fine and can add nodes and display the list but it will not delete a node. It works when I hand code it without the keyboard input, even with the same variable name so that's where the problem is.
public class LinkedList {
public class Link {
public String content;
public Link next;
public Link(String content) {
this.content = content;
}
public void display(){
System.out.println(content);
}
}
public static Link head;
LinkedList(){
head = null;
}
public boolean isEmpty() {
return(head == null);
}
public void insertFirstLink(String content) {
Link newLink = new Link(content);
newLink.next = head;
head = newLink;
}
public void display() {
Link theLink = head;
while(theLink != null) {
theLink.display();
theLink = theLink.next;
}
}
public Link removeLink(String content) {
Link curr = head;
Link prev = head;
while(curr.content != content) {
if (curr.next == null) {
return null;
}
else {
prev = curr;
curr = curr.next;
}
}
if(curr == head) {
head = head.next;
}
else {
prev.next = curr.next;
}
return curr;
}
}
public class Testlist {
public static void main(String[] args) {
Scanner keyboard = new Scanner(System.in);
int choice = 0;
String content;
System.out.println("Enter 1 to add to list");
System.out.println("Enter 2 to display list");
System.out.println("Enter 3 to delete node");
System.out.println("Enter 4 to quit");
choice = keyboard.nextInt();
LinkedList newlist = new LinkedList();
while(choice != 4) {
if (choice == 1) {
content = keyboard.next();
newlist.insertFirstLink(content);
newlist.display();
}
if (choice == 2) {
newlist.display();
}
if (choice == 3) {
content = keyboard.next(); // this is where is goes wrong
newlist.removeLink(content);
newlist.display();
}
System.out.println("Enter 1 to add to list");
System.out.println("Enter 2 to display list");
System.out.println("Enter 3 to delete node");
System.out.println("Enter 4 to quit");
choice = keyboard.nextInt();
}
}
}
You're using !=, which compares by reference for objects, not by value. You want to use .equals(), ie:
while(!curr.content.equals(content))
Some one may have to double check, but i'm fairly sure this is because the nextInt() method grabs the first integer and thats all. which leaves the 'enter/carriage return' in the input stream. so when the next() method is run it grabs that enter. Definatly put in some debug lines to see what content is.
For comparing string you should use equals or equalsignorecase()
For example String1="xyz";
and String2="xyz" these two strings are different if you comare them using == or != as the objects are compared instead of the actual content . the correct implementation for your program would be
package stackoverflow.practice;
public class LinkedList {
public class Link {
public String content;
public Link next;
public Link(String content) {
this.content = content;
}
public void display(){
System.out.println(content);
}
}
public static Link head;
LinkedList(){
head = null;
}
public boolean isEmpty() {
return(head == null);
}
public void insertFirstLink(String content) {
Link newLink = new Link(content);
newLink.next = head;
head = newLink;
}
public void display() {
Link theLink = head;
while(theLink != null) {
theLink.display();
theLink = theLink.next;
}
}
public Link removeLink(String content) {
Link curr = head;
Link prev = head;
while(!curr.content.equalsIgnoreCase(content)) {
if (curr.next == null) {
return null;
}
else {
prev = curr;
curr = curr.next;
}
}
if(curr == head) {
head = head.next;
}
else {
prev.next = curr.next;
}
return curr;
}
}
Also use 'equals' in this line: 'if(curr == head) {'.
How to remove an element from the linked list?
Is it correct way:
public E remove(E element) {
Node search = currentNode;
boolean nonStop = true;
while(((search.previous) != null) && (nonStop)) {
if(search.previous.toString().equals(element.toString())) {
System.out.println("Item found !!!");
search.previous = search.previous.previous;
nonStop = false;
} else {
search = search.previous;
}
}
currentNode = search;
return null;
}
public class Node<E> {
public E data;
public Node<E> previous;
public Node(E data) {
this.data = data;
}
public void printNode() {
System.out.println("Node details: "+data);
}
#Override
public String toString() {
// TODO Auto-generated method stub
return (String)data;
}
}
The problem is when I am printing all elements, getAllElements() is NOT giving correct answer,is there any problem in remove() method or getAllElements
public void getAllElements() {
Node<E> aNode = currentNode;
while(aNode != null) {
aNode.printNode();
aNode = aNode.previous;
}
}
The line
if(search.previous.toString().equals(element.toString())
calls to string on the node and not on the element.
It seems like your remove method does not really remove anything, you should update the pointers in your method so that nothing points toward the element you want to remove, and then garbage collector will the remove the element that nothing points to. Some pseudocode to illustrate what I mean:
public remove(Element element){
for (Element e : myLinkedList){
if (e.equals(element)){
if (next != 0)
previousPtr = nextPtr;
else
previousPtr = null;
}
}
}
Note this is not correct Java code, just pseudocode to give you an idea, I save some fun for you!! :)
Try this:
public void remove(E element)
{
Node n = head; // This is the head of the linked list-- It is the starting node of your linked list: For your case "currentNode"
Node tmp;
while(n!=null && !n.data.equals(element))
{
tmp = n;
n = n.previous;
}
if(n==null)
{
// Do your stuff
System.out.println("Element "+element+" not found.");
}
else
{
// Do your stuff
tmp.prev = n.prev;
n.prev = null;
System.out.println("Element "+element+" removed.");
}
}
// Suggestion: This method name should be "printList()"
public void getAllElements()
{
Node n = head; // In your case: "currentNode"
while(n!=null)
{
n.printNode();
n = n.previous;
}
}
Don't your elements have some kind of identifier?
Then you can do it much simpler, like here: remove an object
public E remove(E element) {
Node search = currentNode;
boolean nonStop = true;
while(((search.previous) != null) && (nonStop)) {
if(search.previous.data.equals(element)) {
System.out.println("Item found !!!");
search.previous = search.previous.previous;
nonStop = false;
}
search = search.previous;
}
return null;
}
I have found the solution for that Issue, thanks everyone for yours kind support.