Post on 15-Jan-2016
1
Lists
2
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
3
List: a sequence of cells in which each cell contains– a data item of type Object– a reference to the next cell
in the sequence (null if this 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.
24 -7 87 78
Array:
lc
0 1 2 3
02
our symbol for null
a0aa0
Lista1
24 a6
a1
-7 a8
a6
87 a2
a8
78
a21
3
4
Class ListCell/** 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 }
/** Set next cell to n public void setNext(ListCell n) {//… called rplacd}} This is how we draw ListCells
24 a6
a1
a1
ListCelldatum 24
next a6
ListCell(Object, ListCell)
getDatum() getNext()
setDatum(Object)
setNext(ListCell)
5
Class ListCell
/** 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; }
/** Set value to ob */ public void setDatum(Object ob) { datum= ob; }
/** Set next cell to n public void setNext(ListCell n) { next= n; }}
6
Building a listInteger t= new Integer(24);Integer s= new Integer(-7);Integer e= new Integer(87);
ListCell p= new ListCell(e,null);
p= new ListCell(s,p);
p= new ListCell(t,p);
// Store in p a list 24, -7, 87
Note: assignment of form p = new ListCell(s,p); does notcreate a circular list.
p a587
a5
87
a5
p a6 87 a5
a6
87
a5
p a6 87 a5
a6
24 a6
a7
7
Building a list
Integer t = new Integer(24);Integer s = new Integer(-7);Integer e = new Integer(87);
// Store in p a list of 24, -7, 87
ListCell p = new ListCell(t, new ListCell(s, new ListCell(e,null)));
Another way:
87
a5
-7 a5
a6
24 a6
a7p a7
8
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()
87
a5
-7 a5
a6
24 a6
a7p a7
p.getDatum() p.getNext()
9
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);
87
a5
-7 a5
a6
24 a6
a7p a7
10
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;
}
87
a5
-7 a5
a6
24 a6
a7p a7
11
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.
12
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());}
13
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; /** 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) { … }
87
a5
-7 a5
a6
24 a6
a7
List with header
p a1head
a1
a7
14
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
87
a5
-7 a5
a6
24 a6
a7p1 a1
a1
head
a7
p2 b2b2
tail a5
head
a7
p3 c3c3
size
3
head
a7
search(ob)
What you put in a header depends
on the application.
15
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 listpublic void insertHead(Object ob);
// insert ob into front of this listpublic void insertTail(Object ob);
// delete ob from this list (if it is there)public void delete(Object ob);
16
Insertion into tail of list
public class List{private ListCell head;public void insertHead(Object ob) { head= new ListCell(ob,head) }… }
8787
a5
-7 a5
a6
24 a6
a7p a1
head
a1
a8
p.insertHead(new Integer(6));
6 a7
a8
17
Insertion into Tail of list
public class List{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; while (c.getNext() != null) c= c.getNext();
c.setNext(new ListCell(ob, null)); }
}
87
87 a9
a5
-7 a5
a6
24 a6
a7p a1
head
a1
a7
p.insertTail(new Integer(6));
6
a9
18
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……
87-7 a5
a6
24 a6
a7p a1
head
a1
a7 87
a5
19
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;
}
-7 a5
a6
24 a6
a7p a7
head
a1
a7 87
a5
20
Remove and return last item from list
Cases:• list is empty:
throw an exception
• list contains one element: change head
• list contains >2 elements: change next-to-last element
-7 a5
a6
24 a6
a7p a1
head
a1
a7 87
a5
p a1head
a1
null
p a1head
a1
a7
24
a7
21
Finding penultimate element of list
/** List size >= 2. Return nameof penultimate element */
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){c= scout;scout= scout.getNext();
}return c;
}
-7 a5
a6
24 a6
a7p a1
head
a1
a7 87
a5
“penultimate” means
“next to last”
22
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);return last.getDatum();
} -7 a5
a6
24 a6
a7
p a1head
a1
a7
87
a5
23
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.
-7 a5
a6
24 a6
a7p a1
head
a1
a7 87
a5
24
Recursive code for deletepublic class List{ 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; }}
25
Finding elemelement of list
/** 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) {
ListCell scout= head.getNext();/** 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;
}
-7 a5
a6
24 a6
a7p a1
head
a1
a7 87
a5
26
Iterative code for delete
// Delete ob from list, if therepublic 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; } // { 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());}
27
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.
24 a5
a6
-7 a6
a7p a1
head
a1
a7 87
a5
28
Recursive insertion
Use notation [f,n] to denote ListCell whose•datum is f•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
29
/** 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;}
}
30
/** 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;
}
31
Exercises
1. Write insert into a sorted list without recursion.
2. Write delete from a sorted list without recursion.
32
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; …..}
-7 a6
a7p a7
a7 24 a5
a6
a6 8
a5
33
• 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.
34
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