570 likes | 745 Views
Lecture Objectives. Linked list data structures: Singly-linked (cont.) Doubly-linked Circular Implementing the List interface as a linked list The Iterator interface Implementing Iterator for a linked list. Double-Linked Lists and Circular Lists. Double-Linked Lists.
E N D
Lecture Objectives • Linked list data structures: • Singly-linked (cont.) • Doubly-linked • Circular • Implementing the List interface as a linked list • The Iterator interface • Implementing Iterator for a linked list CS340
Double-Linked Lists • Limitations of a singly-linked list: • Insertion at the front is O(1) • insertion at other positions is O(n) • Insertion is convenient only after a referenced node • Removing a node requires a reference to the previous node • We can traverse the list only in the forward direction • How to overcome these limitations? • Double-linked list CS340
NodeClass private static class Node<E> { private E data; private Node<E> next = null; private Node<E> prev = null; private Node(E dataItem) { data = dataItem; } } CS340
Node Node Node next = = prev data = "Harry" next = null = prev data = "Sam" next = = prev data = "Sharon" Inserting into a Double-Linked List from predecessor sam to predecessor sharon Node<E> sharon = new Node<E>("Sharon"); sharon.next = sam; sharon.prev = sam.prev; sam.prev.next = sharon; sam.prev = sharon;
Node Node Node next = = prev data = "Dick" next = = prev data = "Harry" next = = prev data = "Sharon" Removing from a Double-Linked List harry harry.prev.next = harry.next harry.next.prev = harry.prev CS340
A Double-Linked List Class • A double-linked list object has data fields: • head (a reference to the first list Node) • tail (a reference to the last list Node) • size • Insertion at either end is O(1) • Insertion elsewhere is still O(n) CS340
The LinkedListClass and the Iterator, ListIterator, and Iterable Interfaces CS340
TheLinkedListClass CS340
The Iterator • A moving place marker • Iteratorobject for a list starts at the list head • It can move by calling its next method. • Stays on its current list item until it is needed • An Iterator traverses in O(n) while a list traversal using get() calls in a linked list is O(n2) CS340
IteratorInterface • Defined in java.util CS340
IteratorInterface (cont.) • An Iterator is between elements CS340
IteratorInterface (cont.) • In the following loop, we process all items in List<Integer> through an Iterator Iterator<Integer> iter = aList.iterator(); while (iter.hasNext()) { int value = iter.next(); // Do something with value ... } CS340
Iterators and Removing Elements • remove() deletes the most recent element returned • You must call next()before each remove() • Else IllegalStateExceptionwill be thrown • LinkedList.remove vs. Iterator.remove: • LinkedList.remove must walk down the list each time, then remove,O(n2) complexity • Iterator.remove removes items without starting over at the beginning, O(n) complexity CS340
Iterators and Removing Elements (cont.) • Remove all elements from a list of type Integer that are divisible by a particular value: public static void removeDivisibleBy(LinkedList<Integer> aList, int div) { Iterator<Integer> iter = aList.iterator(); while (iter.hasNext()) { int nextInt = iter.next(); if (nextInt % div == 0) { iter.remove(); } } } CS340
ListIteratorInterface • Iteratorlimitations • Traverses Listonly in the forward direction • Provides a removemethod, but no add method • If you do not want to start from the beginning: • You must advance the Iterator using your own loop • Solution: • ListIteratorextends Iterator CS340
ListIteratorInterface (cont.) • ListIterator is positioned between elements of the list • ListIterator positions: 0 to size CS340
Comparison of IteratorandListIterator • ListIterator is a subinterface of Iterator • Classes that implement ListIterator must provide the features of both • Iterator: • Requires fewer methods • Can iterate over more general data structures • Iterator is required by the Collection interface • ListIteratoris required only by the List interface CS340
Conversion Between ListIteratorand an Index • ListIterator: • nextIndex()returns the index of item to be returned by next() • previousIndex() returns the index of item to be returned by previous() • LinkedList has method listIterator(int index) • Returns a ListIterator positioned so next()will return the item at position index • How? What is the complexity? CS340
CS340LinkedList CS340
CS340LinkedList (cont.) import java.util.*; /** Class CS340LinkedList implements a double linked list and a ListIterator. */ public class CS340LinkedList <E> { // Data Fields private Node <E> head = null; private Node <E> tail = null; private int size = 0; . . .
AddMethod • Obtain a reference, nodeRef, to the node at position index • Insert a new Node containing obj before the node referenced by nodeRef To use a ListIterator object to implement add: • Obtain an iterator that is positioned just before the Node at position index • Insert a new Node containing obj before the Node currently referenced by this iterator /** Add an item at the specifiedindex. @param index The index at which the object isto be inserted @param obj The object to beinserted @throws IndexOutOfBoundsException if the index is out of range (i < 0 || i > size()) */ public void add(int index, E obj) { listIterator(index).add(obj); }
GetMethod • Obtain a reference, nodeRef, to the node at position index • Return the contents of the Node referenced by nodeRef /** Get the element at position index. @param index Position of item to be retrieved @return The item at index */ public E get(int index) { return listIterator(index).next(); } CS340
OtherAddandGetMethods public void addFirst(E item) { add(0, item); } public void addLast(E item) { add(size, item); } public E getFirst() { return head.data; } public E getLast() { return tail.data; } CS340
Implementing the ListIteratorInterface • CS340ListIter is an inner class of CS340LinkedListwhich implements the ListIterator interface CS340
Implementing the ListIteratorInterface (cont.) private class CS340ListIter implements ListIterator<E> { private Node <E> nextItem; private Node <E> lastItemReturned; private int index = 0; ... CS340
Constructor public CS340ListIter(inti) { if (i < 0 || i > size) { // Validate i parameter. throw new IndexOutOfBoundsException("Invalid index " + i); } lastItemReturned = null; // No item returned yet. if (i == size) {// Special case of last item index = size; nextItem = null; } else { // Start at the beginning nextItem = head; for (index = 0; index < i; index++) { nextItem = nextItem.next; } } }
ThehasNext()Method • tests to see if nextItem is null public booleanhasnext() { return nextItem != null; } CS340
CS340LinkedList CS340ListIter Node Node Node head tail size 3 nextItem lastItemReturned index 1 next prev null data "Tom" next prev next prev data "Sam" Advancing the Iterator data "Harry" public E next() { if (!hasNext()) { throw new NoSuchElementException(); } lastItemReturned = nextItem; nextItem = nextItem.next; index++; return lastItemReturned.data; } 2
Why is the iterator useful? • Process all elements of a list for(i=0; i < aList.size(); i++){ E nextElement = aList.get(i); } E get(int index){ Node<E> nodeRef = head; for(i=0; i < index; i++){ nodeRef= nodeRef.next(); } } CS340
Why is the iterator useful? (cont.) • Process all elements of a list for(i=0; i < aList.size(); i++){ E nextElement = listIterator(i).get(); } CS340
PreviousMethods public boolean hasPrevious() { return (nextItem == null && size != 0) || nextItem.prev != null; } public E previous() { if (!hasPrevious()) { throw new NoSuchElementException(); } if (nextItem == null) { // Iterator past the last element nextItem = tail; } else { nextItem = nextItem.prev; } lastItemReturned = nextItem; index--; return lastItemReturned.data; }
TheAddMethod • 4 cases to address: • Add to an empty list • Add to the head of the list • Add to the tail of the list • Add to the middle of the list CS340
Adding to an Empty List Node CS340LinkedList next = null = prev data = "Tom" head = null tail = null size = 3 (after insertion) 1 if (head == null) { head = new Node<E>(obj); tail = head; } ... size++ CS340ListIter nextItem = lastItemReturned = null index = 0 1 CS340
Adding to the Head of the List CS340ListIter nextItem = lastItemReturned = null index = 0 1 Node Node Node next = null = prev data = "Tom" next = null = prev data = "Sam" next = = prev data = "Harry" CS340LinkedList head = null tail = null size = 3 4 if (nextItem == head) { Node<E> newNode = new Node<E>(obj); newNode.next = nextItem; nextItem.prev = newNode; head = newNode; } ... size++; index++; Node next = null null = prev data = "Ann" newNode
Adding to the Tail of the List CS340ListIter nextItem = nulllastItemReturned = null index = 2 Node 3 next = = prev data = "Ann" Node Node CS340LinkedList next = null = prev data = "Sam" next = prev = null data = "Tom" head = null tail = null size = 3 4 if (nextItem == null) { Node<E> newNode = new Node<E>(obj); tail.next = newNode; newNode.prev = tail; tail = newNode } ... size++; index++; Node next = null null = prev data = "Bob" newNode
Adding to the Middle of the List CS340ListIter nextItem = nulllastItemReturned = null index = 1 Node 2 next = = prev data = "Ann" Node Node CS340LinkedList next = null = prev data = "Sam" next = prev = null data = "Tom" head = null tail = null size = 3 4 Node else { Node<E> newNode = new Node<E>(obj); newNode.prev = nextItem.prev; nextItem.prev.next = newNode; newNode.next = nextItem; nextItem.prev = newNode; } ... size++; index++; next = null null = prev data = "Bob" newNode
Inner Classes: Static and Nonstatic • CS340LinkedListcontains two inner classes: • Node<E> is static: no need for it to access the data fields of its parent class • CS340ListIter cannot be declared static because its methods access and modify data fields of CS340LinkedList’sparent object which created it • An inner class which is not static: • contains an implicit reference to its parent object • can reference the fields of its parent object CS340
Application of the LinkedListClass If time, use example with eclipse
An Application: Royal Navy • We want to maintain a list of officer’s names in alphabetical order at all times • Create a nested linked list using officers' and ships' information from the British Royal Navy archives. • Each ship in the primary linked list is populated with the correct crew using a second linked list. • The resulting data structure is a linked list of ships, with each node containing a linked list of officers assigned to that ship in 1894.
An Application: Royal Navy • Approach • Develop an OrderedListclass (which can be used for other applications) • Implement a Comparable interface by providing a compareTo(E) method • Use a LinkedList class as a component of the OrderedList • if OrderedList extended LinkedList, the user could use LinkedList's add methods to add an element out of order
Inserting into an OrderedList • Strategy for inserting new element e: • Find first item > e • Insert e before that item • Refined with an iterator: • Create ListIterator that starts at the beginning of the list • While the ListIterator is not at the end of the list and e >= the next item • Advance the ListIterator • Insert e before the current ListIterator position