Is this linked list implemented circularly? - java

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!

Related

Remove an element with single Linked List (Explanation needed)

I gone through one site. it has given following code set.
it works perfectly and I completed my task. But I have a doubt with this code. And I am unable to find.
Code:
public class Node
{
private int data;
private Node next;
/**
* #return the data
*/
public int getData() {
return data;
}
/**
* #param data the data to set
*/
public void setData(int data) {
this.data = data;
}
/**
* #return the next
*/
public Node getNext() {
return next;
}
/**
* #param next the next to set
*/
public void setNext(Node next) {
this.next = next;
}
Node(int d)
{
data = d;
next = null;
}
}
class Sam
{
Node head; // head of list
/* Linked list Node*/
/* Inserts a new Node at front of the list. */
public void push(int new_data)
{
/* 1 & 2: Allocate the Node &
Put in the data*/
Node new_node = new Node(new_data);
/* 3. Make next of new Node as head */
new_node.setNext(head);
/* 4. Move the head to point to new Node */
head = new_node;
}
/* Given a reference (pointer to pointer) to the head of a list
and a position, deletes the node at the given position */
void deleteNode(int position)
{
// If linked list is empty
if (head == null)
return;
// Store head node
Node temp = head;
// If head needs to be removed
if (position == 0)
{
head = temp.getNext(); // Change head
return;
}
// Find previous node of the node to be deleted
for (int i=0; temp!=null && i<position-1; i++)
temp = temp.getNext();
// If position is more than number of ndoes
if (temp == null || temp.getNext() == null)
return;
// Node temp->next is the node to be deleted
// Store pointer to the next of node to be deleted
Node next = temp.getNext().getNext();
temp.setNext(next); // Unlink the deleted node from list
}
/* This function prints contents of linked list starting from
the given node */
public void printList()
{
Node tnode = head;
while (tnode != null)
{
System.out.print(tnode.getData()+" ");
tnode = tnode.getNext();
}
}
/* Drier program to test above functions. Ideally this function
should be in a separate user class. It is kept here to keep
code compact */
public static void main(String[] args)
{
/* Start with the empty list */
Sam llist = new Sam();
llist.push(7);
llist.push(1);
llist.push(3);
llist.push(2);
llist.push(8);
llist.push(23);
llist.push(56);
System.out.println("\nCreated Linked list is: ");
llist.printList();
llist.deleteNode(4); // Delete node at position 4
System.out.println("\nLinked List after Deletion at position 4: ");
llist.printList();
}
}
Here is my doubt.
In 'deleteNode(int position)' method 'header' is assigned to new object('temp')
And below changes done with temp, I am ok with that. after this temp object copy didn't assign to header.
Node next = temp.getNext().getNext();
temp.setNext(next);
But in printList method they used header object, and it display remaining elements after removal
public void printList()
{
Node tnode = head;
while (tnode != null)
{
System.out.print(tnode.getData()+" ");
tnode = tnode.getNext();
}
}
I just wondering how could be the changes of temp object replaced with header object (without assign temp object to header object)
Please any one help me on this
Let's say we have a LinkedList 1,2,3,4,5
Inside void deleteNode(int position) method, both head and temp are pointing to the node 1. If we want to delete a node at position 2 (node with value 3) in the list, its iterating temp until position-1 which is node with value 2.
When temp is at node with value 2 then next node is 3 & its next node is 4 is assigned to next of node 2 effectively deleting 3 as 2 is pointing to 4 directly. Note its still temp node which is being altered.
head is still pointing to 1 and so printing is working fine.
If you observe carefully head is unchanged in the entire process.
The code is perfectly fine
The purpose of Header in Delete Function is to keep pointing to First Node of Linked List.
The purpose of temp in Delete Function is to travel to that node which is at position-1 location and change next linking address.
Your Question:
How the changes will be saved, if not assigning back to header?
Answer:A person of basic programming language knowledge will understand that any change to a variable occurs immediately.In case of Linked List , all Nodes are Linked to one another.If temp is assigned to header, the head of the linked list will become unreachable.Which we don't want as header is only variable pointing to head of linked list in whole program.
Temp means temporary variable which is discarded after use.

Recursion of Linked List

When given an array of integers, I'm trying to change each element with the product of the integers before it.
For example, int[] array = {2,2,3,4}; is now: {2, 4, 12, 48};
I added each element to a LinkedList, and I'm trying to do this recursively.
This is what I have:
Node curr = list.getFirst();
product(curr);
public static void product(Node curr)
{
if(curr == null)
{
return;
}
else
{
int data = curr.getData() * curr.getNext().getData();
Node newNode = new Node(data);
curr.setNext(newNode);
// product(curr);
}
}
The first product works: {2,4}, but when I try to put in the recursion, I get a stackoverflow. Any suggestions??
Edit: So the reason that I'm either getting a stackoverflow or null pointer exception is because I'm updating the list, and then trying to get the next integer(but since there's only two elements in the list, there isn't a getNext()). I'm not sure how to fix this.
It looks like you were getting a bit tied up in the recursion. I modified your method to accept a Node along with the product from the previous iteration. At each step of the iteration I update the value in the already-existing List, so there is no need for using the new operator.
public static void product(Node curr, int value) {
if (curr == null) {
return;
}
else {
int data = value * curr.getData(); // compute current product
curr.setData(data); // update Node
product(curr.getNext(), data); // make recursive call
}
}
There are actually two issues with the code.
The recursion never ends, i.e. it is not actually moving to a smaller "subproblem" as the recursion is calling the same node again
and again.
After creating a new node and modifying the next we also need to connect the node "after" the next node otherwise the link will be
lost. Please check the below method which addresses both the issues.
Although I didn't do an excessive testing it is working for simple dataset.
Original List:
2->4->5->6->8->null
Multiplied List:
2->8->40->240->1920->null
public void product(Node curr) {
if (curr.getNext() == null) {
return;
} else {
int data = curr.getData() * curr.getNext().getData();
Node newNode = new Node();
newNode.setData(data);
Node nodeAfterNextNode = curr.getNext().getNext();
newNode.setNext(nodeAfterNextNode);
curr.setNext(newNode);
product(newNode);
}
}
It is because you call recursive method on the current node, so it is actually never move forward in the LinkedList. You can simply update the next node's data and call the recursive method on it. See the code below:
Node curr = list.getFirst();
product(curr);
public static void product(Node curr)
{
Node next = curr.getNext();
if(next == null)
{
return;
}
else
{
int data = curr.getData() * next.getData();
next.setData(data);
product(next);
}
}

What happens to the initial null value set to head of Linked List?

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) {

Circular Double Linked List Infinite Loop

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.

Why would this loop infinitely? (Java)

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)

Categories