Implementation Of Linked-Lists
Outline
Linked list nodes Linked list operations
Insertion Append Deletion
Linked list representation & implementation Other types of linked lists
Sorted Doubly-linked Circular
Linked Lists
Stores a collection of items non-contiguously. Each item in the list is stored with an indication of where the next item is.
Must know where first item is.
The list will be a chain of objects, called nodes, of type ListNodethat contain the data and a reference to the nextListNodein the list.
Allows addition or deletion of items in the middle of collection with only a constant amount of data movement. Contrast this with array.
A0 A1 A2 A3
first
ListNode: Definition
public class ListNode <DataType> {
DataType data; ListNode<DataType> next;
// constructors
ListNode(DataType d, ListNode<DataType> n) {
data = d; next = n; }
ListNode(DataType d) { this (d, null); }
Linked List: Insertion
Insert Ximmediately after current position
a a
current
current
b c d
b c d
x
Implementing Insertion: Step By Step
• Insertion immediately after current position
// create a new node
tmp = new ListNode<DataType>();
a
current
b
tmp
Implementing Insertion: Step By Step
• Insertion immediately after current position
// create a new node
tmp = new ListNode<DataType>(); // place x in the element field tmp.data = x;
a
current
b
tmp x
Implementing Insertion: Step By Step
• Insertion immediately after current position
// create a new node
tmp = new ListNode<DataType>(); // place x in the element field tmp.data = x;
// x s next node is b tmp.next = current.next;
a
current
b
Implementing Insertion: Step By Step
Insertion immediately after current position
// create a new node
tmp = new ListNode<DataType>(); // place x in the element field tmp.data = x;
// x s next node is b tmp.next = current.next; // a s next node is x current.next = tmp;
a
current
b
tmp x
Implementing Insertion: Shorter Version
• A shorter version:
// create a new node
tmp = new ListNode<DataType>(x,current.next); // a s next node is x
current.next = tmp;
a
current
b
tmp x
Implementing Insertion: Shorter Version
• A shorter version:
// create a new node
tmp = new ListNode<DataType>(x,current.next); // a s next node is x
current.next = tmp;
a
current
b
tmp x
Implementing Insertion: Shortest Version
• An even shorter version:
// create a new node current.next = new
ListNode<DataType>(x,current.next);
a
current
b
Implementing Append
• Insert Ximmediately at the end of the list
// last refers to the last node in the linked list last.next = new ListNode<DataType>();
last = last.next; // adjust last last.data = x; // place x in the node last.next = null; // adjust next
• Most efficient approach
last = last.next = new ListNode (x, null);
a b c d
last
a b c X
last d
last
last
Implementing Basic Deletion
• Delete an item immediately after current position
• Basic deletion is a bypass in the linked list.
a x b
a b
current current
Implementing Basic Deletion
Need a reference to node prior to the one to be deleted.
current.next = current.next.next;
a x b
a x b
a b
current
current
current
Important Note
• Remember!!!
– What we store in a
ListNode
is a
reference
to the object,
NOT
the
object
Iterate Through The Linked List
If items are stored in contiguous array:
//step through array, outputting each item for (int index = 0; index < a.length; index++)
System.out.println (a[index]);
If items are stored in a linked list:
// step through list, outputting each item for(ListNode p=l.first; p!=null; p=p.next)
System.out.println (p.data);
A0 A1 A2 A3
first
Implementing a Linked List
So what would a Linked List implementation look like?
What happens if we want to
Delete the first item?
Insert an item before the first item? class MyLinkedList <DataType> {
// Field
ListNode<DataType> first; // Methods
void insert(DataType x, ???); void delete(DataType x, ???); void append(DataType x); ...
}
Header Nodes
Deletion of first item and insertion of new first item are special cases.
Can be avoided by using headernode;
contains no data, but serves to ensure that first "real" node in linked has a predecessor.
To go to the first element, set currentto
header.next;
List is empty if header.next == null; Searching routines will skip header.
A1 A2 A3
header
Linked Lists: List Implementation (partial)
public class LinkedList<T> implements List {
public boolean isEmpty( )
{ return header.next == null; } // Make the list logically empty
Representing the “current” position
• How do we specify where an operation should occur? – Index position (int?)
– ListNode
// Methods
void insert(DataType x, ???); void delete(DataType x, ???);
void insert(DataType x, int current); void delete(DataType x, int current); void insert(DataType x, ListNode current); void delete(DataType x, ListNode current);
a x
current
List Iterator Class
• Maintains a notion of the current position (aka cursor).
• The List class provides methods that do not depend on any position (such as isEmpty, and makeEmpty).
• A List iterator (ListItr) provides other methods such which act on the current position stored in the iterator:
– next() / advance()
– hasNext() / isValid()
– retrieve()
Linked List Iterator: Implementation
public class ListItr <DataType> {
ListNode<DataType> current; // Current position
ListItr(ListNode<DataType> node) { }
public boolean hasNext() { }
public void next()
{ }
public DataType retrieve() { } }
Example Usage
• A method that computes the number of elements in any list:
public static int listSize (List theList) {
int size = 0; ListItr itr;
for(itr=theList.first();itr.hasNext();itr.next()) size++;
Linked Lists: Implementation
public class List <T> {
// Header node
private ListNode<T> header; // Check if list is empty boolean isEmpty() {???} // Make the list empty void makeEmpty () {???} // Cursor to header node public ListItr<T> zeroth() {???} // Cursor to first node public ListItr<T> first() {???} // Cursor to (first) node containing x public ListItr<T> find(T x) {???} // Cursor to node before node containing x public ListItr<T> findPrevious(T x) {???} // Insert x after current cursor position public void insert(T x, ListItr<T> current) {???} // Remove (first) node containing x
public void remove(T x) {???} }
Java Implementations
• Mostly straightforward; all routines are short.
• ListItrmaintains a reference to the list
that it is bound to as a private data member.
• Because ListItris in the same package as
List, if List's data access is (package) friendly, it can be accessed by ListItr.
Note on Exceptions
• Some routines throw ItemNotFound exceptions.
• However, do not overuse exceptions, because they must always be caught or propagated. As
an example, advancedoes not throw an
exception, even if we have already advanced
past the end. Otherwise, listSizewould
need a try/catch block.
Linked List Properties
Running Time Analysis
insert next, prepend - O(1) delete next, delete first - O(1) find - O(n)
retrieve current position - O(1)
Advantages
Growable (compared to array)
Easy (quick) in read/insert/delete the first and the last element (if we also store the last position not just the head/current position)
Disadvantages
Print all elements of Linked List
Method 1: Without Iterator, Simple Looping
public class LinkedList <T> {
public void print() {
// step through list, outputting each item ListNode<T> p = header.next;
while (p != null)
Print all elements of Linked List(2)
• Method 2: Without Iterator, Using Recursion
public class LinkedList <T> {
private void printRec (ListNode<T> node) {
public void print () {printRec (header.next);} }
Print all elements of Linked List(3)
• Method 3: Recursion
class ListNode <T> {
public void print () {
class LinkedList <T> {
public void print() {
if (header.next != null) header.next.print (); }
}
Print all elements of Linked List(4)
• Method 4: Using iterator
class LinkedList <T> {
public void print() {
Sorted Linked Lists
• Maintains items in sorted order.
• Almost all operations are the same as linked lists, except for insert.
• In fact, a sorted linked list IS-A linked list, suggesting that inheritance may be used.
Extend a SortListItrfrom ListItr.
• However, items in a sorted linked list should be Comparable.
Simple Implementation
• Use inheritance, and create Insertmethod
public void insert( Comparable X )
• Note however, that in this implementation, we have no assurance that the list is sorted,
because it can be accessed by either a
SortListItror a ListItr.
• See the textbook for details.
Important Note
ListItrused the equalsmember function in findand remove.
Must make sure MyIntegerhas an equalsmember function if we are storing a linked list of MyIntegers. Signature MUST BE
public boolean equals( Object Rhs )
The following signature is wrong!
public boolean equals( Comparable Rhs )
If you try it, the method from class Objectwill be inherited and used:
public boolean equals (Object obj) {
return (this == obj); }
Other Linked Lists
• Doubly-linked lists: Each list node stores both the previous and next nodes in the list. Useful for traversing linked lists in both directions.
• Circular-linked lists: Last node's next references the first node. Works with or without headers.
A
head tail
prev
next
A B C
first
prev
Doubly-linked lists: Wrong InsertNext
newNode = new DoublyLinkedListNode ( x );
1 newNode.prev = current;
2 newNode.prev.next = newNode;
x
b a
1 2
Doubly-linked lists: insertNext
1 newNode = new
DoublyLinkedListNode (x); 2 newNode.prev = current;
3 newNode.next = current.next; 4 newNode.prev.next = newNode; 5 newNode.next.prev = newNode; 6 current = newNode;
A B
current
X
prev
next
newNode
Doubly-linked lists: DeleteCurrent
1.current.prev.next = current.next;
2.current.next.prev = current.prev;
3.current = current.prev;
x
b a
current 1 2 3
JDK: package java.util
•Collection - List - LinkedList
Summary
• ListNode • List, LinkedList • Iterator class
– a class that maintains a current position and performs all routines that depend on knowing the position in the list.
• Advantage & Disadvantage of linked list – Growable
– Overhead a pointer, new operator – Sequential access only