I'm going over data structures with my java book and i'm needing to recreate a circular linked list. I'm having issues with this linked list infinitely looping and cannot figure out why. I'm able to insert the values into the list, however printing and deleting the values seems to infinitely loop the values initially inserted. How can I change my List class to avoid infinitely looping?
Output:
30, 5, 15, 20, 10, 30, 5, 15, 20, 10, 30, 5, 15, 20, 10, ...
Main:
public static void main(String[] args) {
CircularList theList = new CircularList();
theList.insert(10);
theList.insert(20);
theList.insert(15);
theList.insert(5);
theList.insert(30);
theList.displayList();
System.out.println(theList.delete());
theList.delete(15);
theList.displayList();
while (!theList.isEmpty()) {
Link aLink = theList.delete();
System.out.println("Deleted: " + aLink);
}
if (!theList.isEmpty())
System.out.println("Program error");
else
System.out.println("Program success");
}
CircularList.class
class CircularList {
private Link current;
private Link prev;
public CircularList() {
// implement: set both current and prev to null
current = prev = null;
}
public boolean isEmpty() {
// implement
return (current == null); // true if current is empty
}
public void insert(int id) {
// implement: insert the new node behind the current node
Link newLink = new Link(id);
if (isEmpty()) {
prev = current = newLink;
} else {
prev.next = newLink;
newLink.next = current;
current = newLink;
}
}
public Link delete() {
// implement: delete the node referred by current
if (!isEmpty()) {
Link temp = current;
current = current.next;
return temp;
} else
return null;
}
public Link delete(int id) {
// implement: delete the node with value id
// if no node with the id exists, return null
if (isEmpty()) {
return null;
}
// Link current; // start probe at beginning
Link prev = current; // start previous at current
while (current != null && current.equals(current)) {
prev = current; //save previous link
current = current.next; // move to next Link
}
if (current == current.next)
current = current.next;
else if (current != null)
prev.next = current.next;
return current;
}
public void displayList() {
// implement: print all the list element values once, each value seperated by comma
while (current != null) {
System.out.printf(current + ", ");
current = current.next;
}
}
}
Link.class
class Link {
private int id;
Link next;
public Link(int id) {
// implement
this.id = id;
next = null;
}
public String toString() {
return String.valueOf(id);
}
}
It's a circular list, current will never be null in delete(int id) and displayList() unless the list is empty.
You'll have to remember where you started looking / printing and break if you get back to the starting Link.
Because a circle goes on forever you should probably set a start/stop index:
public void displayList() {
// implement: print all the list element values once, each value seperated by comma
Link start = current;
if (start == null)
return;
do {
System.out.printf(current + ", ");
current = current.next;
} while (current != start)
}
Related
I'm trying to implement delete() method in the LinkedList, which is a custom implementation of the Linked list data structure.
The following code seems to work properly if you delete the first element or an element in the middle. But if I'm trying to delete the last element in the LinkedList, it throws a NullPointerException.
How can I fix this problem?
My code:
public class LinkedList implements List {
Node first;
Node last;
int size;
public LinkedList() {
this.first = null;
this.last = null;
this.size = 0;
}
public void add(double element) {
Node newNode = new Node(element);
if (first == null) {
first = newNode;
last = newNode;
} else {
last.next = newNode;
last = newNode;
}
size++;
}
// more methods (unrelated to the problem)
public void delete(double element) {
if (first == null) {
return;
}
if (first.value == element) {
first = first.next;
return;
}
Node current = first;
Node previous = null;
while (current != null && current.next.value != element) {
previous = current;
current = current.next;
}
if (current == null) {
return;
} else {
current.next = current.next.next;
}
}
#Override
public String toString() {
if (first == null) {
return "[]";
} else {
StringBuffer sb = new StringBuffer();
sb.append("[");
for (Node current = first; current != last; current = current.next) {
sb.append(current.value);
sb.append(",");
}
sb.append(last.value);
sb.append("]");
return sb.toString();
}
}
}
class LinkedListTest {
public static void main(String[] args) {
LinkedList list = new LinkedList();
list.add(5);
list.add(25);
list.add(-7);
list.add(80);
System.out.println(list);
list.delete(80);
System.out.println(list);
}
}
There are two issues in the implementation of the delete() method:
Condition of in the while-loop is not correct. Instead, checking if current != null you need to ensure that current.next is not null (note that it's safe to access the next property of current because iteration starts with current being assigned to first which is proved to be non-null).
You're not considering the edge-case when the Node to remove is the last one. In such a case, when control breaks out from the while-loop current.next would point to last Node, and that would mean the last field should be reassigned (since we're removing the last node).
Also, local variable previous is redundant.
public void delete(double element) {
if (first == null) {
return;
}
if (first.value == element) {
first = first.next;
return;
}
Node current = first;
while (current.next != null && current.next.value != element) {
current = current.next;
}
if (current.next == last) { // reassign last if the Node to be removed is the current last Node
last = current;
}
if (current.next != null) { // if the Node with given value was found
current.next = current.next.next;
}
}
I believe I have the code on how to remove an item in a linked list but I'm not sure how I can make it so that all occurrences of a value would be removed. Where would I need to make some changes that would have it check through all the values in the list?
I've tried to make an alternate or a dummy that pointed to the head but I wasn't sure where I was going with that.
public class LinkList {
private Link first; // ref to first link on list
// -------------------------------------------------------------
public LinkList() // constructor
{
first = null; // no links on list yet
}
// -------------------------------------------------------------
public void insertFirst(int id, double dd) {
Link newLink = new Link(id, dd);
newLink.next = first; // it points to old first link
first = newLink; // now first points to this
}
// -------------------------------------------------------------
public Link find(int key) // find link with given key
{ // (assumes non-empty list)
Link current = first; // start at 'first'
while (current.iData != key) // while no match,
{
if (current.next == null) // if end of list,
{
return null; // didn't find it
} else // not end of list,
{
current = current.next; // go to next link
}
}
return current; // found it
}
// -------------------------------------------------------------
public void displayList() // display the list
{
System.out.print("List (first-->last): ");
Link current = first; // start at beginning of list
while (current != null) // until end of list,
{
current.displayLink(); // print data
current = current.next; // move to next link
}
System.out.println("");
}
// -------------------------------------------------------------
public Link removeAll(int n) // delete link with given key
{ // (assumes non-empty list)
Link current = first; // search for link
Link previous = first;
while (current.iData != n) {
if (current.next == null) {
return null; // didn't find it
} else {
previous = current; // go to next link
current = current.next;
}
}
if (current == first) // if first link,
{
first = first.next; // change first
} else // otherwise,
{
previous.next = current.next; // bypass it
}
return current;
}
}
I expect to have all the values deleted for a given key but it I'm only able to delete one instance of a given value.
This removes all occurrences of Link with id == n. It should be the same if you want to remove by Link.iData.
public Link removeAll(int n)
{
Link head = first;
Link previous = null;
Link current = first;
while (current != null) {
if (current.id == n) {
if (previous == null) {
head = current.next;
} else {
previous.next = current.next;
}
} else {
previous = current; // if we removed current, let previous remain the same
}
current = current.next;
}
first = head;
return head;
}
Running the code like this:
LinkList l = new LinkList();
l.insertFirst(0, 0.1);
l.insertFirst(3, 3.1);
l.insertFirst(1, 1.1);
l.insertFirst(3, 3.1);
l.insertFirst(2, 2.1);
l.displayList();
l.removeAll(3);
l.displayList();
Outputs:
List (first-->last):
2 : 2.1
3 : 3.1
1 : 1.1
3 : 3.1
0 : 0.1
List (first-->last):
2 : 2.1
1 : 1.1
0 : 0.1
I have this class called ListNode, similar to yours.
public class ListNode {
public ListNode next;
public int val;
public ListNode removeAll(int n) {
ListNode newHead = null;
ListNode node = this;
//for keeping track of the node previous to the current node
ListNode prev = null;
//loop through the entire linked list
while (node != null) {
//when you encounter the val == n, delete the node
if (node.val == n) {
if (prev != null){
//this makes the previous node to point the node to the next of the current node
//if 2 -> 1 -> 3 and we have to remove node with key 1 and current node val == 1
// the following code will do this
// 2 -> 3
prev.next = node.next;
}
ListNode next = node.next;
//taking the same example
//this code will break the link : 1->3
node.next = null;
node = next;
} else {
if (newHead == null) {
newHead = node;
}
prev = node;
node = node.next;
}
}
return newHead;
}
}
You, basically, have to traverse through whole linked list, keeping track of the previous node for the current node and when you find a node with value/key/data equal to n, you make the previous node point to the next node of the current node and break the link of the current node to the next node.
Let's first start without deleting anything. To delete all occurrences, you first need to be able to iterate over the entire list (so you can look for multiple matches). Iterating over the whole list would simply be:
public void removeAll(int n) // delete link with given key
{
Link current = first;
Link previous = first;
while (current != null)
{
// simply move to the next Link
previous = current; // store the current node as the previous for the next iteration
current = current.next; // move to the next link
}
}
Next, let's add in a check to see if the current Link is one that should be deleted:
public void removeAll(int n) // delete link with given key
{
Link current = first;
Link previous = first;
while (current != null)
{
if (current.iData == n)
{
// To do...delete the current Link
}
else
{
// simply move to the next Link
previous = current; // store the current node as the previous for the next iteration
current = current.next; // move to the next link
}
}
}
Once we've found a match, there are two possibilities. Either the Link is the first Link, or it is somewhere further down in the list:
If the link is the first one, then we move current to the next Link, and make both first and previous point to the new current Link.
If we are not the first Link, then we move current to the next Link, and update the previous.next field to point to the new current Link (thus skipping over the Link to delete).
Here's the updated code:
public void removeAll(int n) // delete link with given key
{
Link current = first;
Link previous = first;
while (current != null)
{
if (current.iData == n)
{
if (current == first)
{
current = current.next;
first = current;
previous = current;
}
else
{
current = current.next;
previous.next = current;
}
}
else
{
// simply move to the next Link
previous = current;
current = current.next;
}
}
}
Here is simple recursive implementation (this implementation leaves initial list intact, and creates new without specified element):
public class Answer {
public static void main(String[] args) {
LinkedList list = new LinkedList(1, new LinkedList(2, new LinkedList(1, new LinkedList(2, new LinkedList(3, null)))));
System.out.println(list);
LinkedList withoutOne = list.removeAll(1);
System.out.println(withoutOne);
LinkedList withoutTwo = list.removeAll(2);
System.out.println(withoutTwo);
LinkedList withoutThree = list.removeAll(3);
System.out.println(withoutThree);
}
}
class LinkedList {
private int value;
private LinkedList next;
public LinkedList(int value, LinkedList next) {
this.value = value;
this.next = next;
}
public LinkedList removeAll(int value) {
if (this.next == null) {
return (this.value == value) ? null : new LinkedList(this.value, null);
} else if (this.value == value) {
return this.next.removeAll(value);
} else {
return new LinkedList(this.value, this.next.removeAll(value));
}
}
#Override
public String toString() {
String res = "LinkedList:";
for (LinkedList link = this; link != null; link = link.next) {
res += " " + link.value;
}
return res;
}
}
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);
Here is my complete Java source code for implementing a singly linked list. I have seen many tutorials where they have been talking about inserting a node at the beginning. So, I decided to add a method insertAfterNode(int y) in my code where I can add data inside a node after a particular node.
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package datastructures;
/**
*
* #author Administrator
*/
public class Link {
int data;
Link next;
public Link(int d) {
this.data = d;
}
public void display() {
System.out.println(data);
}
public static class LinkedList {
Link first;
public void insertItemFirst(int x){
Link newLink = new Link(x);
newLink.next = first;
first = newLink;
}
public Link deleteFirst() {
Link temp = first;
first = first.next;
return temp;
}
public void displayList() {
Link current = first;
while (current != null) {
current.display();
current = current.next;
}
}
// START Of METHOD
public void insertAfterNode(int y) {
// Considering LinkedList is Sorted
Link newNode = new Link(y);
Link current = first;
while (current != null) {
while (current.data < y) {
current = current.next;
newNode.next = current;
current = newNode;
}
}
}
//END Of METHOD
}
public static void main(String[] args) {
LinkedList addelements = new LinkedList();
addelements.insertItemFirst(20);
addelements.insertItemFirst(30);
addelements.insertItemFirst(40);
addelements.insertItemFirst(50);
addelements.insertAfterNode(44);
addelements.displayList();
System.out.println("After Calling Deletion Method Once ");
addelements.deleteFirst();
addelements.displayList();
}
}
The above code keeps on running in Netbeans and I had to stop the build to exit from it. I believe there is something wrong with my method implementation. Please let me know what's wrong with my following method:
public void insertAfterNode(int y) {
// Considering LinkedList is Sorted
Link newNode = new Link(y);
Link current = first;
while (current != null) {
while (current.data < y) {
current = current.next;
newNode.next = current;
current = newNode;
}
}
}
The code runs just fine without above method.
The current Link reference changes only if the y value is greater than the current.data. If the fist.data is, say, 10, and the y is 5, your code will never terminate.
You have to modify your while(current != null) cycle. Do not use the inner while.
Link newNode = new Link(y);
// "first" requires a special treatment, as we need to replace the "first" value
if(first.data > y){
// insert the new Link as first element
newNode.next = first;
first = newNode;
} else {
// we need the previous Link, because previous.next will be set to the newNode
Link previous = first;
Link current = first.next;
while (current != null) {
if(current.data < y) {
previous = current;
current = current.next;
} else {
// we insert newNode between previous and current
// btw. what should happen if current.data == y?
previous.next = newNode;
newNode.next = current;
break; // we are done, quit the cycle
}
}
// if the newNode.next is null at this point, means we have not inserted it yet.
// insert it as the last element in the list. previous is pointing at it.
if(newNode.next == null){
previous.next = newNode;
}
} // end of else
P.S. I hope it works, I have not tested the code :)
How I can convert this doubly linked list into a doubly linked circular list?
public class DoublyLinkedList {
private Link first;
private Link last;
public DoublyLinkedList() {
first = null;
last = null;
}
public boolean isEmpty(){
return first == null;
}
public void insertFirst(long dd){
Link newLink = new Link(dd);
if (isEmpty())
last = newLink;
else
first.previous = newLink;
newLink.next = first;
first = newLink;
}
public void insertLast(long dd){
Link newLink = new Link(dd);
if (isEmpty())
first = newLink;
else {
last.next = newLink;
newLink.previous = last;
}
last = newLink;
}
public Link deleteFirst(){
Link temp = first;
if (first.next == null)
last = null;
else
first.next.previous = null;
first = first.next;
return temp;
}
public Link deleteLast(){
Link temp = last;
if (first.next == null)
first = null;
else
last.previous.next = null;
last = last.previous;
return temp;
}
public boolean insertAfter(long key, long dd) {
Link current = first;
while (current.dData != key){
current = current.next;
if (current == null)
return false; // cannot find it
}
Link newLink = new Link(dd); // make new link
if (current == last) // if last link,
{
newLink.next = null;
last = newLink;
} else // not last link,
{
newLink.next = current.next;
current.next.previous = newLink;
}
newLink.previous = current;
current.next = newLink;
return true; // found it, insert
}
public Link deleteKey(long key){
Link current = first;
while (current.dData != key)
{
current = current.next;
if (current == null)
return null; // cannot find it
}
if (current == first) // found it; first item?
first = current.next;
else
current.previous.next = current.next;
if (current == last) // last item?
last = current.previous;
else
// not last
current.next.previous = current.previous;
return current; // return value
}
public void displayForward() {
System.out.print("List (first to last): ");
Link current = first; // start at beginning
while (current != null) // until end of list,
{
current.displayLink();
current = current.next; // move to next link
}
System.out.println("");
}
public void displayBackward() {
System.out.print("List : ");
Link current = last;
while (current != null){
current.displayLink();
current = current.previous;
}
System.out.println("");
}
public static void main(String[] args) {
DoublyLinkedList theList = new DoublyLinkedList();
theList.insertFirst(22);
theList.insertFirst(44);
theList.insertLast(33);
theList.insertLast(55);
theList.displayForward();
theList.displayBackward();
theList.deleteFirst();
theList.deleteLast();
theList.deleteKey(11);
theList.displayForward();
theList.insertAfter(22, 77); // insert 77 after 22
theList.insertAfter(33, 88); // insert 88 after 33
theList.displayForward();
}
}
class Link {
public long dData; // data item
public Link next; // next link in list
public Link previous; // previous link in list
public Link(long d)
{
dData = d;
}
public void displayLink(){
System.out.print(dData + " ");
}
}
Thanks
The list, as is, doesn't provide a way to iterate over its elements. If it did, you could ask the list for an iterator and get the next element of the list from the iterator, until it reaches the last element. Making it circular would change the iterator behavior: it would go back to the first element once the last element is reached.
So, the answer is that to make it circular, you have to change the methods of the list so that the next link of the last one is the first one, an the previous link of the first one is the last one. But if you don't add other methods to the list, doing it won't change anything: the public behavior of the existing methods will stay the same once the list is made circular.