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
}
Related
I'm having a bit of an issue with implementing my circularly linked list. I'm working on a problem that requires you to implement any ADT yourself. I seem to be okay with adding nodes to the list, however I'm in unfamiliar territory when it comes to removing. I included the first two remove methods to give you an idea of where my head is at, how would I go about removing the last node in the list?
public class LinkedList {
private Node head;
private Node tail;
private int size = 0;
LinkedList() {
head = null;
current = null;
previous = null;
tail = null;
size = 0;
}
//checks if list is empty
public boolean isEmpty() {
return head == null;
}
//add new node to front of circularly linked list
public void addToFront(E x) {
if (head == null) {
head = new Node(x);
} else {
Node n = new Node(x);
x.next() = head;
head = x;
}
}
public void addtoMiddle(E x) {
x.next = current.next();
current.next = x;
size = size + 1;
}
public void addToEnd(E x) {
x.next = null;
tail.next() = x;
tail = x;
size = size + 1;
}
public void removeFirst(E x) {
if (head = null) {
System.out.println("Error! List is empty!");
} else {
head = current.next();
size = size + 1;
}
}
public void removeMiddle(E x) {
previous.next() = current.next();
current.next() = null;
size = size + 1;
}
In a circular linked list the last node's next points to the head, so you loop through your nodes until node.next.equals( head ). Note that next must never be null and if you have only one node then you have head.next = head.
In a circular doubly linked list you also have a previous node, i.e. you can iterate backwards. In that case your last node is just head.previous.
A small ascii picture:
head -next---> node -next---> node -next---> last
| ^ <---prev- <---prev- <---prev- | ^
| | | |
| |_____________________________________next_| |
|_prev_________________________________________|
I know this is not directly an answer to your question but I feel like Thomas has given the needed explanation here.
Since you have a lot of syntax or incompleteness errors in the example
I would recommend to comment out all functions so it has no more errors. Then comment them in again one by one correcting every error.
Some advices:
You use class members which are not defined e.g. current, previous.
Decide if next should be a member or function.
You need to define a class for Node (containing its members and functions), like you did for LinkedList.
I'm creating a Stack Data Structure and am implementing it using a Linked List. I am using 3 java files - stack.java, stacktest.java and linkedList.java. The linked list works fine when I test it but the stack test is giving me the following errors
Is Empty?: true
Is Empty?: false
Exception in thread "main" java.lang.NullPointerException
at Stack.Peek(Stack.java:56)
at StackTest.main(StackTest.java:12)
Here is my stack.java file
import java.util.EmptyStackException;
public class Stack{
linkedList list;
int count;
public Stack()
{
list = new linkedList();
count = 0;
}
/**
* Adds a node to the head of the list
* #param c character to add
*/
public void Push(char c)
{
if(list.isEmpty())
{// If the list is empty
list.addFirst(c); // Add first
count++;
}
else
{
list.addAtEnd(c); // To the end (tail acts as head)
count++;
}
}
/**
* Removes a node from the head of the list
* #return char removed node
*/
public char Pop() throws EmptyStackException
{
if (!isEmpty())
{
return list.removeLast();
}
else
{
throw new EmptyStackException();
}
}
/**
* Returns the char from the head of the list
* #return char from top of the list
*/
public char Peek() throws EmptyStackException
{
if (!isEmpty())
{
return list.getTail().ch;
}
else
{
throw new EmptyStackException();
}
}
/**
* Is the list empty?
* #return true=yes false=no
*/
public boolean isEmpty()
{
return list.isEmpty();
}
/**
* Counts number of nodes within the list
* #return int # nodes in list
*/
public int getCount()
{
int counter = 0;
Node temp = list.getHead(); // Get head pointer.
while(temp.next != null) // Iterate until tail is reached.
counter++; // Increment counter on each node
return counter;
}
public void printStack()
{
list.printList();
}
}
My stacktest.java
import java.io.IOException;
public class StackTest {
public static void main(String args[]) throws IOException
{
Stack stackList = new Stack();
System.out.println("Is Empty?: " + stackList.isEmpty());
stackList.Push('A');
System.out.println("Is Empty?: " + stackList.isEmpty());
stackList.Pop();
stackList.Peek();
stackList.isEmpty();
stackList.getCount();
stackList.printStack();
}
}
And my linkedList.java
class Node
{
protected char ch;
protected Node next;
protected Node previous;
/**
* Construct a node with the given character value
* #param c - The character
*/
public Node (char c)
{
this.ch = c;
this.next = null;
this.previous = null;
}
}
public class linkedList
{ /** A reference to the head of the list */
protected Node head;
protected Node tail;
/**
* Construct a new empty list
*/
public linkedList()
{
head=null;
tail=null;
}
public Node getHead()
{
return head;
}
public Node getTail()
{
return tail;
}
/**
*Set c as first node in the list
*#param c The character to be inserted
*/
public void addFirst(char c)
{
Node newNode = new Node(c);
head=newNode; // Adding new element.
tail=newNode; // Head and tail will be the same.
}
/**
*Add a character to the end of the list
*#param c The character to be inserted
*/
public void addAtEnd(char c)
{
Node nod = new Node(c);
Node temp = head;
while (temp.next != null) // cycle until at end of list.
temp = temp.next;
temp.next=nod; // last element is new node.
nod.previous=temp; // linking last node with rest of list.
tail=nod; // new node is the tail.
}
/**
*Add a character in alphabetical order into the list
*#param c The character to be inserted
*/
public void addInOrder(char c)
{
Node n= new Node(c);
if(isEmpty())
{
addFirst(c);
}
else
{
Node pre=head;
Node succ= head.next;
if (n.ch < pre.ch)
{
n.next =head;// join node n to the list at the head.
head = n;// head is reading from n.
}
else
{
while(succ!=null && n.ch > succ.ch)
{ // find the position to insert the node
pre = succ;
succ = pre.next;
} //rearrange pointers
n.next = succ;
pre.next = n;
}
}
}
/**
*Test to see if this list is empty
*#returns true or false
*/
public boolean isEmpty()
{
return (head == null && tail == null);
}
/**
*removes a node from the head of the list
*#returns c The character from the removed node
*/
public char removeFirst()
{
if(!isEmpty())
{
// a temporary pointer to enable return of the char being removed
Node temp = head;
head = head.next; // move head pointer along the list
return temp.ch;
}
else
{
System.out.println("List is empty");
return '?'; //to indicate that the list is empty
}
}
/**
* removes a node from the tail of the list
* #return c The character from the removed node
*/
public char removeLast()
{
Node t = getTail(); // Retrieve tail
tail = t.previous; // Set tail to previous node
return t.ch; // return character
}
/**
*prints the characters in the list
*/
public void printList()
{
Node temp=head;
while(temp!=tail.next)
{
System.out.print(temp.ch + " ");
temp=temp.next;
}
System.out.println(); // After print, goes to new line.
}
}
I understand that I am using a variable which is null but can someone explain to me where I am going wrong
When you call addFirst(), it sets both the head and the tail to the new node. However, when you removeLast(), it only changes tail to null and leaves head set to the node you popped.
Then, when you call isEmpty(), since head is not null, it doesn't recognize that the list is empty and returns false.
You need to modify removeLast() to check whether you're removing the only element in the list, and update the head accordingly.
Once you have popped out your only element of the stack, the inner list is empty. Therefore list.getTail() will return null, and you cannot peek into your stack anymore.
In StackTest.java you are inserting one element into the stack, then popping it and then trying to peek into the stack. Your pop function is using removeLast method of linkedList.java. While you are correctly pointing the tail to tail.previous, you need to also check if the result of this leads to tail becoming null (which means you have removed the last element in your linked list). You should check for this in removeLast and make head = tail if this is the case:
public char removeLast()
{
Node t = getTail(); // Retrieve tail
tail = t.previous; // Set tail to previous node
if(tail == null){
head = tail;
}
return t.ch; // return character
}
This way isEmpty() method will always return true if you have popped out the last element in the list. You will have to make a similar change to removeFirst() as follows:
public char removeFirst()
{
if(!isEmpty())
{
// a temporary pointer to enable return of the char being removed
Node temp = head;
head = head.next; // move head pointer along the list
if(head == null){
tail = head;
}
return temp.ch;
}
else
{
System.out.println("List is empty");
return '?'; //to indicate that the list is empty
}
}
After this change your peek() method will now throw an EmptyStackException (which is desirable) instead of a NPE when you try to peek into an empty stack.
Might I also suggest that you don't need to traverse the whole list to add at the end of the list (on addAtEnd()). Since you already have the tail you can just append to the end of the tail pointer.
This question is unlikely to help any future visitors; it is only relevant to a small geographic area, a specific moment in time, or an extraordinarily narrow situation that is not generally applicable to the worldwide audience of the internet. For help making this question more broadly applicable, visit the help center.
Closed 10 years ago.
I'm studying for an exam I have next week and I was hoping somebody could help me out when it comes to adding and removing elements from a doubly linked list. The logic makes sense to me, unfortunately I am not that great at coding yet (only my second computer science course). I have looked all over the web and in my text as well, but I can't seem to find an example close enough to my problem. Below I will post what my professor is asking me to accomplish, as well as my current code. Thank you in advance for any help.
UPDATE
I was having issues with adding as well, but somebody was able to help me out, however I'm still having issues with my remove method. I find it odd that my professor has a remove method with a return type other than void. Can somebody explain this? Anyways, my updated code is below.
From the professor:
Fill in the missing code in CS401DblLinkedListImpl.java as
indicated in the class lecture.
To test your code, create a doubly linked list and enter the
following elements of type String in it:
Bill, Rohan, James, Krishna, Javier, Lisa
(a) Print the linked list starting at the beginning.
(b) Print the linked list starting at the end.
(c) Remove Bill and print the linked list starting from beginning.
(d) Remove Lisa and print the linked list starting from end.
(e) Remove Krishna and print the linked list starting from the
beginning.
This following set of code is my user defined class and the methods I will be testing are boolean add(E e), E remove(int n), void print_from_beginning(), and void print_from_end():
package week6;
import java.util.Iterator;
public class CS401DblLinkedListImpl<E> //implements CS401CollectionInterface<E>
{
private LinkEntry<E> head = null;
private LinkEntry<E> tail = null;
private int size = 0;
public CS401DblLinkedListImpl()
{
head = tail = null;
}
public boolean is_empty()
{
if (head == null)
return true;
return false;
}
public int size()
{
int count = 0;
for (LinkEntry<E> current = head; current != null; current = current.next)
count++;
return count;
}
/*
* Add e to the end of the doubly linked list.
* Returns true - if e was successfully added, false otherwise.
*/
public boolean add(E e)
{
LinkEntry<E> new_element = new LinkEntry<E>();
new_element.element = e;
if (head == null)
{
new_element.next = head;
head = new_element;
tail = head;
}
else
{
tail.next = new_element;
new_element.previous = tail;
tail = new_element;
}
return true;
}
/*
* Remove the nth element in the list. The first element is element 1.
* Return the removed element to the caller.
*/
public E remove(int n)
{
LinkEntry<E> current = new LinkEntry<E>();
int i = 0;
while (n == i++)
{
current.previous.next = current.next;
if (current.next == null)
{
current.next.previous = current.previous;
}
}
return (E) current;
}
/*
* Print the doubly linked list starting at the beginning.
*/
public void print_from_beginning()
{
LinkEntry<E> current = new LinkEntry<E>();
for (current = head; current != null; current = current.next)
{
System.out.print(current.element + " ");
}
}
/*
* Print the doubly linked list starting the end.
*/
public void print_from_end()
{
LinkEntry<E> current = new LinkEntry<E>();
for (current = tail; current != null; current = current.previous)
{
System.out.print(current.element + " ");
}
}
/* ------------------------------------------------------------------- */
/* Inner classes */
protected class LinkEntry<E>
{
protected E element;
protected LinkEntry<E> next;
protected LinkEntry<E> previous;
protected LinkEntry() { element = null; next = previous = null; }
}
/* ------------------------------------------------------------------- */
protected class CS401DblLinkedListImplIterate<E> implements Iterator<E>
{
protected LinkEntry<E> next;
protected CS401DblLinkedListImplIterate()
{
next = (LinkEntry<E>) head;
}
#Override
public boolean hasNext() {
// TODO Auto-generated method stub
return false;
}
#Override
public E next() {
// TODO Auto-generated method stub
return null;
}
#Override
public void remove() {
// TODO Auto-generated method stub
}
}
} /* CS401LinkedListImpl<E> */
Below is my main class where I test the methods:
package week6;
import java.util.*;
public class App {
public static <E> void main(String[] args) {
/*
* Part 1 of lab 6: Testing CS401DblLinkedListImpl
*/
System.out.println("Testing Lab 6: Part 1...");
CS401DblLinkedListImpl<String> list = new CS401DblLinkedListImpl<String>();
list.add("Bill");
list.add("Rohan");
list.add("James");
list.add("Krishna");
list.add("Javier");
list.add("Lisa");
System.out.println("List size after all names are added: " + list.size());
//a. Print the linked list starting at the beginning.
System.out.println("\nPrint the linked list starting at the beginning:");
list.print_from_beginning();
//b. Print the linked list starting at the end.
System.out.println("\nPrint the linked list starting at the end:");
list.print_from_end();
//c. Remove Bill and print the linked list starting from beginning.
System.out.println("\nRemove Bill and print the linked list starting from beginning:");
list.remove(0);
list.print_from_beginning();
//d. Remove Lisa and print the linked list starting from end.
System.out.println("\nRemove Lisa and print the linked list starting from end:");
list.remove(4);
list.print_from_end();
//e. Remove Krishna and print the linked list starting from the beginning.
System.out.println("\nRemove Krishna and print the linked list starting from the beginning:");
list.remove(2);
list.print_from_beginning();
System.out.println("\nList size: " + list.size());
}
}
Finally, below is what I get when I run my program:
Testing Lab 6: Part 1...
List size after all names are added: 6
Print the linked list starting at the beginning:
Bill Rohan James Krishna Javier Lisa
Print the linked list starting at the end:
Lisa Javier Krishna James Rohan Bill
Remove Bill and print the linked list starting from beginning:
Exception in thread "main" java.lang.NullPointerException
at week6.CS401DblLinkedListImpl.remove(CS401DblLinkedListImpl.java:67)
at week6.App.main(App.java:34)
FYI, CS401DblLinkedListImpl.java:67 refers to the following line of code in my remove method:
current.previous.next = current.next;
Any help on this would be much appreciated. I feel like I'm somewhat close to the answer, it just needs some clarifying. Thanks.
Your current code will not handle removing index 0.
LinkEntry<E> current = head;
if (n == 0) {
// something like this maybe...
head = head.next;
if (head != null) { head.previous = null; }
return current;
}
You start with i = 0 but do an i++ so you're at head, but with an index of 1.
Also your remove logic looks odd to me.
current.previous.next == current (is true)
current.next.previous == current (is true)
so it should be something like:
if (n == i++) {
// We're at the spot so let's remove it.
current.previous.next = current.next;
if (current.next != null) { current.next.previous = current.previous; }
return current;
}
Also I believe you add logic is wrong too, should be like.
LinkEntry<E> new_element = new LinkEntry<E>();
new_element.element = e;
if (head == null) {
head = new_element;
tail = head;
} else {
tail.next = new_element;
new_element.previous = tail;
tail = new_element;
}
size++; // You don't use size it looks like... and your size starts at 1 which is
// wrong, it should start at 0 since it's empty, also remove would have to
// update size.
return true;
My assigment is to create my own linked list class (I can't use Java's LinkedList class) and implement a selection sort on it by swapping pointers rather than data.
I've created a double-linked MyLinkedList class, but I'm having trouble with the sort method. I've tried a number of things but nothing has worked - not even anything that would make sense to post here for correction. (I do know that I need to use at least one temp Node.) It has to be a selection sort.
I'm not looking for someone to code it for me, necessarily; I'm hoping someone can help me with an algorithm that I can then turn into code myself. Any help is appreciated greatly.
Here's how I've implemented the MyLinkedList class and the associated Node class:
public class MyLinkedList
{
private Node head;
private int count;
public MyLinkedList()
{
head = new Node(null);
count = 0;
}
public void add(String line)
{
Node temp = new Node(line);
Node current = head;
while (current.getNext() != null)
{
current = current.getNext();
}
temp.setLine (line); // not sure this is how to do it
current.setNext(temp);
temp.setPrev(current);
count++;
}
public void displayList()
{
Node current = head;
for (int i = 0; i < count; i++)
{
current = current.getNext();
System.out.println(current.getLine());
}
}
public void sortList()
{
Node start = head;
Node index = start;
Node min = start;
Node temp1, temp2;
while (start.getNext() != null)
{
index = index.getNext();
if (index.getLine().compareTo(min.getLine()) < 0)
{
min = index;
}
//swap - HELP, PLEASE :-)
{
// Algorithm???
}
}
}
public int size()
{
return count;
}
private class Node
{
String textLine;
Node next;
Node prev;
public Node()
{
textLine = null;
next = null;
prev = null;
}
public Node (String line)
{
textLine = (line);
next = null;
prev = null;
}
public Node (String line, Node node1, Node node2)
{
textLine = line;
prev = node1;
next = node2;
}
public String getLine()
{
return textLine;
}
public Node getNext()
{
return next;
}
public Node getPrev()
{
return prev;
}
public void setLine(String line)
{
textLine = line;
}
public void setNext(Node nextNode)
{
next = nextNode;
}
public void setPrev(Node prevNode)
{
prev = prevNode;
}
}
}
It may get confusing if an empty MyLinked List has a node in it even if it's just one with null prev, next and data, so you need to be careful of that MyLinkedList constructor - it would probably be much easier if it read simply head = null;.
Also it would be useful if a MyLinked List had a tail node as well to save you following the chain to the end to find where add should put a new Node.
After that, I think the problem is that you haven't noticed you need two loops: one to work your way through the list to keep track of where the unsorted nodes start, and one to find the smallest node from thereon. You also need to write a swap method for Node so that you can write something like this untested pseudocode that just happens to look a lot like Java
for (index = head; index != null; index = index.getNext()) {
min = index;
for (test = min.getNext(); test != null; test = test.getNext) {
if (test.getLine().compareTo(min.getLine()) < 0)
min = test;
}
if (min != index) {
swap(index, min);
index = min;
}
}
and swap would look roughly like
public void swap(Node other)
{
Node temp;
temp = next;
next = other.getNext();
other.setNext(temp);
temp = prev;
prev = other.getPrev();
other.setPrev(temp);
other.getNext().setPrev(this);
other.getPrev().setNext(this);
this.getNext().setPrev(other);
this.getPrev().setNext(other);
}
Note again this is completely untested and hasn't even seen a compiler.
Make sure to think about special cases like when the list is empty or has only one element in it, and when there is only one node left unsorted in the list.
I couldn't leave this without pointing out that swap is actually a lot more complex than that. I've added a few lines to correct the pointers in the nodes before and after the nodes to be swapped. You also need to consider:
Whether either of the nodes that are swapped are at the end of the list, in which case the head (and tail if you have one) of the list will need to be updated instead of the pointers in the adjacent nodes. That's fairly obvious.
Whether the nodes to be swapped are next to each other in the list, when if you apply the normal algorithm you get nodes pointing to themselves. That's less obvious.
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.