Lecture 5 -- Linked Lists
Linked Lists
Consider the array implementation of List. It provides efficient access
to individual data items by index; in particular, the get and set methods
are fast. However, it has some shortcomings:- The resize operation is expensive (in execution time).
- Adding at the beginning or middle of the list is expensive.
- Removing from the beginning or middle of the list is expensive.
On the other hand, it is the contiguous nature of the array that is responsible for its drawbacks. An alternative is the linked list. A linked list is comprised of a series of memory blocks called nodes. Each node contains one data item along with a reference ("link") to the next node in the list, as shown below:
Some properties of linked lists:
- Items need not be stored contiguously. The logical order of the list may not be the same as its physical order.
- To maintain a logical ordering, each item has a reference to the next item.
- Items may be removed from the list by skipping over them in the link path.
- Items may be added to the list by linking them in; that is, modifying a few of the links.
- Sequential traversal (in logical order) can be performed by following the link path.
for(ListNode n = head; n!=null; n=n.next)
System.out.println(n.datum);
Linked lists are used frequently in the implementation of abstract data types. Most data structure implementations are either array-based or link-based.
Several variations on the basic linked list are possible, such as
- Maintaining both a head and tail pointer.
- Using a sentinel node (dummy node) at the head or tail of the list.
- Circular linked list.
- Doubly-linked list.
/*
Linked List implementation. This implementation uses a nested ListNode class.
Each ListNode contains one data item and a link to the next node in the
list. The LinkedList class itself contains references to the head node and
the tail node in the list. It also keeps a count of the number of items in
the list.
*/
public class LinkedList implements SimpleList
{
private int nitems;
private ListNode head,tail;
private class ListNode {
private Object datum;
private ListNode next;
ListNode(Object datum){
this.datum = datum;
next = null;
}
ListNode(Object datum, ListNode next){
this.datum = datum;
this.next = next;
}
private Object getDatum(){
return datum;
}
private ListNode getNext(){
return next;
}
}
LinkedList()
{
nitems = 0;
head = null;
tail = null;
}
private ListNode getnth(int index)
{
ListNode target = head;
if(index<0 || index>=nitems)
throw new IndexOutOfBoundsException();
for(int k=0; k<index; k++)
target = target.next;
return target;
}
public void clear()
{
nitems=0;
head=tail=null;
}
public int size()
{
return nitems;
}
public boolean isEmpty()
{
return head==null;
}
public Object get(int index)
{
return getnth(index).datum;
}
public Object set(int index, Object obj)
{
ListNode node = getnth(index);
Object temp = node.datum;
node.datum = obj;
return temp;
}
public boolean add(Object item)
{
if(isEmpty())
head = tail = new ListNode(item);
else {
tail = tail.next = new ListNode(item);
}
nitems++;
return true;
}
public Object remove(int index)
{
Object target;
if(index<0 || index>=nitems)
throw new IndexOutOfBoundsException();
else if(index==0){
target = head.datum;
head = head.next;
if(nitems==1)
tail = null;
}
else {
ListNode prior = getnth(index-1);
target = prior.next.datum;
prior.next = prior.next.next;
if(nitems==index+1)
tail = prior;
}
--nitems;
return target;
}
public void add(int index, Object item)
{
if(index<0 || index>nitems)
throw new IndexOutOfBoundsException();
else if(index==nitems)
add(item);
else if(index==0)
head = new ListNode(item, head);
else {
ListNode prior = getnth(index-1);
prior.next = new ListNode(item,prior.next);
++nitems;
}
}
public String toString()
{
String result = "[";
for(ListNode n = head; n!=null; n=n.next){
result += n.datum;
if(n!=tail)
result += ",";
}
return result+"]";
}
public Iterator iterator() {
return new Iterator() {
ListNode cursor = head;
boolean hasNext(){
return cursor!=null;
}
Object next() {
Object result = cursor.datum;
cursor = cursor.next;
return result;
}
};
}
}
Some advantages of linked lists:
- Access by pointer is faster than array indexing.
- Add and remove don't require shuffling data.
- They use only needed storage.
- Efficient operations: adding or removing the first element; appending one list to another.
- Process in forward order only (unless doubly-linked).
- Extra storage required for links.
- Inefficient operations: access to the nth element.