SLinkedList and Node in Java - java

To start with, yes, this is for an assignment in class, but my lack of understanding on how it operates is higher than I want it to be.
We were given 3 classes, they are the following:
SLinkedList.java
package chapter3.linkedList;
public class SLinkedList<V> {
// instance variables. Add the tail reference.
protected Node<V> head, tail;
protected long size;
// methods, empty list constructor first
public SLinkedList () {
head = null;
tail = null;
size = 0;
} // end constructor of a SLinkedList
// method to add nodes to the list. Storage space for the node
// is already allocated in the calling method
public void addFirst (Node<V> node) {
// set the tail only if this is the very first node
if (tail == null)
tail = node;
node.setNext (head); // make next of the new node refer to the head
head = node; // give head a new value
// change our size
size++;
} // end method addFirst
// addAfter - add new node after current node, checking to see if we are at the tail
public void addAfter (Node<V>currentNode, Node<V>newNode) {
if (currentNode == tail)
tail = newNode;
newNode.setNext (currentNode.getNext ());
currentNode.setNext (newNode);
// change our size
size++;
} // end method addAfter
// addLast - add new node after the tail node. Adapted from Code Fragment 3.15, p. 118.
// Mike Qualls
public void addLast (Node<V> node) {
node.setNext (null);
tail.setNext (node);
tail = node;
size++;
} // end method addLast
// methods to remove nodes from the list. (Unfortunately, with a single linked list
// there is no way to remove last. Need a previous reference to do that. (See
// Double Linked Lists and the code below.)
public Node<V> removeFirst () {
if (head == null)
System.err.println("Error: Attempt to remove from an empty list");
// save the one to return
Node<V> temp = head;
// do reference manipulation
head = head.getNext ();
temp.setNext(null);
size--;
return temp;
} // end method removeFirst
// remove the node at the end of the list. tail refers to this node, but
// since the list is single linked, there is no way to refer to the node
// before the tail node. Need to traverse the list.
public Node<V> removeLast () {
// // declare local variables/objects
Node<V> nodeBefore;
Node<V> nodeToRemove;
// make sure we have something to remove
if (size == 0)
System.err.println("Error: Attempt to remove fron an empty list");
// traverse through the list, getting a reference to the node before
// the trailer. Since there is no previous reference.
nodeBefore = getFirst ();
// potential error ?? See an analysis and drawing that indicates the number of iterations
// 9/21/10. size - 2 to account for the head and tail nodes. We want to refer to the one before the
// tail.
for (int count = 0; count < size - 2; count++)
nodeBefore = nodeBefore.getNext ();
// save the last node
nodeToRemove = tail;
// now, do the pointer manipulation
nodeBefore.setNext (null);
tail = nodeBefore;
size--;
return nodeToRemove;
} // end method removeLast
// method remove. Remove a known node from the list. No need to search or return a value. This method
// makes use of a 'before' reference in order to allow list manipulation.
public void remove (Node<V> nodeToRemove) {
// declare local variables/references
Node<V> nodeBefore, currentNode;
// make sure we have something to remove
if (size == 0)
System.err.println("Error: Attempt to remove fron an empty list");
// starting at the beginning check for removal
currentNode = getFirst ();
if (currentNode == nodeToRemove)
removeFirst ();
currentNode = getLast ();
if (currentNode == nodeToRemove)
removeLast ();
// we've already check two nodes, check the rest
if (size - 2 > 0) {
nodeBefore = getFirst ();
currentNode = getFirst ().getNext ();
for (int count = 0; count < size - 2; count++) {
if (currentNode == nodeToRemove) {
// remove current node
nodeBefore.setNext (currentNode.getNext ());
size--;
break;
} // end if node found
// change references
nodeBefore = currentNode;
currentNode = currentNode.getNext ();
} // end loop to process elements
} // end if size - 2 > 0
} // end method remove
// the gets to return the head and/or tail nodes and size of the list
public Node<V> getFirst () { return head; }
public Node<V> getLast () { return tail; }
public long getSize () { return size; }
} // end class SLinkedList
Node.java
package chapter3.linkedList;
public class Node<V> {
// instance variables
private V element;
private Node<V> next;
// methods, constructor first
public Node () {
this (null, null); // call the constructor with two args
} // end no argument constructor
public Node (V element, Node<V> next) {
this.element = element;
this.next = next;
} // end constructor with arguments
// set/get methods
public V getElement () { return element; }
public Node<V> getNext () { return next; }
public void setElement (V element) { this.element = element; }
public void setNext (Node<V> next) { this.next = next; }
} // end class Node
and GameEntry.java
package Project_1;
public class GameEntry
{
protected String name; // name of the person earning this score
protected int score; // the score value
/** Constructor to create a game entry */
public GameEntry(String name, int score)
{
this.name = name;
this.score = score;
}
/** Retrieves the name field */
public String getName()
{
return name;
}
/** Retrieves the score field */
public int getScore()
{
return score;
}
/** Returns a string representation of this entry */
public String toString()
{
return "(" + name + ", " + score + ")";
}
}
I've spent the past 3 hours listening to his lecture, reading through the text (Data Structures and Algorithms 5th Edition), and looking through internet forums and youtube videos, but I can't seem to grasp any understanding of how to utilize the node/slinkedlist class.
The object of the assignment is "Write a class that maintains the top 10 scores or a game application, implementing the add and remove methods, but using a single linked list instead of an array.
I don't want someone to do this for me, but I do want to know how to make the linked list. I know these are NOT that hard, but doing them with this code he's given has become painfully difficult, any help would be really appreciated.
Thank you in advance.
Edit:
My main function: ScoresTest.java
package Project_1;
public class ScoresTest {
/**
* #param args
*/
public static void main(String[] args)
{
GameEntry entry;
Scores highScores = new Scores();
entry = new GameEntry("Anna", 600);
highScores.add(entry);
entry = new GameEntry("Paul", 720);
highScores.add(entry);
System.out.println("The Original High Scores");
System.out.println(highScores);
entry = new GameEntry("Jill", 1150);
highScores.add(entry);
System.out.println("Scores after adding Jill");
System.out.println(highScores);
}
}
This is for the most part exactly how it should end up looking, but it's everything that makes this work that's throwing me off...well...everything dealing with the 3 classes mentioned above, I could do this if they weren't a factor without too much of an issue, they are what's causing my blank.

Here is a skeleton, without doing much for you this at least talks you through what you have so far in the comments above:
public class ScoreDriver
{
public static void main(String[] args)
{
SLinkedList<GameEntry> sll = new SlinkedList<GameEntry>();
}
}
Once you have this in eclipse, auto-complete will take you pretty far. Instantiating the linked list class with generics could be odd if you've never seen them before. Focus, on SLinkedList though it has a lot of utility for what you want to do, don't worry about Node too much upfront.

Related

Is there a way to make this main class reverse method more efficient? Possibly requiring only one loop?

//code inside a reverse method that has the list object
//passed as a parameter from main method
int size = list.size();
//create temporary list object to hold contents of original list in reverse
MyListReferenceBased temp = new MyListReferenceBased();
for (int i = 0; i < size; i++)
{
//list add method requires which index your adding to, and object
//get method just gets the object at the specified index in list
temp.add(i, list.get((size-i)-1));
//remove method just removes object at specified index
list.remove((size-i)-1);
}
//now that original list is empty, put the contents back in
for (int i = 0; i<size; i++)
{
list.add(i, temp.get(i));
}
temp.removeAll();
//end result: original list is now reversed
//and temporary array is all empty
System.out.println("List has been Reversed.");
//is there a way to get rid of the 2nd loop?? Not possible to just assign?
So this code is in a reverse method inside the main class for reversing a linked list. Well reversing a list in general, since the user of the main class isn't suppose to interact with the linked list directly but just has access to the linked list methods (Didn't do reverse inside linked list class on purpose). Rather in the main/driver class, I'm reversing the list by first creating a second/temporary linked list, adding over each of the elements from the original list (in reverse) into the new list. And then since I need the contents to be in the original list and only need the temporary list during the duration of this method, I copy over the elements back into the old list.
The list object is instantiated as local in the main method of this main class and then calls the reverse method, passing the list object as a parameter. Instead of having the second loop, isn't there a way to just assign the temporary list object to the original list? I was able to do this when I the underlying implementation of the list was using arrays, but not sure how to it with linked lists.
Or any other efficient work around? Remember this is specifically for reversing a linked list without directly being inside the linked list class.
///FULL CODE IF NEEDED://
public class MyListReferenceBased implements ListInterface {
private Node head;
public MyListReferenceBased()
{
head = null;
}
public boolean isEmpty() {
return head == null;
}
// dont use find()
public int size() {
int size = 0;
Node curr = head;
while (curr != null) {
curr = curr.getNext();
size++;
}
return size;
}
private Node find (int index)
{
Node curr = head;
for (int skip = 0; skip < index; skip++)
{
curr = curr.getNext();
} // end for
return curr;
} // end find
public void add(int index, Object item)
throws ListIndexOutOfBoundsException
{
if (index >= 0 && index < size() + 1)
{
if (index == 0)
{
// insert the new node containing item at
// beginning of list
Node newNode = new Node(item, head);
head = newNode;
}
else
{
Node prev = find(index-1);
Node newNode = new Node(item, prev.getNext());
prev.setNext(newNode);
} // end if
}
else
{
throw new ListIndexOutOfBoundsException(
"List index out of bounds exception on add");
} // end if
} // end add
public Object get(int index)
throws ListIndexOutOfBoundsException
{
if (index >= 0 && index < size())
{
Node curr = find(index);
Object dataItem = curr.getItem();
return dataItem;
}
else
{
throw new ListIndexOutOfBoundsException(
"List index out of bounds exception on get");
} // end if
} // end get
public void remove(int index)
throws ListIndexOutOfBoundsException
{
if (index >= 0 && index < size())
{
if (index == 0)
{
head = head.getNext();
}
else
{
Node prev = find(index-1);
Node curr = prev.getNext();
prev.setNext(curr.getNext());
} // end if
}
else
{
throw new ListIndexOutOfBoundsException(
"List index out of bounds exception on remove");
} // end if
} // end remove
public void removeAll() {
head = null;
}
public String toString() {
String x = "";
Node curr = head;
int size = size();
for (int i = 0; i < size ; i++) {
// curr.getNext();
x += curr.getItem() + " ";
curr = curr.getNext();
}
return x;
}
}
///NODE CLASS///
public class Node
{
private Object item;
private Node next;
public Node(Object newItem)
{
item = newItem;
next = null;
} // end constructor
public Node(Object newItem, Node nextNode)
{
item = newItem;
next = nextNode;
} // end constructor
public void setItem(Object newItem)
{
item = newItem;
} // end setItem
public Object getItem()
{
return item;
} // end getItem
public void setNext(Node nextNode)
{
next = nextNode;
} // end setNext
public Node getNext()
{
return next;
} // end getNext
} // end class Node
Here's recursive implementation.
Base case: the tail becomes a new head, i.e. index argument is equal to size (or greater, which would be the case if the given list is empty).
Recursive case:
obtain the next that should be swapped using get(), indices of nodes to swap start from size - 2 (because it would be redundant to remove and immediately add the tail-node) and move towards 0;
invoke remove() to delete the current node;
add the new node to the tail using add();
invoke reverse() recursively passing index incremented by 1.
That's how it might look like:
public static void reverse(MyListReferenceBased list) {
reverse(list, 1, list.size()); // initial index is 1 (if the first call would with the index 0 the list would not change its state after the first execution of `reverse()` because we would be dialing with tail node which would stay on the same place)
}
public static void reverse(MyListReferenceBased list, int index, int size) {
if (index >= size) return; // Base case - tail becomes a head (we don't need to touch the tail)
// recursive case
Object valueToRemove = list.get(size - 1 - index);
list.remove(size - 1 - index);
list.add(size - 1, valueToRemove);
reverse(list, index + 1, size);
}
A link to Online Demo
Well, prepend one node after the other to an initially empty list:
/** Prepend the elements of <code>suffix</code> to <code>suffix</code>,
* in reverse order.
* #param emptied gets, well, <i>emptied</i>
* #param suffix
* #return <code>suffix</code> with the elements of
* <code>emptied</code> prepended in reverse order */
static ListInterface
prependReversed(ListInterface emptied, ListInterface suffix) {
while (!emptied.isEmpty()) {
suffix.add(0, emptied.get(0));
emptied.remove(0);
}
return suffix;
}
/** Reverse a List.
* #param emptied the list to reverse; will be empty on return
* #return a <code>MyListReferenceBased</code> containing
the elements of <code>emptied</code> in reverse order */
static MyListReferenceBased reverse_(ListInterface emptied) {
return prependReversed(emptied, new MyListReferenceBased());
}
/** Reverse a MyListReferenceBased in place (sort of).
* Argument is emptied temporarily and restored on return.
* #param toReverse the list to reverse; will be restored on return
* #return a <code>MyListReferenceBased</code> with
the elements of <code>toReverse</code> in reverse order */
public static MyListReferenceBased reverse(ListInterface toReverse) {
MyListReferenceBased
reversed = new MyListReferenceBased(),
saved = new MyListReferenceBased();
// an O(1) toReverse.clone() or saved.addAll(toReverse) would come in handy
while (!toReverse.isEmpty()) {
Object item = toReverse.get(0);
reversed.add(0, item);
saved.add(0, item);
toReverse.remove(0);
}
prependReversed(saved, toReverse);
return reversed;
}
True non-mutating variant (in O(1) timeā€¦) left as an exercise.

Reversing a Linked List not working as expected

I am currently trying to reverse a linked list, I have an unexpected problem where it doesn't print correctly. And when I try and access the values of the linked list I get an error. I would greatly appreciate an expert eye to see what I am missing. Thanks in advance.
public class SinglyLinkedList<E> implements Cloneable, Iterable<E>, List<E> {
//---------------- nested Node class ----------------
/**
* Node of a singly linked list, which stores a reference to its
* element and to the subsequent node in the list (or null if this
* is the last node).
*/
private static class Node<E> {
private E data; // reference to the element stored at this node
private Node<E> nextNode;
//methods for accessing variables
public Node<E> getNextNode() { return nextNode; }
public E getData() { return data; }
// Modifier methods
public void setNext(Node<E> n) { nextNode = n; }
public void setData(E n) { data = n; }
public Node(E e, Node<E> n) {
nextNode = n;
data = e;
}
// reference to the subsequent node in the list// TODO
} //----------- end of nested Node class -----------
// instance variables of the SinglyLinkedList
private int size = 0; // number of nodes in the list
private Node<E> head = null; // head node of the list (or null if empty)
public SinglyLinkedList() {
} // constructs an initially empty list
// access methods
/**
* Returns the number of elements in the linked list.
*
* #return number of elements in the linked list
*/
public void addFirst(E e) {
head = new Node<E>(e, head); // create the new node and link new node
size++;
}
/**
* Produces a string representation of the contents of the list.
* This exists for debugging purposes only.
*/
public String toString() {
StringBuilder temporaryString = new StringBuilder();
temporaryString.append("[");
for(Iterator<E> iterator = iterator(); iterator.hasNext();){
temporaryString.append(iterator.next()).append(", ");
}
temporaryString.deleteCharAt(temporaryString.length() - 1);
temporaryString.deleteCharAt(temporaryString.length() - 1);
temporaryString.append("]");
return temporaryString.toString();
}
private class SinglyLinkedListIterator implements Iterator<E> {
private Node<E> current;
public SinglyLinkedListIterator() {
current = head;
}
#Override
public boolean hasNext() {
return current != null;
}
#Override
public E next() {
if(!hasNext()) throw new RuntimeException("No such element");
E res = current.getData();
current = current.getNextNode();
return res;
}
}
public Iterator<E> iterator() {
return new SinglyLinkedListIterator();
}
The reverse Linked List method:
public Node<E> reverseLinkedList(SinglyLinkedList sll) {
Node<E> previous = null;
Node<E> current = sll.head;
while (current != null) {
Node<E> nextElement = current.getNextNode();
current.setNext(previous);
previous = current;
current = nextElement;
}
return previous;
}
The main method:
public static void main(String[] args) {
SinglyLinkedList<Integer> sll2 = new SinglyLinkedList<Integer>();
sll2.addFirst(1);
sll2.addFirst(2);
sll2.addFirst(3);
System.out.println(sll2.toString());
sll2.reverseLinkedList(sll2);
System.out.println(sll2.toString());
}
The output:
[3, 2, 1]
//i should expect to get 1,2,3
[3]
As you are mutating ("rewiring") the given linked list in the reverseLinkedList function, you are not actually producing a new linked list. So to have it return something is actually contradictory. Either it should return a completely new linked list without mutating the given one, or it should mutate the given linked list and not return anything.
From your main code I see that you actually expect to mutate the given linked list, as you don't use the returned value and print the result based on sll. So make your function a void one, and drop the return statement.
The core problem now is that you never change the head member: it still references what used to be the first node in the list, but is now the last one. You should assign the node to head that previously was the tail node.
So the last statement in your function should be:
sll.head = previous;

Implementing a method in the linkedList that returns the current node

I'm implementing a generic linkedList, but I had a hard time writing a function that returns the current node. It always returns the last added node. I'm sharing my code below.
I have searched for similar questions but I didn't find what I want.
Here's the linkedList file. I'm sure the add method which is vorne() is working as expected. It adds elements at the beginning.
public class Liste<T> {
// Points to the head of the Linked List
// i.e the first element
Node<T> head;
Node<T> tail;
static int size = 0;
static class Node<T> {
// Data Stored in each Node of the Linked List
T data;
// Pointer to the next node in the Linked List
Node<T> next;
// Node class constructor used to initializes the data
// in each Node
private Node(T data) {
this.data = data;
next = null;
}
}
public static <T> Liste<T> neu() {
Liste<T> l = new Liste<T>();
return l;
}
public static <T> Liste<T> einfuegen(Liste o, T auD, Nat nat) {
return null;
}
// Add element at the beginning
public static <T> Liste<T> vorne(Liste<T> list, T data) {
//Create new node
Node newNode = new Node(data);
//Checks if the list is empty.
if(list.head == null) {
//If list is empty, both head and tail would point to new node.
list.head = newNode;
list.tail = newNode;
newNode.next = list.head;
size++;
}
else {
//Store data into temporary node
Node temp = list.head;
//New node will point to temp as next node
newNode.next = temp;
//New node will be the head node
list.head = newNode;
//Since, it is circular linked list tail will point to head.
list.tail.next = list.head;
size++;
}
return list;
}
// This method should return the last added element
public static <T> T kopf(Liste<T> lNat) {
// Throws an Exception if the List is empty
if (lNat.head == null) {
System.out.print("No Element found");
}
return lNat.head.data;
}
// This method should return all the elements except the first element.
public static <T> Liste<T> rest(Liste<T> lString) {
// TODO Auto-generated method stub
if (lString.head != null) {
lString.head = lString.head.next;
}
return lString;
}
public int getCount() {
return size;
}
}
The problem arises here!
public static void main(String[] args) {
// TODO Auto-generated method stub
Liste<String> l0 = Liste.neu();
Liste<String> l1a = Liste.vorne(l0, "AuD");
Liste<String> l1b = Liste.vorne(l0, "PFP");
Liste<String> l2a = Liste.vorne(l1a, "FAUL");
Liste<String> l2b = Liste.vorne(l1b, "FAIL");
//Liste<String> l1x = Liste.rest(l2b);
//Liste<String> l1y = Liste.rest(l2b);
//Liste<String> l0x = Liste.rest(l1x);
//Liste<String> l0y = Liste.rest(l1y);
//String l0y = Liste.kopf(l2a);
System.out.println(l1b.getCount());
System.out.println(Liste.kopf(l2a));
}
The output:
4
FAIL
when I call the kopf method which supposes to return the last added element, it returns the string "FAIL" instead of "FAUL". I have stored it in a separate object, and I am calling l2a object, so why it's returning "FAIL". As you can see, I'm creating a new list using neu() method, then I'm using the same list to add elements. I think it's a silly bug that I don't see.
It seems I can't figure it out. Please any help would be appreciated.

Java Priority Queue in Linked List Test Cases

So I'm trying to implement a priority queue with a linked list. I think I have the basics together, but for some reason my test cases aren't working. When I run it, the size show up fine, but none of the node values are showing (only an arrow "->" pops up once). If anyone could help me figure out why it isn't working, or suggest a better way to set up test cases in java (I've never done that before) it would be appreciated!
Node class:
public class Node { //Node class structure
int data; //data contained in Node; for assignment purposes, data is an int
Node next; //pointer to Next Node
//Node Constructor
public Node(int data) {
this.data = data;
next = null;
}
//Set Methods
public void setData(int data) { //set Node value
this.data = data;
}
public void setNext(Node next) { //set next Node value
this.next = next;
}
//Get Methods
public int getData() { //get Node value
return this.data;
}
public Node getNext() { //get next Node value
return this.next;
}
//Display the Node Value
public void displayNode() {
System.out.println(data + "urgh"); //display value as a string
}
}
Linked List Class:
import Question1.Node;
//basic set-up of a FIFO singly linked list
public class SLList{
protected Node head; //head of SLList
protected Node tail; //tail of SLList
int n; //number of elements in SLList
//SLList constructor
public SLList() {
head = null;
n = 0;
}
//check if list is empty
public boolean isEmpty() {
return head == null;
}
//return the size of the list
public int size() {
return n;
}
//add a new node to the end of the list
public boolean insert(int x){
Node y = new Node(x);
if (head == null){ //if head is null, thus an empty list
head = y; //assign head as y
}
else{ //if there is already a tail node
tail.next = y; //assign the tail's pointer to the new node
}
tail = y; //assign tail to y
this.n++; //increment the queue's size
return true; //show action has taken place
}
//remove and return node from head of list
public Node remove(){
if (n == 0){ //if the list is of size 0, and thus empty
return null; //do nothing
}
else{ //if there are node(s) in the list
Node pointer = head; //assign pointer to the head
head = head.next; //reassign head as next node,
n--; //decrement list size
return pointer; //return the pointer
}
}
//display SLList as string
public void displayList() {
Node pointer = head;
while (pointer != null) {
pointer.displayNode();
pointer = pointer.next;
}
System.out.println(" ");
}
}
Priority Queue Class:
import Question1.Node;
import Question1.SLList;
public class PriorityQueue extends SLList {
private SLList list; //SLList variable
public PriorityQueue(){ //create the official SLList
list = new SLList();
}
//add a new node; new add method that ensures the first element is sorted to be the "priority"
public boolean add(int x){
Node y = new Node(x);
if (n == 0){ //if there are 0 elements, thus an empty list
head = y; //assign head as y
}
else if (y.data < head.data){ //if new node y is the smallest element, thus highest priority
y.next = head; //assign y's next to be current head of queue
head = y; //reassign head to be actual new head of queue (y)
}
else{ //if there is already a tail node
tail.next = y; //assign the tail's pointer to the new node
}
tail = y; //assign tail to y
n++; //increment the queue's size
return true; //show action has taken place
}
//delete the minimim value (highest priority value) from the queue and return its value
public Node deleteMin(){
return list.remove(); //the list is sorted such that the element being removed in indeed the min
}
//return the size of the queue
public int size() {
return n;
}
//display Queue as string
public void displayQueue() {
System.out.println("->");
list.displayList();
}
}
Test Cases (so far, the delete one wasn't working so it's commented out):
import Question1.PriorityQueue;
public class TestQ1 { //Test code
public static void main(String[] args){
PriorityQueue PQueue1 = new PriorityQueue();
PQueue1.add(3);
PQueue1.add(2);
PQueue1.add(8);
PQueue1.add(4);
System.out.println("Test add(x): ");
PQueue1.displayQueue();
System.out.println("Test size(): " + PQueue1.size());
PriorityQueue PQueue2 = new PriorityQueue();
//Node node1 = PQueue1.deleteMin();
System.out.println("Test deleteMin():");
PQueue2.displayQueue();
System.out.println("Test size(): " + PQueue2.size());
}
}
Change list.displayList() to displayList(), and you'll see the expected output.
Why? Because your queue is already a list (that is, an instance of SLList). When a class A extends another class B, an instance of A is also an instance of B. This is inheritance.
You've also included an instance variable private SLList list within your PriorityQueue implementation, which is an example of composition. Generally you'll only do one or the other of these two options, depending on your situation. In this case it seems you're trying to use inheritance, so there's no reason to create a separate list instance variable. You're adding the data directly to the queue (using the fact that, intrinsically, it is a list in its own right).
You should remove the list instance variable, and all the usages of it should refer to the parent class' methods or variables.

Creating push and pop methods within a user defined LinkedList

Recently, my class has been studying ArrayLists and LinkedLists. This past week we received an assignment that asked us to create push and pop methods within our LinkedList stack class. I understand the logic behind stacks such that it's last-in-first-out, but I am having trouble with the actual code. I am fairly new to computer science (this being my second course ever) and this particular assignment is literally causing me to pull my hair out. I already turned this assignment in, but we have a midterm next week and I would like to do well on it. I have been all over the web and my textbook looking for help, but nothing. My professor only refers me to the TA and the TA is only concerned with helping me with the logic, not the actual code. I'll post the instructions my professor gave me below, as well as my code so far. Thanks in advance.
From the professor:
Implement stacks using the template given in the following Java
files:
CS401StackInterface.java CS401StackLinkedListImpl.java
public interface CS401StackInterface<E>
{
/**
* Get the top element on the stack.
*
* #return the first element on the stack.
*/
public E pop();
/**
* Adds an element on the top of the stack.
*
* #param e - The element to be added to the stack.
*/
public void push(E e);
/**
* Determines the number of elements in this data structure.
*
* #return the number of elements currently resident in this
* data structure.
*/
public int size();
}
Here is the actual class where I attempt to define my methods:
public class CS401StackLinkedListImpl<E> implements CS401StackInterface<E>
{
private LinkEntry<E> head;
private int num_elements;
public CS401StackLinkedListImpl()
{
head = null;
num_elements = 0;
}
public void setElement(LinkEntry<E> anElement){
head = anElement;
}
/*Append the new element to the end of the list*/
public void push(E e)
{
LinkEntry<E> temp = new LinkEntry<E>();
temp.element = e;
temp.next = head;
head = temp;
}
/*Remove the most recently pushed element at the end of the list*/
public E pop()
{
head.next = head;
num_elements--;
return (E) head;
}
public int size()
{
LinkEntry<E> temp = new LinkEntry<E>();
for (temp = head; head != null; head = head.next)
num_elements++;
return num_elements;
}
public String toString()
{
String string = "";
LinkEntry<E> temp = new LinkEntry<E>();
for (temp = head; temp != null; temp = temp.next)
{
string += temp.element.toString() + "";
}
return string;
}
/* ------------------------------------------------------------------- */
/* Inner classes */
protected class LinkEntry<E>
{
protected E element;
protected LinkEntry<E> next;
protected LinkEntry() { element = null; next = null; }
}
}
Finally, here is my main class where I test my methods:
import java.util.*;
public class App {
public static <E> void main(String[] args) {
CS401StackLinkedListImpl<String> my_stack = new CS401StackLinkedListImpl<String>();
my_stack.push("Brian");
my_stack.push("Chris");
my_stack.push("Joe");
System.out.println("Stack size: " + my_stack.size());
my_stack.pop();
System.out.println("Stack size: " + my_stack.size());
my_stack.toString();
}
}
When I run my main class this is what it returns:
Stack size: 3
Exception in thread "main" java.lang.NullPointerException
at week6.CS401StackLinkedListImpl.pop(CS401StackLinkedListImpl.java:30)
at week6.App.main(App.java:66)
Everything I've come across just tells me to create a new Stack, which is easy because then I don't have to worry about the "innards" of the code, but that's not what I need. Thanks.
The problem is with your size method. It corrupts the value of head so that it is null. Then your call to pop gets an NPE.
You also have a problem with variable initialization - num_elements will just increase on every call to size. You can simplify this by increasing the variable on calls to push.
Also your setElement will corrupt your stack, if used, because it just sets head, without patching up the next pointers.
Sorry, I see that this is turned in homework... so here are some concrete ways to correct the code:
public CS401StackLinkedListImpl()
{
head = null;
num_elements = 0;
}
public void setElement(LinkEntry<E> anElement)
{
if (head != null)
anElement.next = head.next; //New top-of-stack needs to point to next element, if any
else
anElement.next = null;
head = anElement;
}
/*Append the new element to the end of the list*/
public void push(E e)
{
LinkEntry<E> temp = new LinkEntry<E>();
temp.element = e;
temp.next = head;
head = temp;
num_elements++; // Increase number of elements count here
}
/*Remove the most recently pushed element at the end of the list*/
public E pop()
{
E result = head.element; // Save return value of TOS
head = head.next; // Corrected POP action
num_elements--;
return result;
}
public int size()
{
//Remove below since count is kept accurate with push/pop methods
//LinkEntry<E> temp = new LinkEntry<E>();
//for (temp = head; head != null; head = head.next)
// num_elements++;
return num_elements;
}
You might want to add an addition check in pop to throw a better exception than NPE if there are no elements, such as:
if (head == null)
throw new StackUnderflowException(); // and define a StackUnderflowException; or use a standard exception with a message
public void push(E e)
It seems ok.
public E pop()
It doensn't seem ok: you assign to the head.next element itself, this creates a loop. Then you return the actual head. You should first save current head somewhere, then update head reference to the next element and return the previous head.
public int size()
Method is wrong: first of all you instantiate a useless element to temp but you don't need it (since you will use the temp inside the loop and you should initialize it to the current head. Then check your for loop: you are using head either in the stop condition either in the end of loop iteration. You should never use head, since you are just iterating on the list and not modifying it, but just temp (check your toString code which appears to be correct).
looking at the code, it appears your Pop method is backwards.
In your push method, you assign the current head element to the 'next' attribute of the new LinkEntry, and then make that the new head. Therefor, when you pop the item off the list, you need to assign the 'next' element back to the head of the list. so your code, which is:
head.next = head;
should be:
LinkEntry<E> toReturn = head;
head = head.next;
return toReturn.element;
In effect, you are cloning the head reference to the current item at the top of the stack (so you can return it), then moving the head reference to point to the next item in the stack
/*Append the new element to the end of the list*/
public void push(E e)
{
LinkEntry<E> temp = new LinkEntry<E>();
temp.element = e;
temp.next = head;
num_elements++;//Increment count<--- Correction
head = temp;
}
/*Remove the most recently pushed element at the end of the list*/
public E pop()
{
E returnValue =head.element ;<--- Correction
head=head.next;<--- Correction
num_elements--;//Decrement count
return returnValue;
}
public int size()
{
return num_elements;<--- Correction
}

Categories

Resources