I am currently working on my own Java class called LString, which is meant to convert back and forth between linked lists of characters and Strings.
I am having issues with my toString() method, specifically keeping track of the "head" of the linked list in order to loop through it and concatenate the characters into a new string. While researching, I read that I am supposed to keep track of the head of the list somehow, but I can't figure out how to implement it.
Any help would be greatly appreciated!
Edit: The error message I am receiving is:
LString.java:79: error: cannot find symbol
ListNode current = this.front;
public class LString{
private static int length;
// ListNode constructors
// Creates a new ListNode with characters stored in variable "data" and
// Node named next
private class ListNode{
char item;
ListNode next;
private ListNode(){
}
// creates a new ListNode that has the value and links to the specified ListNode
private ListNode(char item, ListNode next){
this.item = item;
this.next = next;
}
// given a character, creates a new ListNode that doesn't link to anything
private ListNode(char item){
this.item = item;
this.next = null;
}
}
public LString(){
this.length = 0;
ListNode front = new ListNode();
}
//LString
// Takes in a String object and loops until it has added all characters to a new linked list
public LString(String original){
ListNode front;
this.length = 1; // length keeps track of number of nodes
if (original.charAt(0) == 0){ // creates a new ListNode if it is an empty string
front = new ListNode();
}
else {
front = new ListNode(original.charAt(0));
}
//System.out.println("this is happening " + front.item);
//ListNode current = front;
for (int index = 1; index < original.length(); index++) {
front.next = new ListNode(original.charAt(index), front.next);
front = front.next;
//System.out.println("strings: " + front.item);
length++;
}
//System.out.println("length: " + length);
}
// returns length of the LString object
public int length(){
return this.length;
}
// toString takes an LString object and converts it to a string
public String toString(){
StringBuilder newString;
ListNode current = this.front;
while (current.next != null){
newString.append(current.item);
current = current.next;
}
return newString.toString();
}
public static void main(String[] args){
LString stuffTest = new LString("hello");
int valueOf = stuffTest.length();
System.out.println(stuffTest.length());
String testMeWhy = stuffTest.toString();
}
}
The general pattern for building a linked list by appending to the end is:
At the beginning:
head = null;
tail = null;
To append newNode to the list:
if (head == null) {
head = newNode;
} else {
tail.next = newNode;
}
tail = newNode;
I think you're trying to do this by keeping just one pointer in the list class, which doesn't work very well. Also, doing things using this pattern means you don't have to have a "special" node at the front of the list, unless there's some other good reason to. It looks like you were trying to use new ListNode() with no arguments to create some kind of special node, but only sometimes. It's unnecessary and just makes things more complicated.
Your basic problem is that there should be only one front, and it should be a class member and not a local variable. That is how your LString class "keeps track" of the first node.
public class LString {
private ListNode front = null;
private int size = 0;
...
This will get you started and allow you to maintain the actual list. Your other LString methods will also need some work, but once you get past this problem you should be able to use your debugger to step through the code and solve the remaining issues yourself.
Related
I am creating a program that will read in a file, organize all of the words in lexicographic order, and output the word, how many times it appears in the document, and on what lines it appears. I have implemented this code in four different class files. However, I am having trouble linking the words to the linked list that will show the line numbers that the linked list arrives in. I am supposed to use the nodes of front and rear to traverse the list and am unsure how to go about iterating through this list and printing out each word.
here is the code form the class that take strings and make a linked list:
private class Node
implements Entry<String, IntQueue> {
String key;
IntQueue queue = new IntQueue();
Node link;
Node(String keyword, Node newlink) {
key = keyword;
link = newlink;
}
public String getKey() {
return key;
}
public IntQueue getValue() {
return queue;
}
public IntQueue setValue(IntQueue queue) {
throw new UnsupportedOperationException();
}
}
private Node head = new Node("", null);
public ListMap() {
// Not needed, since head defaults to null anyway.
}
public void insert(String key, int linenr) {
misc.trace("insert", key, linenr);
Node prevcursor = head;
Node cursor = head.link;
boolean write = false;
while (cursor != null) {
if (key.compareTo(cursor.getKey()) < 0) {
prevcursor.link = new Node(key, prevcursor.link);
prevcursor.link.getValue().insert(linenr);
write = true;
break;
}
if (key.compareTo(cursor.getKey()) == 0) {
cursor.queue.insert(linenr);
write = true;
break;
}
prevcursor = prevcursor.link;
cursor = cursor.link;
}
if (!write) {
prevcursor.link = new Node(key, prevcursor.link);
prevcursor.link.getValue().insert(linenr);
}
}
and here is the code that acually makes the int linked list:
class IntQueue
implements Iterable<Integer> {
private class node {
int linenr;
node link;
node(int number, node newlink) {
linenr = number;
link = newlink;
}
}
private int count = 0;
private node rear = null;
private node front = new node(0, null);
private int linenumb = 0;
private int count = 0;
private node rear = null;
private node front = null;
private int linenumb= 0;
public void insert (int number) {
++count;
misc.trace (count);
if(front=null){
node temp = new node(number,rear.link);
front = temp;
rear = temp;
}else{
if(linenumb != number ){
rear.link= new node(number,null);
}
}
linenumb = number;
rear = rear.link;
}
the big problem is the insert function in the second class. I can't understand how to link front and rear and to consistently add a new node every time the function is called in a way that can be called later
If your first issue is how to write the insert method for IntQueue then here are some suggestions. I'm assuming you don't want the code written as this looks like it's likely to be an assignment.
You are creating a new node as the front when the list is constructed. This is likely to be a mistake. The list is initially empty which is generally represented as front and rear being null.
The first thing to do in insert is to check if front is null. If it is you just set front and rear to a new node.
After that you know that rear will point to the most recently inserted node so you only need to check the new int to insert against rear.lineNumber.
Assuming you need a new node, create it, make rear.link point to it and then make rear point to it.
You're done.
As your assignment is a linked list with each node including a linked list I would expect your classes to be defined something like:
class WordList {
private class Node {
private String word;
private int count;
private LineNumberList lineNumbers;
private Node next;
}
private Node head;
private Node tail;
public addWord(String word, int lineNumber) {
...
}
}
class LineNumberList {
private class Node {
private int lineNumber;
private Node next;
}
private Node head;
private Node tail;
public addLineNumber(int lineNumber) {
...
}
}
Both addWord and addLineNumber should follow the same pattern as my algorithm above. However addWord will need to start by looking for the word and inserting it with a count of 1 if it's not present or incrementing the count if it is.
I've been working through some standard coding interview questions from a book I recently bought, and I came across the following question and answer:
Implement an algorithm to find the nth to last element in a linked list.
Here's the provided answer:
public static LinkedListNode findNtoLast(LinkedListNode head, int n) { //changing LinkedListNode to ListNode<String>
if(head == null || n < 1) {
return null;
}
LinkedListNode p1 = head;
LinkedListNode p2 = head;
for(int j = 0; j < n-1; ++j) {
if(p2 == null) {
return null;
}
p2 = p2.next;
}
if(p2 == null) {
return null;
}
while(p2.next != null) {
p1 = p1.next;
p2 = p2.next;
}
return p1;
}
I understand the algorithm, how it works, and why the book lists this as its answer, but I'm confused about how to access the LinkedListNodes to send as an argument to the method. I know that I'd have to create a LinkedListNode class (since Java doesn't already have one), but I can't seem to figure out how to do that. It's frustrating because I feel like I should know how to do this. Here's something that I've been working on. I'd greatly appreciate any clarification. You can expand/comment on my code or offer your own alternatives. Thanks.
class ListNode<E> {
ListNode<E> next;
E data;
public ListNode(E value) {
data = value;
next = null;
}
public ListNode(E value, ListNode<E> n) {
data = value;
next = n;
}
public void setNext(ListNode<E> n) {
next = n;
}
}
public class MyLinkedList<E> extends LinkedList {
LinkedList<ListNode<E>> list;
ListNode<E> head;
ListNode<E> tail;
ListNode<E> current;
ListNode<E> prev;
public MyLinkedList() {
list = null;
head = null;
tail = null;
current = null;
prev = null;
}
public MyLinkedList(LinkedList<E> paramList) {
list = (LinkedList<ListNode<E>>) paramList; //or maybe create a loop assigning each ListNode a value and next ptr
head = list.getFirst();
tail = list.getLast(); //will need to update tail every time add new node
current = null;
prev = null;
}
public void addNode(E value) {
super.add(value);
//ListNode<E> temp = tail;
current = new ListNode<E>(value);
tail.setNext(current);
tail = current;
}
public LinkedList<ListNode<E>> getList() {
return list;
}
public ListNode<E> getHead() {
return head;
}
public ListNode<E> getTail() {
return tail;
}
public ListNode<E> getCurrent() {
return current;
}
public ListNode<E> getPrev() {
return prev;
}
}
How can the LinkedListNode head from a LinkedList?
Update: I think part of my confusion comes from what to put in the main method. Do I need to create a LinkedList of ListNode? If I do that, how would I connect the ListNodes to each other? How would I connect them without using a LinkedList collection object? If someone could show me how they would code the main method, I think that would put things into enough perspective for me to solve my issues. Here's my latest attempt at the main method:
public static void main(String args[]) {
LinkedList<ListNode<String>> list = new LinkedList<ListNode<String>>();
//MyLinkedList<ListNode<String>> list = new MyLinkedList(linkedList);
list.add(new ListNode<String>("Jeff"));
list.add(new ListNode<String>("Brian"));
list.add(new ListNode<String>("Negin"));
list.add(new ListNode<String>("Alex"));
list.add(new ListNode<String>("Alaina"));
int n = 3;
//ListIterator<String> itr1 = list.listIterator();
//ListIterator<String> itr2 = list.listIterator();
LinkedListNode<String> head = new LinkedListNode(list.getFirst(), null);
//String result = findNtoLast(itr1, itr2, n);
//System.out.println("The " + n + "th to the last value: " + result);
//LinkedListNode<String> nth = findNtoLast(list.getFirst(), n);
ListNode<String> nth = findNtoLast(list.getFirst(), n);
System.out.println("The " + n + "th to the last value: " + nth);
}
In an attempt to connect the nodes without using a custom linked list class, I have edited my ListNode class to the following:
class ListNode<E> {
ListNode<E> next;
ListNode<E> prev; //only used for linking nodes in singly linked list
ListNode<E> current; //also only used for linking nodes in singly linked list
E data;
private static int size = 0;
public ListNode() {
data = null;
next = null;
current = null;
if(size > 0) { //changed from prev != null because no code to make prev not null
prev.setNext(this);
}
size++;
}
public ListNode(E value) {
data = value;
next = null;
current = this;
System.out.println("current is " + current);
if(size > 0) {
prev.setNext(current);//this line causing npe
}
else
{
prev = current;
System.out.println("prev now set to " + prev);
}
size++;
System.out.println("after constructor, size is " + size);
}
public ListNode(E value, ListNode<E> n) {
data = value;
next = n;
current = this;
if(size > 0) {
prev.setNext(this);
}
size++;
}
public void setNext(ListNode<E> n) {
next = n;
}
}
As is right now, the program will run until it reaches prev.setNext(current); in the single argument constructor for ListNode. Neither current nor prev are null at the time this line is reached. Any advice would be greatly appreciated. Thanks.
You don't actually need a separate LinkedList class; the ListNode class is a linked list. Or, to state it differently, a reference to the head of the list is a reference to the list.
The use of head, tail, current, prev in the sample code you posted has come from a double-linked list which is a data type that has links in both directions. This is more efficient for certain types of applications (such as finding the nth last item).
So I would recommend renaming your ListNode class to LinkedList and renaming next to tail.
To add a new item to the list you need a method that creates a new list with the new item at it's head. Here is an example:
class LinkedList<E> {
...
private LinkedList(E value, LinkedList<E> tail) {
this.data = value;
this.tail = tail;
}
public LinkedList<E> prependItem(E item) {
return new LinkedList(item, this);
}
}
Then to add a new item i to list you use list = list.prependItem(i);
If for some reason you need to always add the items to the end, then:
private LinkedList(E value) {
this.data = value;
this.tail = null;
}
public void appendItem(E item) {
LinkedList<E> list = this;
while (list.tail != null)
list = list.tail;
list.tail = new LinkedList<>(item);
}
However this is obviously pretty inefficient for long lists. If you need to do this then either use a different data structure or just reverse the list when you have finished adding to it.
Incidentally, an interesting side effect of this is that a reference to any item in the list is a reference to a linked list. This makes recursion very easy. For example, here's a recursive solution for finding the length of a list:
public int getLength(LinkedList list) {
if (list == null) {
return 0;
} else {
return 1 + getLength(list.getTail());
}
}
And using this a simple (but very inefficient!) solution to the problem you provided - I've renamed the method to make its function more obvious:
public LinkedList getTailOfListOfLengthN(LinkedList list, int n) {
int length = getLength(list);
if (length < n) {
return null;
} else if (length == n) {
return list;
} else {
return getTailOfLengthN(list.getTail(), n);
}
}
And to reverse the list:
public LinkedList<E> reverse() {
if (tail == null) {
return this;
} else {
LinkedList<E> list = reverse(tail);
tail.tail = this;
tail = null;
return list;
}
}
As I hope you can see this makes the methods a lot more elegant than separating the node list classes.
Actually you have created a linked list with you class ListNode.
A linked list is made of a node and a reference to another linked list (see the recursion?).
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.
So the app reads from an external file a bunch of strings, each on a separate line.
For example:
and
cake
here
It is not arranged in any particular order. I need to read these letters and put them into linked list and finally sort them.
I need help on doing that:
Here is the current code:
import java.util.*;
import java.io.*;
public class LinkedList
{
static File dataInpt;
static Scanner inFile;
public static void main(String[] args) throws IOException
{
dataInpt=new File("C:\\lldata.txt");
inFile=new Scanner(dataInpt);
Node first = insertInOrder();
printList(first);
}
public static Node getNode(Object element)
{
Node temp=new Node();
temp.value=element;
temp.next=null;
return temp;
}
public static void printList(Node head)
{
Node ptr; //not pointing anywhere
for(ptr=head;ptr!=null;ptr=ptr.next)
System.out.println(ptr.value);
System.out.println();
}
public static Node insertInOrder()
{
Node first=getNode(inFile.next());
Node current=first,previous=null;
Node last=first;
int count=0;
while (inFile.hasNext())
{
if (previous!=null
&& ((String)current.value).compareTo((String)previous.value) > 0)
{
last.next=previous;
previous=last;
}
if (previous!=null
&& ((String)current.value).compareTo((String)previous.value) < 0)
{
current.next=last;
last=current;
}
previous=current;
current=getNode(inFile.next());
}
return last;
}
}
But that gives an infinite loop with "Cat".
Here is the data file:
Lol
Cake
Gel
Hi
Gee
Age
Rage
Tim
Where
And
Kite
Jam
Nickel
Cat
Ran
Jug
Here
Okay, self-study. Split the reading and inserting. Though old and new code both have 14 lines of code,
it makes it more intelligable.
public static Node insertInOrder() {
Node first = null;
while (inFile.hasNext()) {
String value = inFile.next().toString();
first = insert(first, value);
}
return first;
}
/**
* Insert in a sub-list, yielding a changed sub-list.
* #param node the sub-list.
* #param value
* #return the new sub-list (the head node might have been changed).
*/
private static Node insert(Node node, String value) {
if (node == null) { // End of list
return getNode(value);
}
int comparison = node.value.compareTo(value);
if (comparison >= 0) { // Or > 0 for stable sort.
Node newNode = getNode(value); // Insert in front.
newNode.next = node;
return newNode;
}
node.next = insert(node.next, value); // Insert in the rest.
return node;
}
This uses recursion (nested "rerunning"), calling insert inside insert. This works like a loop, or work delegation to a clone, or like a mathematical inductive proof.
Iterative alternative
also simplified a bit.
private static void Node insert(Node list, String value) {
Node node = list;
Node previous = null;
for (;;) {
if (node == null || node.value.compareTo(value) >= 0) {
Node newNode = getNode(value);
newNode.next = node;
if (previous == null)
list = newNode;
else
previous.next = newNode;
break;
}
// Insert in the rest:
previous = node;
node = node.next;
}
return list;
}
public static Node insertInOrder()
{
Node first=getNode(inFile.next());
Node current=first,previous=null;
Node last=first;
int count=0;
while (inFile.hasNext())
{
if (previous!=null
&& ((String)current.value).compareTo((String)previous.value) > 0)
{
last.next=previous;
previous=last;
}
if (previous!=null
&& ((String)current.value).compareTo((String)previous.value) < 0)
{
current.next=last;
last=current;
}
previous=current;
current=getNode(inFile.next());
}
return last;
}
First of all, you never do anything with the last line read from the file, so that's not ever inserted. You have to read the line and create the new Node before relinking next pointers.
Then, if last and previous refer to the same Node and the data of current is larger than that of previous,
if (previous!=null
&& ((String)current.value).compareTo((String)previous.value) > 0)
{
last.next=previous;
previous=last;
}
You set last.next = last, breaking the list. From the code (in particular the absence of a sort(Node) function), it seems as though you want to sort the list as it is created. But you only ever compare each new Node with one other, so that doesn't maintain order.
For each new node, you have to find the node after which it has to be inserted, scanning from the front of the list, and modify current.next and the predecessor's next.
In relatively simple code like that in your question, a good exercise to understanding it is to work through a few interations of your loop, inspecting the values of all your local variable to see the effect of your code. You can even do it by hand if the code is simple. If it is too difficult to do by hand, your code is probably too complicated. If you can't follow it, how can you know if you are doing what you intend. For example, I could be wrong, but this appears the be the state at the top of each iteration of the loop. It starts falling apart on the third time through, and by the fourth you have a severe problem as your list becomes disjointed.
1)last = first = Lol, current = previous = null
Lol->null
2)last = first = previous = Lol, current = Cake
Lol->Lol
3)first = Lol, last = Cake, previous = Cake, current = Gel
Cake->Lol->Lol
4)first = Lol, last = Cake, previous = Cake, current = Hi
Cake->Gel, Lol->Lol
Quite honestly, if I were running the course, I would consider the correct answer to be:
List<String> list = new LinkedList<String>();
// read in lines and: list.add(word);
Collections.sort(list);
Ok, I don't remember exactly school theory about insertion sort, but here is somehow a mix of what I think it is and your code:
import java.io.File;
import java.io.IOException;
import java.util.Scanner;
public class LinkedList {
public static class Node {
public String value;
public Node next;
}
static File dataInpt;
static Scanner inFile;
public static void main(String[] args) throws IOException {
inFile = new Scanner("Lol\r\n" + "Cake\r\n" + "Gel\r\n" + "Hi\r\n" + "Gee\r\n" + "Age\r\n" + "Rage\r\n" + "Tim\r\n" + "Where\r\n"
+ "And\r\n" + "Kite\r\n" + "Jam\r\n" + "Nickel\r\n" + "Cat\r\n" + "Ran\r\n" + "Jug\r\n" + "Here");
Node first = insertInOrder();
printList(first);
}
public static Node getNode(String element) {
Node temp = new Node();
temp.value = element;
temp.next = null;
return temp;
}
public static void printList(Node head) {
Node ptr; // not pointing anywhere
for (ptr = head; ptr != null; ptr = ptr.next) {
System.out.println(ptr.value);
}
System.out.println();
}
public static Node insertInOrder() {
Node current = getNode(inFile.next());
Node first = current, last = current;
while (inFile.hasNext()) {
if (first != null && current.value.compareTo(first.value) < 0) {
current.next = first;
first = current;
} else if (last != null && current.value.compareTo(last.value) > 0) {
last.next = current;
last = current;
} else {
Node temp = first;
while (current.value.compareTo(temp.value) < 0) {
temp = temp.next;
}
current.next = temp.next;
temp.next = current;
}
current = getNode(inFile.next());
}
return first;
}
}
And it works like a charm. Of course this far from optimal, both in terms of performance and code reuse.
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.