Sunday, December 21, 2008

Double Linked List in Java


/**
* LinkedList
*
* This is the core List class
* Provides a facility to a doublly linked list.
*
* Has Header Node optimization
* Has LastNode optimization as well
*
* Future Features:
* Optimized iterator support
* actually use some more of the optimization doublly linked lists gives you
*
*/

/**
* ListNode
*
* -The workhorse of the LinkedList Class
*
* Provides a doublely linked potencial to other list nodes
* Provides recursion for relative position Node lookups
* Provides automatic linking of next and previous nodes
*
*/
public class ListNode
{
/**
* Blank constructor
*/
public ListNode()
{
}
/**
* Purposeful constructor:
* passes data, and previous node, allows you to build node lists, easily by chaining
*/
public ListNode(Object pData,ListNode pPrevious)
{
mData = pData;
if (pPrevious != null) //since you can pass null to it
{
pPrevious.setNext(this); //automatic hook up
}
}

private Object mData; // stores the Object of value here

//Accessors to the Data Object
public Object getData()
{
return mData;
}
public void setData(Object obj)
{
mData = obj;
}


private ListNode mNext; // stores link to the next node in the list
//accessor to the Next reference
public ListNode getNext()
{
return mNext;
}
/**
* Automatic linking on setNext
* -set the mNext field's data
* but also will automaticly link the "nextNodes previous link to this Node's
*/
public void setNext(ListNode pNode)
{
mNext = pNode;
if (mNext != null)
{
mNext.mPrevious = this; //internal auto link MUST USE INTERNAL, If you use mNext.setPrevious infinite loop become evident
}
}

private ListNode mPrevious;
//public accessor to Previous Link
public ListNode getPrevious()
{
return mPrevious;
}
/**
* Automatic linking on setPrevious
* -set the mPrevious field's data
* but also will automaticly link the "previousNodes next link to this Node's
*/
public void setPrevious(ListNode pNode)
{
mPrevious = pNode;
if (mPrevious != null)
{
mPrevious.mNext = this; //internal auto link MUST USE INTERNAL, If you use mPrevious.setNext infinite loop become evident
}
}

/**
* Recurisve GetNext
* will return the node that is relativePos offset from this node only in the forward direction
*/
public ListNode getNextRecurisive(int relaitivePos)
{
if (relaitivePos <= 0) // if pos =0 return self
{
return this;
}
else
{
ListNode next = this.getNext(); //move to the next node
if (next != null)
{
return next.getNextRecurisive(relaitivePos - 1); //Let it count the rest of the way
}
else
{
throw new IndexOutOfBoundsException("Recursive search for rel pos could not find a node soon enough");
}
}

}

public class LinkedList
{

private ListNode mHeaderNode = new ListNode();
private ListNode mLastNode;
private int mNumItems = 0;

/**
* Constructor, sets up the default last node
*/
public LinkedList()
{
mLastNode = mHeaderNode;
}



/**
* Add is your basic add operation
* Adds to the end of the list, using the last node optimization
* the setNext function automaticly links in the previous links.
*
*/
public void add(Object obj)
{
ListNode node = new ListNode(obj,null);
mLastNode.setNext(node);
mLastNode = node; //update the last node optimization
mNumItems++;
}
/** add overload -> Insert
* Inserts a Object in the list node at any position
*
*/
public void add(int pos, Object obj)
{
if (pos == mNumItems)
{
//special case adding at the end of the list
add(obj); // use the regular add
return;
}
IsPositionInBoundsOf(pos); //Insure the pos is a vaild pos
ListNode node = getNode(pos);//node I am inserting at
ListNode newNode = new ListNode(obj, node.getPrevious());
// hook up new node to node that was behind current node
newNode.setNext(node);
// hook up old node, to the new position
mNumItems++;
}
/**
* Contains
* Returns true if LinkedList Contains a certain object
* Object.equals is our comparer method of choice
*
* other wise false
*
*/
public boolean contains(Object obj)
{
ListNode node = mHeaderNode.getNext(); //get the first node in the list

while (node != null) // go through till the end of the list
{
if (node.getData() != null) // check so you don't get a null ref exception
{
if (node.getData().equals(obj)) // use equals so.. ref type weird data types.. cough STRINGS don't hang us up
{
return true;
}
}
else
{
// if null was passed we want to return true if the obj is null
if (obj == null) return true;
}
node = node.getNext(); // increment up to the next node
}
return false;

}

/**
* IsPositionInBoundsOf
* Returns true if pos would return a valid node in this list, if not, it will throw and indexOutOfBoundsException
*
*/
protected boolean IsPositionInBoundsOf(int pos)
{
if (pos > mNumItems - 1)
{
throw new IndexOutOfBoundsException(pos + " Is out of the bounds of the List");
}
return true;

}
/**
* get
* Returns The object of a node at a certain position
*
*/
public Object get(int pos)
{
IsPositionInBoundsOf(pos); // insure pos is accurate

ListNode node = getNode(pos); //grab the node

return node.getData(); //return the data ; null is ok

}

/**
* INTERNAL METHOD
* getNode(pos)
* Returns the list node at a certain position
*
* does a recursive search for the specified position
*
*/
protected ListNode getNode(int pos)
{
IsPositionInBoundsOf(pos);
return mHeaderNode.getNextRecurisive(pos + 1); // +1 because of header node
}
/**
* isEmpty
* returns true if their are 0 items in this list
* otherwise false
*/
public boolean isEmpty()
{
return mHeaderNode.getNext() == null;

}
/**
* remove(pos)
* Returns the object at the pos you are removeing from
* Remove the last node, will re update the lastnode reference
*
* deincrements the count in list
*
*/
public Object remove(int pos)
{
IsPositionInBoundsOf(pos);
ListNode deletednode = getNode(pos);
if (deletednode == this.mLastNode) //last node special case
{
this.mLastNode = deletednode.getPrevious(); // just patch up the last node reference
}
deletednode.getPrevious().setNext(deletednode.getNext()); //patch the whole you just made

mNumItems--;
return deletednode.getData();
}
/**
* size
* Returns the number of items in this list
*/
public int size()
{
return mNumItems;
}

//DEBUG Methods
//remove these methods
/**
* Prints out the entire list of objects in list
*/
//public void printList()
//{
// System.out.println("");
// for (int i = 0; i < mNumItems; i++)
// {
// System.out.println(get(i));
// }
// System.out.println("
");
//}

}

No comments: