Download Dr-Margush-06-07_LinkedLists

Survey
yes no Was this document useful for you?
   Thank you for your participation!

* Your assessment is very important for improving the workof artificial intelligence, which forms the content of this project

Document related concepts

Red–black tree wikipedia , lookup

Lattice model (finance) wikipedia , lookup

Quadtree wikipedia , lookup

Interval tree wikipedia , lookup

Binary tree wikipedia , lookup

Binary search tree wikipedia , lookup

Linked list wikipedia , lookup

B-tree wikipedia , lookup

Transcript
Linked Lists
Dr. Tim Margush
University 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
class Node<E>{
private E data;
private Node<E> next;
}
© 2009 Dr. Tim Margush
Inner Classes
• An inner class is defined inside another class
• A private inner class is only accessible by the
outer (enclosing) class
public class LList<E>
implements ListInterface<E>{
private class Node{
private E data;
private Node next;
}
private Node head;
© 2009 Dr. Tim Margush
Inner Classes
• Methods in both the inner and outer class
have complete access to all members of each
other, including private members
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();
© 2009 Dr. Tim Margush
Visualization of a Linked List
null
Node head;
© 2009 Dr. Tim Margush
Inner Class: Node
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;
}
}
}
…
© 2009 Dr. Tim Margush
Linked List Implementation
public 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 add
public 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, add
private 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
remove
public 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
package ListPackage;
//Everything in this class is package access
Class Node<E>{
E data;
Node<E> next;
Node(E newEntry){
this(newEntry, null);
}
Node(E newEntry, Node<E> n){
data = newEntry;
next = n;
}
}
© 2009 Dr. Tim Margush
Package Model - add
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;
}
…
}
© 2009 Dr. Tim Margush
Package Model - getEntry
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;
}
}
© 2009 Dr. Tim Margush
Circular Lists
Head 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
0
a
1
b
a
2
© 2009 Dr. Tim Margush
Circular Traverse
public void display(){
if (last==null) return;
Node current = last;
do{
current = current.next;
System.out.println(current.data);
while(current!=last);
}
a
b
3
© 2009 Dr. Tim Margush
c
getNodeAt
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;
}
a
b
3
© 2009 Dr. Tim Margush
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
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++;
}
© 2009 Dr. Tim Margush
Circular - remove
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;
}
© 2009 Dr. Tim Margush
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
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;
}
}
© 2009 Dr. Tim Margush
Doubly-Linked - add
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;
}
© 2009 Dr. Tim Margush
Doubly-Linked - remove
• No special cases!
public E remove(int loc){
Node toRemove = getNodeAt(loc);
toRemove.prev.next = toRemove.next;
toRemove.next.prev = toRemove.prev;
size--;
return toRemove.data;
}
© 2009 Dr. Tim Margush
Doubly-Linked - getNodeAt
• Efficiently scan for location
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;
}
© 2009 Dr. Tim Margush
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