My CS professor asked us to develop our own Java program using circular linked lists. My project is to add or delete names (of type String) from a circular list. So far, my add methods work perfectly; however, my removeNode() method does not work and does not remove the desired element. It also goes on an infinite loop and I have tried so many pieces of code and neither of them work.
My remove method is the following:
public E removeNode(E nodeToBeDeleted)
{
Node<E> nodeFound = findNode(nodeToBeDeleted);
if(nodeFound != null)
{
nodeFound.prev.next = nodeFound.next;
nodeFound.next.prev = nodeFound.prev;
size--;
return nodeFound.data;
}
return null;
}
basically, the findNode() searches for the node whose data is equal to the String plugged in as a parameter, but when I call the outputList() method, which returns a String representation of the current nodes on screen, it goes on infinite loop.
The outputList method is:
public void outputList()
{
Node<E> position = head;
do
{
System.out.print(position.data + " ==> ");
position = position.next;
} while((position != null) && (position.next != position));
}
Any help would be highly appreciated.. Thanks in advance.
The Node class is:
static class Node<E> {
/** The data value. */
private E data;
/** The link to the next node. */
private Node<E> next = null;
/** The link to the previous node. */
private Node<E> prev = null;
private Node(E dataItem) {
data = dataItem;
}
private Node(E newData, Node<E> nodeRef)
{
data = newData;
next = nodeRef;
}
private Node(Node<E> prevRef, E newData)
{
data = newData;
prev = prevRef;
}
//set next link
private Node(Node<E> newData, Node<E> nodeRef)
{
data = (E) newData;
next = nodeRef;
}
} //end class Node
while((position != null) && (position.next != position))
This should really be:
while((position != null) && (position.next != head))
Imagine if you have a singleton - the absolute base case for traversal. head and position will both be pointing to it when you start, and when you wish to advance, position will refer to the same place as head once again. This will continue ad infinitum.
The iteration must stop when you've reached your starting point once again.
while(position.next != head)
I think checking above condition is enough for Doubly Circular LinkedList.
Related
This is my first post on here!
I am a CS student, so I'm still learning. If you have any advice or pointers (haha..!) to give as far as structuring my code or general practice, I'd appreciate any feedback!
I was given an assignment to re-implement the Queue class in java (https://docs.oracle.com/javase/7/docs/api/java/util/Queue.html) using a circular linked list. My submission is attached to this question. I received a zero on the assignment -- according to the grader my implementation of the linked list is not circular.
I do not want to come off as egotistical or too self-assured, because I obviously have no idea what I'm doing to some degree, but in lines 155 through 161 I have commented-out a section that prints out the data of the next link in the list. To my knowledge, the nodes in the list are linked circularly, because they continue to print the first node's data even after the last node's data has been printed.
For example (and I know this segment looks messy, I only have it set like this for the purpose of debugging -- this is actually the section I have commented-out my actual code):
System.out.println("next: " + cursor.getNext().getData());
System.out.println("next.next: " + cursor.getNext().getNext().getData());
System.out.println("next.next.next: " + cursor.getNext().getNext().getNext().getData());
System.out.println("next.next.next.next: " + cursor.getNext().getNext().getNext().getNext().getData());
prints:
next: 45
next.next: 71
next.next.next: 3
next.next.next.next: 45
when there are three nodes containing data entered in the list.
Furthermore, the add method starting on line 30 assigns the next node after the tail of the list to the head (as opposed to a null value), thus the list should cycle circularly, correct?
Here's a segment:
Node<T> node = new Node<T>(element);
if(isEmpty() == true){
head = node;
}else{tail.setNext(node);}
tail = node;
node.setNext(head);
I guess my question is: in what way is this not implemented circularly?
Again it totally is possible that I have no idea what I am talking about, but to my knowledge, this is in fact a circular linked list.
Thank you in advance for any help!
Full code (the three classes are CircularLinkedQueue, Node, and CircularLinkedListTest, respectively):
CircularLinkedQueue:
import java.util.NoSuchElementException;
public class CircularLinkedQueue<T> {
int count = 0;
private Node<T> head = null;
private Node<T> tail = head;
public CircularLinkedQueue(){
Node<T> node = new Node<T>();
tail = node;
}
/* Inserts the specified element into this queue if it is
* possible to do so immediately without violating capacity
* restrictions, returning true upon success and throwing
* an IllegalStateException if no space is currently available.
*/
public boolean add(T element){
try{
Node<T> node = new Node<T>(element);
if(isEmpty() == true){
head = node;
}else{tail.setNext(node);}
tail = node;
node.setNext(head);
count++;
return true;
}catch(Exception all){
Node<T> node = new Node<T>(element);
if(element == null){throw new NullPointerException("Specified
element is null.");}
else if(element.getClass().getName() !=
node.getData().getClass().getName()){
throw new ClassCastException
("Class of specified element prevents it from being added.");
}
return false;
}
}
/* Retrieves, but does not remove, the head of this queue.
* This method differs from peek only in that it throws
* an exception if this queue is empty.
*/
public T element(){
Node<T> cursor;
if(isEmpty() != true){
cursor = head;
}else{throw new NoSuchElementException("No such element exists.");}
return cursor.getData();
}
/*
Inserts the specified element into this queue if it is possible
to do so immediately without violating capacity restrictions.
When using a capacity-restricted queue, this method is generally
preferable to add(E), which can fail to insert an element only
by throwing an exception.
/*
public boolean offer(T element){
try{
Node<T> node = new Node<T>(element);
if(isEmpty() == true){
head = node;
}else{tail.setNext(node);}
tail = node;
node.setNext(head);
count++;
return true;
}catch(Exception all){return false;}
}
/* Retrieves, but does not remove, the head of this queue,
* or returns null if this queue is empty.
*/
public T peek(){
Node<T> cursor;
//set cursor to head if not empty, create new null node otherwise
if(isEmpty() != true){
cursor = head;
}else{cursor = new Node<T>(); cursor.setData(null);}
//return null if no data is stored
return cursor.getData();
}
/* Retrieves and removes the head of this queue,
* or returns null if this queue is empty.
*/
public T poll(){
Node<T> cursor = head;
if(isEmpty() != true){
if(count <= 1){
head.setNext(null);
head = head.getNext();
tail = head;
count--;
return null;
}else{
//cursor = head;
head = head.getNext();
tail.setNext(head);
}
}else{cursor = new Node<T>(); cursor.setData(null);}
count--;
return cursor.getData();
}
/* Retrieves and removes the head of this queue.
* This method differs from poll only in that it
* throws an exception if this queue is empty.
*/
public T remove(){
Node<T> cursor;
if(isEmpty() != true){
if(count <= 1){
head.setNext(null);
head = head.getNext();
tail = head;
count--;
return null;
}else{
cursor = head;
head = head.getNext();
tail.setNext(head);
}
}
else{throw new NoSuchElementException("No such element exists.");}
count--;
return cursor.getData();
}
//returns whether the list is empty or not
public boolean isEmpty(){return head == null;}
/* This method puts all the values of the circular linked list
* into a String type for output purposes.
*/
#Override
public String toString(){
int cycles = count;
String s = "";
Node<T> cursor = head;
while(cycles > 0){
s = s + cursor.getData() + "\n";
cursor = cursor.getNext();
cycles--;
}
/*
* these lines print as expected & exist only for debugging purposes
System.out.println("next: " + cursor.getNext().getData());
System.out.println("next.next: " +
cursor.getNext().getNext().getData());
System.out.println("next.next.next: " +
cursor.getNext().getNext().getNext().getData());
System.out.println("next.next.next.next: " +
cursor.getNext().getNext().getNext().getNext().getData());
*/
return s;
}
//returns the length of the list
public int getCount(){return count;}
}
Node:
public class Node<T> {
T data;
Node<T> next;
public Node(){data = null;}
public Node(T data){this.data = data;}
public void setData(T data){this.data = data;}
public void setNext(Node<T> nextNode){next = nextNode;}
public T getData(){return data;}
public Node<T> getNext(){return next;}
}
CircularLinkedListTest:
public class CircularLinkedListTest<T>{
public static void main(String[] args) {
/* demonstrates creation of new circular linked lists/linked queues,
* uses two different data types
*/
CircularLinkedQueue<Integer> c1 = new CircularLinkedQueue<Integer>();
CircularLinkedQueue<String> c2 = new CircularLinkedQueue<String>();
//demonstrate add and offer methods detailed in Queue interface
c1.add(3);
c1.offer(45);
c1.offer(71);
c2.add("hello");
c2.offer("good evening");
c2.offer("how do you do");
//demonstrates a toString method and prints after data has been added
System.out.println("c1.toString(): \n" + c1.toString());
System.out.println("c2.toString(): \n" + c2.toString());
/* demonstrates the remove and poll methods, prints out the values in
the list,
* poll method returns null when implemented, isEmpty method shows the
* nodes are truly being removed from the list after poll or remove
methods are
* called
*/
c1.remove();
c2.remove();
c2.remove();
System.out.println("c1.toString(): \n" + c1.toString());
System.out.println("c2.poll(): " + c2.poll());
System.out.println("c2.getCount(): " + c2.getCount());
System.out.println("c2.isEmpty(): " + c2.isEmpty());
System.out.println("");
//re-add data to c2
c2.offer("howdy");
c2.offer("hi there");
//reprint c2, getCount and isEmpty to prove updated data values
System.out.println("c2.toString(): \n" + c2.toString());
System.out.println("c2.getCount(): " + c2.getCount());
System.out.println("c2.isEmpty(): " + c2.isEmpty());
System.out.println("");
/* demonstrate peek and element functions by printing out most
* recent items in the linked queue
*/
System.out.println("c1.peek(): " + c1.peek());
System.out.println("c2.element(): " + c2.peek());
System.out.println("");
//remove items from c1 to show peek returns null when list is empty
c1.remove();
c1.remove();
System.out.println("c1.peek(): " + c1.peek());
System.out.println("c1.getCount(): " + c1.getCount());
System.out.println("c1.isEmpty(): " + c1.isEmpty());
//all methods in queue interface have been demonstrated
}
}
Thank you again in advance for any help!
I received a zero on the assignment -- according to the grader my implementation of the linked list is not circular.
I find that assessment a bit harsh. Looking from the outside, your class behaves circular: it is able to add new values in O(1) time, and the "last" value has a link to the "first", closing the loop.
I guess my question is: in what way is this not implemented circularly?
In a truly circular implementation,
I wouldn't expect to see notions of "head" and "tail".
After all, a circle has no beginning and no end.
It may have a current element, with links to next and previous elements.
And maybe this is what was required.
Looking from the inside,
this implementation looks very similar to a run-of-the-mill linked list,
with fast access to tail.
It would be best to ask the grader!
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.. ?
I have been making an implementation of a Linked List to manipulate it to do various things so I could better learn it and I have come across something which I don't understand.
I have made three classes: Node, LinkedListExample, LinkedListTest
My node class looks like:
public class Node {
Node next;
Object data;
// Node constructor
public Node(Object dataValue) {
next = null;
data = dataValue;
}
public Object getData() {
return data;
}
public void setData(Object dataValue) {
data = dataValue;
}
public Node getNext() {
return next;
}
public void setNext(Node nextValue) {
next = nextValue;
}
}
My Linked List looks like:
public class LinkedListExample {
private Node head;
private int listCount;
public LinkedListExample() {
head = new Node(null);
listCount = 0;
}
public void add(Object data) {
Node temp = new Node(data);
Node current = head;
while (current.getNext() != null) {
current = current.getNext();
}
current.setNext(temp);
}
public int size() {
for (Node n = head; n.next != null; n = n.next) {
listCount++;
}
return listCount;
}
public String toString() {
String result = "";
Node current = head;
while (current.getNext() != null) {
current = current.getNext();
result += current.getData() + " ";
}
return result;
}
public String headString() {
String result = "";
Node current = head;
//current = current.getNext();
result = current.getData() + ""; /* Returns null currently */
/* If previous line replaced by result = current.getData().toString() it would result in NULL POINTER EXCEPTION */
return result;
}
}
Finally, my Linked List Test class looks like:
public class LinkedListTest {
public static void main(String[] args) {
LinkedListExample example = new LinkedListExample();
example.add(1);
example.add(2);
example.add(3);
System.out.println("The list looks like: " + example.toString());
System.out.println("The size is: " + example.size());
System.out.println("The list head is: " + example.headString());
}
}
My question is in my constructor, I create a Node object, head, and set it to null. I later go on to add three objects, 1 2 and 3 to my Linked List. I am now confused as to what is in my Linked List? Is the null value included or not? Why or why not?
When I run the program as is, my print statement would say The list looks like 1 2 3. But if I was to flip the lines within the while loop in my toString() method in LinkedListExample to look like:
current = current.getNext();
result += current.getData() + " ";
Then the output would be The list looks like null 1 2.
Does null never get replaced?
The same goes for headString(). It currently outputs The list head is: null but if I were to uncomment the previous line, I would get The list head is: 1.
On a side note, what is also the difference between using "" and toString() because as commented out in the code above, in one situation it prints out null while the other throws a null pointer exception?
Sorry if these questions are simple, I just am lost on this concept.
This is one particular way of implementing a linked list. The "head" node is not counted as part of the list.
If you counted the head node as part of the list, then when you add an item, you will find that you need to add it differently depending on whether it's the first node or not. Removing also works differently depending on whether the node is the first node.
To simplify the code, you can create a "header node" that is not used to store a value. If you do this, then you don't need to think about how to insert or remove nodes at the start of the list. Nodes with data are always after the head node, so they're never at the start.
you create a new Node and set the data value to null. So in your c'tor you create a new Node with next=null and data=dataValue=null.
So your LinkedListExample head is an element:
Node: next=null, data=null
Your add()-method creates a temporary node and sets a (temporary) current node.
Temp: next=null, data=1
Current=head: next=null, data=null
As current has no next you replace it:
Head: next=1, data=null
Next: next=null, data=1
And so on.
You head stays the same, but output null wont have an effect, it's just empty.
So, your null-head never get's replaced and the change in output is because of your
while (current.getNext() != null) {
I have the following Node class used to implement linked list:
class Node {
Node next = null;
int data;
public Node (int d) {
data = d;
}
void AppendToTail (int d) {
Node end = new Node(d);
Node current = this;
while (current.next != null) {
current = current.next;
}
current.next = end;
}
}
And I want to create a method that given a Node, it will delete it from a Linked list. So, I know how to create a function like this. But I am unsure how would I make it fit in my class.
Node deleteNode(Node head, Node toDelete) {
Node n = head;
if (n.data == toDelete.data) {
return head.next;
}
while (n.next != null) {
if (n.next.data == toDelete.data) {
n.next = n.next.next;
return head;
}
n = n.next;
}
return head;
}
However, I am failing to see how would I put that into my Node class. Any suggestions?
Make the function a static function in the Node class.
A problem I see would be you not putting the append and delete functions into the linked list class rather than in the node class. You should have the node class be totally separate from the linked list class. Therefore you can have the append and delete methods in the linked list class that add and delete instances of your node class. This helps you because then you don't have to worry about the node class one its created, you can just focus on the implementation in the linked list class.
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)