Transcript powerpoint

Lists
1
Overview
• Arrays
– Random access: 
– Fixed size: cannot grow on demand after creation: 
• Characteristics of some applications:
– do not need random access
– require a data structure that can grow and shrink
dynamically to accommodate different amounts of
data
 (Linked) Lists satisfy this requirement.
• We study
– list creation
– accessing elements in a list
– inserting elements into a list
– deleting elements from a list
2
Array:
a a0
List: a sequence of cells in
a0
which each cell contains
– a data item of type Object
– a reference to the next cell
in the sequence (null if this
0
1
2
3
24 -7 87 78
is last cell in the
sequence)
– empty list: null
• List is a sequential-access
data structure
– to access data in position n
of sequence, we must
access cells 0..n-1
• We will define a class ListCell
from which we will build lists.
a1 0
24
List
lc a1
a6
a8 2
87
a6 1
-7
our symbol
for null
a8
a2
a2 3
78
3
/** An instance is a cell of a list, with a value
and a name of another cell */
public class ListCell {
protected Object datum; // value of cell
protected ListCell next; // name of next cell
//(null if none)
/** Constructor: cell with value ob and next cell n */
public ListCell(Object ob, ListCell n){ …
/** = the value in this cell */
public Object getDatum() {//sometimes called car}
/** = name of next cell (none if none)*/
public ListCell getNext() {// … called cdr}
/** Set value to ob */
public void setDatum(Object ob) {// … called rplaca }
Class ListCell
a1
ListCell
datum 24
next
a6
ListCell(Object, ListCell)
getDatum() getNext()
setDatum(Object)
setNext(ListCell)
a1
24
a6
/** Set next cell to n
public void setNext(ListCell n) {//… called rplacd}
This is how we draw ListCells
}
4
/** Instance: a cell of list, with a value and a name of a cell */
public class ListCell {
private Object datum; // value of cell
private ListCell next; // name of next cell (null if none)
/** Constructor: cell with value ob and next cell n */
public ListCell(Object ob, ListCell n) { datum= ob; next= n; }
/** = the value in this cell */
public Object getDatum() { return datum; }
/** = name of next cell (none if none)*/
public ListCell getNext() { return next; }
Class ListCell
/** Set value to ob */
public void setDatum(Object ob) { datum= ob; }
/** Set next cell to n
public void setNext(ListCell n) { next= n; }
}
5
// Store in p a list 24, -7, 87
Integer t= new Integer(24);
Integer s= new Integer(-7);
Integer e= new Integer(87);
Building a list
a5
p a5
87
ListCell p= new ListCell(e,null);
a6
p= new ListCell(s,p);
p a6
87
a5
a5
87
p= new ListCell(t,p);
a6
a7
p a6
24
a6
87
a5
a5
87
Note: assignment of form p = new ListCell(s,p); does not
create a circular list.
6
Building a list
Integer t = new Integer(24);
Integer s = new Integer(-7);
Integer e = new Integer(87);
Another way:
// Store in p a list of 24, -7, 87
ListCell p = new ListCell(t, new ListCell(s, new ListCell(e,null)));
a6
p a7
a7
24
-7
a5
a6
a5
87
7
Accessing list elements
• Lists are sequential-access data structures.
– to access the contents of cell n in sequence,
you must access cells 0..n-1
• Accessing data in first cell: p.getDatum()
• Accessing data in second cell:
p.getNext().getDatum()
• Accessing next field in second cell:
p.getNext().getNext()
a7
p a7
24
p.getDatum()
a6
a6
-7
a5
a5
87
p.getNext()
8
Accessing list elements
Writing to fields in cells can be done the same way
//update data field of first cell
p.setDatum(new Integer(53)); ));
//update field of second cell
p.getNext().setDatum(new Integer(53));
//chop off third cell
p.getNext().setNext(null);
a7
p a7
24
a6
a6
-7
a5
a5
87
9
Access example: linear search
// = “ob is in list p”
public static boolean search(Object ob, ListCell p) {
// invariant: c is the name of a cell in list p (or null)
//
ob does not occur before cell c in list p
for (ListCell c= p; ci != null; c= c.getNext())
if (c.getDatum().equals(ob)) return true;
// { ob is not in the list }
return false;
}
a7
p a7
24
a6
a6
-7
a5
a5
87
10
Recursion on lists
• Recursion can be done on lists in a manner similar to
recursion on integers.
• Almost always
– base case: empty list
– recursive case: assuming you can solve problem on
(smaller) list obtained by eliminating first cell, write
down solution for list
• Many list problems can be solved very simply by using
this idea.
– Some problems, though, are easier to solve
iteratively.
11
Recursion example: linear search
• Base case: empty list
– return false
• Recursive case: non-empty list
– if data in first cell equals object ob, return true
– else return result of doing linear search on rest of list
// = “ob occurs in list p” */
public static boolean recSearch(Object ob, ListCell p) {
if (p == null) return false;
return p.getDatum().equals(ob) || recSearch(ob,p.getNext());
}
12
Some prefer to use a class List that is distinct from class ListCell.
A List object is like a head element that always exists even if list
itself is empty.
/** An instance is a list with a header */
class List {
private ListCell head;
List with header
/** Constructor: an instance is a list p
public List (ListCell p) {head= p; }
/** = the first value of list (0 if none)
public ListCell getHead() { … }
/** Set list to p */
public void setHead(ListCell p) { … }
p a1
a1
a7
head a7
24
a6
a6
-7
a5
a5
87
13
Variations of list with header
• Header can keep other info, e.g.
– reference to last cell of list
– number of elements in list
– search/insertion/ deletion
as instance methods
c3
b2
p2 b2
tail
What you put in a
header depends
on the
application.
p3 c3
a5
3
size
head a7
head a7
search(ob)
p1 a1
a1
a7
head a7
24
a6
a6
-7
a5
a5
87
14
Example of use of class List
• We write code to
– insert object into unsorted list
– delete the first occurrence of an object in an unsorted list.
• We use the class List to show how to use this class.
– It is just as easy to write code without the header element.
• Methods for insertion/deletion will be instance methods in
class List.
// insert ob into front of this list
public void insertHead(Object ob);
// insert ob into front of this list
public void insertTail(Object ob);
// delete ob from this list (if it is there)
public void delete(Object ob);
15
Insertion into tail of list
public class List{
private ListCell head;
public void insertHead(Object ob)
{ head= new ListCell(ob,head) }
… }
p.insertHead(new Integer(6));
a8
6
p a1
a7
a1
a7
head a8
24
a6
a6
-7
a5
a5
87
87
16
Insertion into Tail of list
public class List{
p.insertTail(new Integer(6));
private ListCell head;
public void insertTail(Object ob) {
if (head == null)
head = new ListCell(ob, null)
else {
// Store in c the name of the tail of the list
ListCell= head;
a9
while (c.getNext() != null)
c= c.getNext();
6
c.setNext(new ListCell(ob, null));
}
} p a1
a1
a7
head a7
24
a6
a6
-7
a5
a5
87
a9
87
17
Example of use of insert methods
List p= new List(null);
//List p is empty
p.insertHead(new Integer(-7));
//p contains -7
p.insertHead(new Integer(24));
//p contains 24, -7
p.insertTail(new Integer(87));
……
//p contains 24, -7, 87
p a1
a1
a7
head a7
24
a6
a6
-7
a5
a5
87
87
18
Remove first item from list
/** remove and return the first element of this list. Throw
RuntimeException if this list is empty. */
public Object deleteFirst(){
if (head == null)
{ throw new RuntimeException(“List is empty”); }
Object t= head.getDatum();
head= head.getNext();
return t;
}
p a7
a1
a7
head a7
24
a6
a6
-7
a5
a5
87
19
Remove and return last item from list
a1
Cases:
• list is empty:
throw an exception
p a1
a1
• list contains one element:
change head
p a1
head a7
a7
• list contains >2 elements:
change next-to-last element
p a1
a1
a7
head a7
24
head null
24
a6
a6
-7
a5
a5
87
20
/** List size >= 2. Return name
Finding penultimate
of penultimate element */
element of list
private Object getPenultimate() {
ListCell c= head;
ListCell scout= head.getNext();
/** invariant: c is name of a cell of the list,
c.getNext() is not null,
scout is the next cell following c */
while (scout.getNext() != null){
“penultimate”
c= scout;
means
scout= scout.getNext();
}
“next to last”
return c;
}
a1
a7
a6
a5
p a1
head a7
24
a6
-7
a5
87
21
Remove and return last item from list
/** remove and return last element of list.
Throw RuntimeException if list is empty */
public Object deleteLast(){
if (head == null)
throw new RuntimeException(“list is empty”);
}
if (head.getNext() == null) {
Object t= head.getDatum();
head= null;
return t;
}
// { list contains at least two elements }
ListCell penultimate= getPenultimate;
ListCell last= penultimate.getNext();
penultimate.setNext(null);
a6
return last.getDatum();
-7
a1
p a1
head a7
a7
24
a6
a5
a5
87
22
Delete object from list
• Delete first occurrence of an object ob from a list p.
• Idea of recursive code:
– If list p is empty, return null.
– If first element of p is ob, return rest of list p.
– Otherwise, return list consisting of first element of p, and
the list that results from deleting p from the rest of list p.
p a1
a1
a7
head a7
24
a6
a6
-7
a5
a5
87
23
public class List{
Recursive code for delete
private ListCell head;
// Delete first occur. of ob from list (if it is there)
public void delete(Object ob) {
head= deleteRec(ob, head);
}
// = list lc but with first occur. of ob deleted (if there)
private static ListCell deleteRec(Object ob, ListCell lc) {
if (lc == null) return null; // handle empty list
// { list lc is not empty }
if (l.getDatum().equals(ob))
return lc.getNext();
// { first element of lc is not ob }
lc.setNext(deleteRec(ob, lc.getNext()));
return l;
}
}
24
/** First element of list c is not ob. Return name of
element that precedes ob (or null if none) */
private Object getOb(ListCell c, Object ob) {
Finding elem
ListCell scout= head.getNext();
element of list
/** invariant: c is name of a cell of the list,
c.getDatum() is not ob.
scout is name of next element (null if none) */
while (scout != null && !scout.getDatum().equals(ob)){
c= scout;
scout= scout.getNext();
}
if (scout == null) return null;
return c;
}
a1
a7
a6
a5
p a1
head a7
24
a6
-7
a5
87
25
// Delete ob from list, if there
public void delete(Object ob) {
if (head == null) return;
// If first element is ob, remove it and return
if (head.getDatum().equals(o)) {
head= head.getNext();
return;
}
Iterative code
for delete
// { First element of list is not ob }
ListCell preceding= getOb(head, ob);
if (preceding == null)
return;
//splice out cell containing ob
preceding.setNext(preceding.getNext());
}
26
Insertion and deletion with sorted lists
• Assume that we have a list of Comparables sorted in increasing
order.
• We want to splice a new Comparable into this list, keeping new
list in sorted order as shown in figure.
• Code shows recursive code for insertion and deletion.
• We show code that uses class ListCell directly.
p a1
a1
a7
head a7
-7
a6
a6
24
a5
a5
87
27
Use notation [f,n] to denote ListCell whose
•datum is f
Recursive insertion
•next is n
Pseudo-code:
insert (Comparable c, ListCell l):
if l is null return new ListCell(c,null);
else
suppose l is [f,n]
if (c < f) return new ListCell(c,l);
else return new ListCell(f, insert(c,n));
Compactly:
insert(c,null) = [c,null]
insert(c,[f,n]) = [c,[f,n]]
if c < f
[f, insert(c,n)] if c >= f
28
/** lc is a sorted list. Insert c into it */
public static ListCell insert(Comparable c, ListCell lc) {
if (lc == null)
return new ListCell(c, lc);
// { list has at least one element }
if (c.compareTo(lc.getDatum()) < 0)
return new ListCell(c, lc);
// { first element of list is > c }
lc.setNext(insert(c,lc.getNext()));
return lc;
}
}
29
/** List lc is sorted.
Delete first occ. of c from it (if there) */
public static ListCell delete(Comparable c, ListCell lc) {
if ((l == null)
return null;
if (c.compareTo(lc.getDatum()) < 0)
return lc;
if (c.compareTo(lc.getDatum()) == 0)
return lc.getNext();
lc.setNext(delete(c,lc.getNext()));
return lc;
}
30
Exercises
1. Write insert into a sorted list without recursion.
2. Write delete from a sorted list without recursion.
31
Doubly-linked lists
• In some applications, it is convenient to have a ListCell
that references both its predecessor and its successor in
the list.
public class DLLCell {
private Object datum;
private DLLCell next;
private DLLCell previous;
a5
…..
a6 8
}
a7
p a7
a6
-7
a6
a7
24
a5
32
• In general, it is easier to work with doubly-linked lists than
with lists.
• For example, reversing a DLL can be done simply by
swapping the previous and next fields of each cell.
• Trade-off: DLLs require more space than singly-linked lists.
33
Summary
• Lists are sequences of ListCell elements
– recursive data structure
– grow and shrink on demand
– not random-access but sequential access data structures
• List operations:
– create a list
– access a list and update data
– change structure of list by inserting/deleting cells
• cursors
• Recursion makes perfect sense on lists. Usually
– base case: empty list, perhaps one-element list also
– recursive case: non-empty list
• Sub-species of lists
– list with header
– doubly-linked lists
34