Implementing Insertion: Step By Step
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 ListNode that contain the data and a reference to the next ListNode in 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); } ListNode() { this (null); }
} Linked List: Insertion Implementing Insertion: Step By Step
- Insertion immediately after current position
a b c d // create a new node tmp = new ListNode<DataType>(); current
Insert X immediately after current position
a b c d a b x current current tmp
Implementing Insertion: Step By Step Implementing Insertion: Step By Step
- Insertion immediately after current position • Insertion immediately after current position
// create a new node // create a new node tmp = new ListNode<DataType>(); tmp = new ListNode<DataType>(); // place x in the element field // place x in the element field tmp.data = x; tmp.data = x; // x s next node is b tmp.next = current.next; a b a b x x current current tmp tmp Implementing Insertion: Step By Step Implementing Insertion: Shorter Version
Insertion immediately after current position
- A shorter version:
// create a new node // create a new node tmp = new ListNode<DataType>(); tmp = new ListNode<DataType>(x,current.next); // place x in the element field // a s next node is x tmp.data = x; current.next = tmp; // x s next node is b tmp.next = current.next; // a s next node is x a b current.next = tmp; a b x current tmp x current tmp
Implementing Insertion: Shorter Version Implementing Insertion: Shortest Version
- A shorter version:
- An even shorter version:
// create a new node tmp = new ListNode<DataType>(x,current.next); // create a new node // a s next node is x current.next = new ListNode<DataType>(x,current.next); current.next = tmp; a b a b x x current current tmp
Implementing Append Implementing Basic Deletion
- Insert X immediately at the end of the list
- Delete an item immediately after current
// last refers to the last node in the linked list
position
last.next = new ListNode<DataType>(); last = last.next; // adjust last • Basic deletion is a bypass in the linked list. last.data = x; // place x in the node a x b last.next = null; // adjust next a b c d current last last a b a b c d
X last current last
- Most efficient approach
last = last.next = new ListNode (x, null); Implementing Basic Deletion
Important Note Need a reference to node prior to the one to be deleted. current.next = current.next.next; a x b
- Remember!!!
- – What we store in a ListNode is a
current reference to the object, NOT the object a x b itself nor a copy of the object! current a b current Iterate Through The Linked List Implementing a Linked List
So what would a Linked List implementation look like?
If items are stored in contiguous array:
//step through array, outputting each item class MyLinkedList <DataType> for (int index = 0; index < a.length; index++) { System.out.println (a[index]); // Field ListNode<DataType> first;
If items are stored in a linked list:
// Methods // step through list, outputting each item void insert(DataType x, ???); for(ListNode p=l.first; p!=null; p=p.next) void delete(DataType x, ???); System.out.println (p.data); void append(DataType x); ... }
A0 A1 A2 A3
What happens if we want to Delete the first item? Insert an item before the first item? first
Header Nodes Linked Lists: List Implementation (partial)
public class LinkedList<T> Deletion of first item and insertion of new first implements List item are special cases.
{ ListNode<T> header;
Can be avoided by using header node; // Constructor
contains no data, but serves to ensure that first "real"
public LinkedList() node in linked has a predecessor. { header = new
ListNode<T>(null); }
To go to the first element, set current to header.next;
// Test if the list is logically empty.
List is empty if header.next == null;
public boolean isEmpty( ) Searching routines will skip header. { return header.next == null; } // Make the list logically
A1 A2 A3
empty public void makeEmpty( ) { header.next = null; }
}
header
List Iterator Class Representing the “current” position
- Maintains a notion of the current position (aka
a x cursor).
- The List class provides methods that do not
current
- How do we specify where an operation should occur?
depend on any position (such as isEmpty,
- – Index position (int?) and makeEmpty).
- – ListNode
- A List iterator (ListItr) provides other
// Methods
methods such which act on the current
void insert(DataType x, ???); void delete(DataType x, ???);
position stored in the iterator:
void insert(DataType x, int current );
- – next() / advance()
void delete(DataType x, int current );
- – hasNext() / isValid()
void insert(DataType x, ListNode current ); retrieve()
- – void delete(DataType x, ListNode current );
Linked List Iterator: Implementation Example Usage public class ListItr <DataType>
- A method that computes the number of
{ ListNode<DataType> current; // Current position
elements in any list:
ListItr(ListNode<DataType> node) { } public static int listSize (List theList) { public boolean hasNext() int size = 0; { } ListItr itr; public void next()
{ } for(itr=theList.first();itr.hasNext();itr.next()) size++; public DataType retrieve() return size; { }
} } Linked Lists: Implementation Java Implementations public class List <T> {
- Mostly straightforward; all routines are short.
// Header node private ListNode<T> header;
- ListItr maintains a reference to the list
// Check if list is empty boolean isEmpty() {???}
that it is bound to as a private data member.
// Make the list empty void makeEmpty () {???} // Cursor to header node
- Because ListItr is in the same package as
public ListItr<T> zeroth() {???}
List, if List's data access is (package)
// Cursor to first node public ListItr<T> first() {???}
friendly, it can be accessed by ListItr.
// 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) {???}
} Note on Exceptions
Linked List Properties
Running Time Analysis
- Some routines throw ItemNotFound
insert next, prepend - O(1) exceptions. delete next, delete first - O(1)
- However, do not overuse exceptions, because
find - O(n) retrieve current position - O(1)
they must always be caught or propagated. As Advantages an example, advance does not throw an
Growable (compared to array)
exception, even if we have already advanced
Easy (quick) in read/insert/delete the first and the last
past the end. Otherwise, listSize would
element (if we also store the last position not just the head/current position)
need a try/catch block.
Disadvantages
Calling to operator new (compare to array) overhead one reference for each node Print all elements of Linked List
Method 1: Without Iterator, Simple Looping
- Method 2: Without Iterator, Using Recursion
public class LinkedList <T> { public void print() { // step through list, outputting each item ListNode<T> p = header.next; while (p != null) { System.out.println (p.data); p = p.next; } } } Print all elements of Linked List(2)
public class LinkedList <T> { private void printRec (ListNode<T> node) { if (node != null) { System.out.println (node.data); printRec (node.next); } } public void print () {printRec (header.next);} } Print all elements of Linked List(3)
- Method 3: Recursion
- Method 4: Using iterator
class ListNode <T> { public void print () { System.out.println (data); if (next != null) next.print (); } } class LinkedList <T> { public void print() { if (header.next != null) header.next.print (); } } Print all elements of Linked List(4)
class LinkedList <T> { public void print() { ListItr<ListNode<T>> itr = first(); while(itr.hasNext()) { itr.next(); System.out.println(itr.retrieve()); } } } Sorted Linked Lists • Maintains items in sorted order.
Simple Implementation
- Use inheritance, and create Insert method
public void insert( Comparable X )
- 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 SortListItr from ListItr.
- However, items in a sorted linked list should be Comparable.
- Note however, that in this implementation, we have no assurance that the list is sorted, because it can be accessed by either a SortListItr or a ListItr.
- See the textbook for details.
Important Note ListItr used the equals member function in find and remove. Must make sure MyInteger has an equals member function if we are storing a linked list of MyIntegers. Signature MUST BE public boolean equals( Object Rhs )
- 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.
The following signature is wrong! public boolean equals( Comparable Rhs )
If you try it, the method from class Object will be inherited and used: public boolean equals (Object obj) { return (this == obj); }
Other Linked Lists
A head tail prev next
A B C first prev next Doubly-linked lists: Wrong InsertNext Doubly-linked lists: insertNext newNode = new DoublyLinkedListNode ( x );
A B 1 newNode.prev = current; prev
2 newNode.prev.next = newNode;
X next current newNode
1 newNode = new
a b
2 DoublyLinkedListNode (x);
2 newNode.prev = current;
1 x
3 newNode.next = current.next; 4 newNode.prev.next = newNode; 5 newNode.next.prev = newNode; 6 current = newNode;
Doubly-linked lists: DeleteCurrent JDK: package java.util
List
1.current.prev.next =
- Collection
- current.next;
- LinkedList
Iterator ListIterator
- 2.current.next.prev = current.prev;
3.current = current.prev;
1 a b
2
3 x current
Further Reading
Summary
- ListNode
- List, LinkedList
- Iterator class
- Chapter 6 & 17
- – 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