Date post: | 19-Dec-2015 |
Category: |
Documents |
View: | 213 times |
Download: | 0 times |
Linked Lists
Dr. Tim MargushUniversity of Akron
© 2009
Goals
• Describe a linked data structure• Perform basic operations on a linked data structure
using a Node class• Implement the List ADT using a linked data structure• Compare the advantages of linked to array-based
implementations of a list
© 2009 Dr. Tim Margush
Backing Store
• Every List implementation requires a backing store– A data structure containing elements of the List
• An array is one possible backing store– Arrays store data references physically contiguous
memory locations• A linked structure is another– References to data in linked structures are
scattered throughout memory
© 2009 Dr. Tim Margush
Array vs. Linked Structure
• References to List elements can be stored– In physical sequential order (array)– In random locations (linked)
• Must be able to locate the first and next items– list[0], list[1], …– head, current.next• The first element is special• Each element "knows" where the next is
© 2009 Dr. Tim Margush
Links
• Links specify the location of something• Links can be integers, or references– Object t; • t is a link (reference) to an Object
– int loc;• loc is an array subscript used to locate an Object (or
primitive value)
© 2009 Dr. Tim Margush
Nodes
• Nodes support linked structures by bundling data with one or more links to other elements of the collection
• A linked list uses Nodes with a data value and one or more links (references) to other Nodes
© 2009 Dr. Tim Margush
class Node<E>{ private E data; private Node<E> next;}
Inner Classes
• An inner class is defined inside another class • A private inner class is only accessible by the
outer (enclosing) class
© 2009 Dr. Tim Margush
public class LList<E> implements ListInterface<E>{ private class Node{ private E data; private Node next; }
private Node head;
Inner Classes
• Methods in both the inner and outer class have complete access to all members of each other, including private members
© 2009 Dr. Tim Margush
public class LList<E> implements ListInterface<E>{ private class Node{ private Node(){ //access private outer member if (head == null) … } } //access private constructor private Node head = new Node();
Visualization of a Linked List
© 2009 Dr. Tim Margush
null
Node head;
Inner Class: Node
© 2009 Dr. Tim Margush
public class LList<E> implements ListInterface<E>{ private class Node{ private E data; private Node next; private Node(E newEntry){ this(newEntry, null); }
private Node(E newEntry, Node n){ data = newEntry; next = n; } } } …
Linked List Implementationpublic class LList<E> implements ListInterface<E>{ private Node head; private int size;
//insert inner class for Node here
public LList(){ clear(); } public final void clear(){ head = null; size = 0; } …}
© 2009 Dr. Tim Margush
Linked List addpublic boolean add(int newPosition, E newEntry){ if (newPosition<0 || newPosition>size) return false; Node prev = getNodeAt(newPosition-1); if (prev == null){ head = }else{ prev.next = } size++; return true;}
© 2009 Dr. Tim Margush
getNodeAt, addprivate Node getNodeAt(int loc){ Node temp = head; if (loc<0 || loc>=size) return null; while(loc-- > 1)
temp = return temp;}
public boolean add(E newEntry){
return}
© 2009 Dr. Tim Margush
removepublic E remove(int position){ if (position<0 || position>-size) return null; Node todelete, prev = getNodeAt(position-1); if (prev == null){ todelete = head; head = todelete.next; }else{
} size--; return todelete.data;}
© 2009 Dr. Tim Margush
Array vs. Linked List Backing Store
Array• Wastes memory in unused
positions• Resizing requires moving
many references• Random access is efficient• Insert in middle requires
shifting• Add to end is fast• Add to beginning is costly
Linked list• Uses only the memory
needed for the data actually in the list
• Resizing is never necessary• Random access is inefficient• Insert in middle is efficient
after locating previous • Add to end is costly• Add to beginning is fast
© 2009 Dr. Tim Margush
Variations on Node
• class Node should be accessible only to LList (or other collection-type clients)– Private inner class• Add public get/set methods
– Package access• Access can be package or public• Set/get methods are optional as free access is available
inside package (unless declared private)
© 2009 Dr. Tim Margush
Package Model
© 2009 Dr. Tim Margush
package ListPackage;
//Everything in this class is package accessClass Node<E>{ E data; Node<E> next; Node(E newEntry){ this(newEntry, null); } Node(E newEntry, Node<E> n){ data = newEntry; next = n; }}
Package Model - add
© 2009 Dr. Tim Margush
package ListPackage;
public class LList<E>{ Node<E> head; int size; public boolean add(E newEntry){ if (head==null) head = new Node<E>(newEntry); else{ //note package access requirement getNodeAt(size).next = new Node<E>(newEntry); size++; return true; } …}
Package Model - getEntry
© 2009 Dr. Tim Margush
package ListPackage;
public class LList<E>{
//illustrates package access to member public boolean getEntry(int position){ if (position>=0 && position<size) return getNodeAt(position).data; else return null; }}
Circular ListsHead and Tail Access
• List keeps reference to last Node– Facilitates add to end since we always know where
the last node is• Last Node points to first node– Otherwise, how would we know where the first
Node was located?• This can also be done with a standard list
maintaining a head and tail pointer
© 2009 Dr. Tim Margush
Small Lists
© 2009 Dr. Tim Margush
0 1
2
a
b
a
Circular Traverse
© 2009 Dr. Tim Margush
public void display(){ if (last==null) return; Node current = last; do{ current = current.next; System.out.println(current.data); while(current!=last);}
3
ba c
getNodeAt
© 2009 Dr. Tim Margush
private Node getNodeAt(int position){ //node at 0 or size is the last node (or null if empty) if (position<0||position>size) return last; Node current = last.next; while(position-- > 0) current = current.next; return current;}
3
ba c
Circular Add
• Add to end is to add between the last and first– Insert between last and first• last = last.next = new Node(x, last.next);
• If empty, last.next is illegal– New node is last and points to self• last.next = last = new Node(x);
• Adding at the front is even easier– Assuming not empty• last.next = new Node(x, last.next);
© 2009 Dr. Tim Margush
Circular - add
© 2009 Dr. Tim Margush
public boolean add(E newEntry){ if (last==null) last.next = last = new Node(newEntry); else last = last.next = new Node(newEntry, last.next); size++;}public boolean add(int newLoc, E newEntry){ if (newLoc==size) //add to end case return add(newEntry); //adding somewhere other than at the end Node prev = getNodeAt(newLoc-1); prev.next = new Node(newEntry, prev.next); size++;}
Circular - remove
© 2009 Dr. Tim Margush
public E remove(int loc){ if (loc<0 || loc>=size) return null; Node prev = getNodeAt(loc-1); Node toRemove = prev.next; prev.next = toRemove.next; if (loc==size-1) last = prev; size--; if (size==0) last = null; return toRemove.data;}
Dummy Header Node
• First Node always exists as a placeholder, but is not used to store data– Node head = new Node(null);
• Eliminates special case of no previous node– getNodeAt(-1) returns the header Node.
© 2009 Dr. Tim Margush
Doubly-Linked• Each Node has a forward and backward link• Usually combined with circular list structure
with dummy header
© 2009 Dr. Tim Margush
private Node<E>{ private E data; private Node<E> prev, next; private Node(E newEntry){ data = newEntry; prev = next = this; //circular } private Node(E newEntry, Node<E> p, Node<E> n){ data = newEntry; prev = p; next = n; }}
Doubly-Linked - add
© 2009 Dr. Tim Margush
class DLCList<E> implements ListInterface<E>{ private Node head = new Node(null); //size and private Node class here public boolean add(newEntry){ Node last = head.prev; last.next = head.prev = new Node(newEntry,last,head); size++; return true; } public boolean add(int newLoc, E newEntry){ Node prev = getNodeAt(newLoc-1); Node after = prev.next; prev.next = after.prev = new Node(newEntry,prev,after); size++; return true; }
Doubly-Linked - remove
• No special cases!
© 2009 Dr. Tim Margush
public E remove(int loc){ Node toRemove = getNodeAt(loc); toRemove.prev.next = toRemove.next; toRemove.next.prev = toRemove.prev; size--; return toRemove.data;}
Doubly-Linked - getNodeAt
• Efficiently scan for location
© 2009 Dr. Tim Margush
private Node getNodeAt(int loc){ if(loc<-1 || loc>=size) return null; Node current = head; //location 0 or size+1 if(loc<size/2){ //scan forward int pos=0; while(pos++ < loc) current = current.next; }else{ //scan in reverse int pos = size+1; do current = current.prev; while(--pos > loc); } return current;}
Linked List
• Doubly-Linked List– Provides for forward or backward iteration– No linked list supports random access• getNodeAt is a non-trivial method
• Dummy header and circularity– Eliminates special cases and all null references at
the expense of one extra Node
© 2009 Dr. Tim Margush
java.util.LinkedList
• Implements List, Cloneable, Serializable• Uses a doubly-linked list backing store• Includes special methods that take advantage
of linked list structure– addFirst, addLast– getFirst, getLast– removeFirst, removeLast
© 2009 Dr. Tim Margush