Please send questions to
st10@humboldt.edu .
/* Cs132LinkedList.java 1.1 */
/* by Sharon Tuttle */
/* last modified: 3-7-03 */
/* originally from Georgia Tech's CS 1322 Module 27 notes */
/* on Linked Lists, Stacks, and Queues, */
/* with influences from course text, "Java Structures",*/
/* pp. 168-189. */
/* */
/* A concrete subclass of Cs132AbstractList, */
/* using a linked list implementation */
public class Cs132LinkedList extends Cs132AbstractList
{
/*------------------------------------
fields
-------------------------------------*/
// beginning of linked list
private Cs132ListNode head;
// number of items currently in linked list
private int count;
/*--------------------------------------
constructors
---------------------------------------*/
// creates an empty linked list
public Cs132LinkedList()
{
this.head = null;
this.count = 0;
}
/*-------------------------------------------------------
accessors
-------------------------------------------------------*/
public Cs132ListNode getHead()
{
return this.head;
}
/*-------------------------------------------------------
modifiers
-------------------------------------------------------*/
public void setHead(Cs132ListNode newHead)
{
this.head = newHead;
}
/*------------------------------------------
overridden methods
-------------------------------------------*/
public String toString()
{
return "Cs132LinkedList[size = " + this.count + ", elements are:\n"
+ toStringHelper(this.head)
+ "]";
}
/*-------------------------------------------------------
toStringHelper
Purpose: auxiliary function for toString(), to help it print all
of the elements in a LinkedList
(strictly for local use...!)
---------------------------------------------------------*/
private String toStringHelper(Cs132ListNode currNode)
{
// BASE CASE: if node is null, nothing to print ---
// time to stop, return an empty String.
if (currNode == null)
{
return "";
}
// else, RECURSIVE CASE: create string for current
// node, concatenating the strings for the rest of the
// nodes...
else
{
return "" + currNode.getData() + "\n" +
toStringHelper(currNode.getNext());
}
}
/*---------------------------------------
other methods
----------------------------------------*/
/*-----------------------------------------------------------
isEmpty()
Purpose: return true if this object contains no nodes, return
false otherwise.
-----------------------------------------------------------------*/
public boolean isEmpty()
{
return this.count == 0;
}
/*--------------------------------------------------------
size
Purpose: return current size of the list
(why not make this an accessor? Well, I'd like to hide
the implementation detail count --- but, whether I
store it or not, finding the size of a list is a useful
piece of info for many lists.)
----------------------------------------------------------*/
public int size()
{
return this.count;
}
/*-------------------------------------------------------
addFirst
Purpose: add given data newObj to beginning
of list.
---------------------------------------------------------*/
public void addFirst(Object newObj)
{
// here's a list node to hold the new data
Cs132ListNode newNode = new Cs132ListNode(newObj);
// new list node should be set to point to
// current first element in list...
// (what if list is currently empty? that's OK,
// head is null, and new node's next field is
// simply reset to null, which is just what we
// want for a 1-element list...
newNode.setNext(this.head);
// now, newNode can be NEW first element in list!
this.head = newNode;
// and don't forget to increment the count!
this.count = this.count + 1;
}
/*-------------------------------------------------------
addLast()
Purpose: add given data newObj to end
of list.
---------------------------------------------------------*/
public void addLast(Object newObj)
{
// here's a list node to hold the new data
Cs132ListNode newNode = new Cs132ListNode(newObj);
// what if list is empty? then first is last, too!
if (this.head == null)
{
this.head = newNode;
}
// but, more likely, you'll need to "walk" to the end...
else
{
Cs132ListNode currNode = this.head;
// keep "walking" down the list until you reach the last
// node; how do you know? When the node you are looking
// at has NO "next" node!
while (currNode.getNext() != null)
{
// make the NEXT node the next node to consider...
currNode = currNode.getNext();
}
// you KNOW currNode is the last node, now!
// ... and so it is the one leading to our new node-to-add
currNode.setNext(newNode);
}
// in either case, don't forget to increase list size!
this.count = this.count + 1;
}
/*----------------------------------------------------------------
add()
Purpose: add given data newElement to list at position index (where
0 is the index of the first item in the list, 1 is the
index of the 2nd item in the list, etc.)
Throw a ListIndexOutOfBoundsException if the list
index is not between 0 and the size of the array
(I *could* add a new element to the end --- thus "size"
instead of the usual "size - 1").
BUT note --- those elements "after" this position ARE
shifted "up" a position!
-----------------------------------------------------------------*/
public void add(int index, Object newElement) throws
ListIndexOutOfBoundsException
{
// complain if trying to add an element to an illegal position
if ((index < 0) || (index > this.size()))
{
throw new ListIndexOutOfBoundsException(index);
}
// if get here, index is reasonable.
Cs132ListNode previous = null;
Cs132ListNode current = this.head;
Cs132ListNode newNode = new Cs132ListNode(newElement);
// what if this item goes on the beginning of the list?
if (index == 0)
{
newNode.setNext(this.head);
this.head = newNode;
}
else
{
// find out where the element SHOULD go
int temp = 0;
while (temp != index)
{
previous = current;
current = current.getNext();
temp = temp + 1;
}
// NOW we should be where the element goes...
previous.setNext(newNode);
newNode.setNext(current);
}
this.count = this.count + 1;
}
/*----------------------------------------------------------------
getFirst()
Purpose: IF list is not empty, return FIRST element in list.
(this is its VALUE, not the node itself!)
If it IS empty, throw a ListEmptyException
-----------------------------------------------------------------*/
public Object getFirst() throws ListEmptyException
{
if (this.size() == 0)
{
throw new ListEmptyException();
}
// if reach here, there IS something to get!
return this.head.getData();
}
/*----------------------------------------------------------------
getLast()
Purpose: IF the list is not empty, return the LAST element in list.
(this is its VALUE, not the node itself!)
If it IS empty, throw a ListEmptyException
----------------------------------------------------------------------*/
public Object getLast() throws ListEmptyException
{
if (this.size() == 0)
{
throw new ListEmptyException();
}
// if reach here, there IS something in the list to get
// start by looking at beginning of list
Cs132ListNode currNode = this.head;
// "walk" through list until reach last element
while (currNode.getNext() != null)
{
currNode = currNode.getNext();
}
// when we get here, currNode IS the last node.
// return its value.
return currNode.getData();
}
/*----------------------------------------------------------------
get()
Purpose: return the element at position index in the list
(where 0 is the index of the first item in the list).
If the list is empty, throw a ListEmptyException.
If the index is not between 0 and (list's size - 1),
throw a ListIndexOutOfBoundsException.
----------------------------------------------------------------------*/
public Object get(int index) throws ListEmptyException,
ListIndexOutOfBoundsException
{
// is list empty?
if (this.size() == 0)
{
throw new ListEmptyException();
}
// list is NOT empty, so now
// make sure that index is reasonable --- if not, complain
if ((index < 0) || (index >= this.count))
{
throw new ListIndexOutOfBoundsException(index);
}
// index must be reasonable, if reach here ---
// proceed to that list element
else
{
Cs132ListNode currNode = this.head;
for (int i=0; i < index; i++)
{
currNode = currNode.getNext();
}
// so, i==index now... this is the desired position
return currNode.getData();
}
}
/*----------------------------------------------------------------
remove()
Purpose: This seeks to remove the element at position index
of the list (where 0 is the index of
the first element in the list). It will do so and return
the object removed if the index is indeed a position
in the list. (elements "above" in this list are now
one position "lower")
If the list is empty, however, it will
throw a ListEmptyException, and if the index is not
a position in the list, it will throw a
ListIndexOutOfBoundsException.
--------------------------------------------------------------------*/
public Object remove(int index) throws ListEmptyException,
ListIndexOutOfBoundsException
{
// is list empty?
if (this.size() == 0)
{
throw new ListEmptyException();
}
// list is NOT empty, so now
// make sure that index is reasonable --- if not, complain
if ((index < 0) || (index >= this.count))
{
throw new ListIndexOutOfBoundsException(index);
}
// since it is reasonable, proceed to ONE BEFORE the list element
// to be removed
else
{
Cs132ListNode currNode = this.head;
// special case: what if removing first element?
if (index == 0)
{
this.head = (this.head).getNext();
this.count = this.count - 1;
return currNode.getData();
}
// if get here, node t be removed is NOT first in list
for (int i=0; i < (index-1); i++)
{
currNode = currNode.getNext();
}
// so, currNode is now the node BEFORE the node to
// be removed.
Object removedElement = (currNode.getNext()).getData();
currNode.setNext( (currNode.getNext()).getNext() );
this.count = this.count - 1;
return removedElement;
}
}
/*----------------------------------------------------------------
clear()
Purpose: empties the LinkedList instance that calls this.
----------------------------------------------------------------------*/
public void clear()
{
this.head = null;
this.count = 0;
}
}