Last Class
-
Upload
jasmine-bolton -
Category
Documents
-
view
21 -
download
1
description
Transcript of Last Class
![Page 1: Last Class](https://reader036.fdocuments.us/reader036/viewer/2022062517/56813578550346895d9cdbb8/html5/thumbnails/1.jpg)
Last Class
![Page 2: Last Class](https://reader036.fdocuments.us/reader036/viewer/2022062517/56813578550346895d9cdbb8/html5/thumbnails/2.jpg)
2
InterfaceImplementation Technique
Hash table
Array Tree Linked list
Hash table + Linked list
Set HashSet TreeSet LinkedHashSet
Sorted Set TreeSet
List ArrayList LinkedList
Queue PriorityQueue LinkedList
Map HashMap TreeMap LinkedHashMap
Sorted Map
TreeMap
Summary of Implementations
Collection MapSet
List
Queue
SortedSet SortedMap
![Page 3: Last Class](https://reader036.fdocuments.us/reader036/viewer/2022062517/56813578550346895d9cdbb8/html5/thumbnails/3.jpg)
Comming up
Array based implementations for List and Queue
–ArrayList
–ArrayQueue
–ArrayDequeue
–DualArrayDequeu
e
![Page 4: Last Class](https://reader036.fdocuments.us/reader036/viewer/2022062517/56813578550346895d9cdbb8/html5/thumbnails/4.jpg)
Lists versus Arrays
Lists–a[i] and a[i] = x–get(i) and put(i,x)
Arrays
–add(x) adds elements to the list
–add(i,x) inserts and element into the list
– remove(i) removes an element
–size is specified at time of creation - can't grow–size is specified at time of creation - can't grow– remove(i) requires shifting a[i+1],a[i+2],...a[i+a.length-1]
![Page 5: Last Class](https://reader036.fdocuments.us/reader036/viewer/2022062517/56813578550346895d9cdbb8/html5/thumbnails/5.jpg)
Using arrays to implement List
public class ArrayList<T> extends AbstractList<T> { T[] a; // data goes in here int n; // the number of elements in the list ...}
• The ArrayList class implements a list as an array
• How?–Uses an array a, called a backing array–An integer n keeps track of the number of elements•At all times, n ≤ a.size
![Page 6: Last Class](https://reader036.fdocuments.us/reader036/viewer/2022062517/56813578550346895d9cdbb8/html5/thumbnails/6.jpg)
Using arrays to implement List
public T set(int i, T x) { if (i < 0 || i > n - 1) throw new IndexOutOfBoundsException(); T y = a[i]; a[i] = x; return y; }
public T set(int i, T x) { if (i < 0 || i > n - 1) throw new IndexOutOfBoundsException(); T y = a[i]; a[i] = x; return y; }
• List element i is stored in a[i]
public T get(int i) { if (i < 0 || i > n - 1) throw new IndexOutOfBoundsException(); return a[i];}
![Page 7: Last Class](https://reader036.fdocuments.us/reader036/viewer/2022062517/56813578550346895d9cdbb8/html5/thumbnails/7.jpg)
Appending an element
public boolean add(T x) { if (n + 1 > a.length) resize(); // increase length of a a[n++] = x; return true;}
• To append an element x–grow a first if necessary–store x in a[n] and increment n
![Page 8: Last Class](https://reader036.fdocuments.us/reader036/viewer/2022062517/56813578550346895d9cdbb8/html5/thumbnails/8.jpg)
Inserting an element
public void add(int i, T x) { if (n + 1 > a.length) resize();
for (int j = n; j > i; j--) a[j] = a[j-1]; a[i] = x; n++;}
b c d ea
b c d exa
add(1,x)
• To insert element i–Grow a if necessary–shift– Increment n
![Page 9: Last Class](https://reader036.fdocuments.us/reader036/viewer/2022062517/56813578550346895d9cdbb8/html5/thumbnails/9.jpg)
Removing an element
public T remove(int i) { T x = a[i]; for (int j = i; j < n-1; j++) a[j] = a[j+1]; n--; if (a.length >= 3*n) resize(); return x;}
• To remove element i–shift–decrement n–shrink a if desired b c d ea
b c d exa
remove(1)
![Page 10: Last Class](https://reader036.fdocuments.us/reader036/viewer/2022062517/56813578550346895d9cdbb8/html5/thumbnails/10.jpg)
Growing the array a - first try
protected void resize() { T[] b = makeArray(n+1); for (int i = 0; i < n; i++) { b[i] = a[i]; } a = b;}
• To grow a–allocate a larger array b–copy everything into b
![Page 11: Last Class](https://reader036.fdocuments.us/reader036/viewer/2022062517/56813578550346895d9cdbb8/html5/thumbnails/11.jpg)
Growing the array a - first try
List<Integer> l = new MyArrayList<Integer>();for (int i = 0; i < n; i++) { l.add(new Integer(i));...
• Increasing a.length by 1 at each step causes a lot of copying–when i=1, 1 element is copied from a to
b–when i=2, 2 elements are copied from a to
b–when i=3, 3 elements are copied from a to
b–when i=n-1, n-1 elements are copied from a to
b
![Page 12: Last Class](https://reader036.fdocuments.us/reader036/viewer/2022062517/56813578550346895d9cdbb8/html5/thumbnails/12.jpg)
Growing the array a - first try
How many element are copied from one array into another during a sequence of n add operations on an empty MyArrayList ?
1 + 2 + 3 + ... + (n-1)
n-1
n-1
n-1
n-1
n
n-1
Arithmetic series: 2n(n-1)/2
![Page 13: Last Class](https://reader036.fdocuments.us/reader036/viewer/2022062517/56813578550346895d9cdbb8/html5/thumbnails/13.jpg)
Result
Theorem (Incrementing a.length): During a sequence of n add operations on an
empty MyArrayList, exactly n(n-1)/2 elements are copied from one array into
another.
Theorem (Incrementing a.length): During a sequence of n add operations on an
empty MyArrayList, exactly n(n-1)/2 elements are copied from one array into
another.
![Page 14: Last Class](https://reader036.fdocuments.us/reader036/viewer/2022062517/56813578550346895d9cdbb8/html5/thumbnails/14.jpg)
Growing the array a – second try
protected void resize() { T[] b = makeArray(2*n); for (int i = 0; i < n; i++) { b[i] = a[i]; } a = b;}
• Grow the array faster, so that we have to copy less often
![Page 15: Last Class](https://reader036.fdocuments.us/reader036/viewer/2022062517/56813578550346895d9cdbb8/html5/thumbnails/15.jpg)
• When adding n elements into an empty
MyArrayList we get– an array of length 1 that gets copied into– an array of length 2 that gets copied into– an array of length 4 that gets copied into– an array of length 8 that gets copied into– ...– an array of length 2r-1 < n– an array of length 2r < 2n
Growing the array a – second try
How many elements are copied during a sequence of n add operations?
![Page 16: Last Class](https://reader036.fdocuments.us/reader036/viewer/2022062517/56813578550346895d9cdbb8/html5/thumbnails/16.jpg)
16
• How much is 1+2+4+8+...+2r-1
1
Geometric Series
– Claim: 1+2+4+8+...+2r-1 < 2r
– Proof (by picture): Dividing by 2r, we need to show• 1/2r + 1/2r-1 + ... + 1/8 + 1/4 + 1/2 < 1• 1/2 + 1/4 + 1/8 + ... + 1/2r-1 + 1/2r < 1
![Page 17: Last Class](https://reader036.fdocuments.us/reader036/viewer/2022062517/56813578550346895d9cdbb8/html5/thumbnails/17.jpg)
17
• 1/2 < 1
1
1/2
1/2
Geometric Series• How much is 1+2+4+8+...+2r-1
– Claim: 1+2+4+8+...+2r-1 < 2r
– Proof (by picture): Dividing by 2r, we need to show• 1/2r + 1/2r-1 + ... + 1/8 + 1/4 + 1/2 < 1• 1/2 + 1/4 + 1/8 + ... + 1/2r-1 + 1/2r < 1
![Page 18: Last Class](https://reader036.fdocuments.us/reader036/viewer/2022062517/56813578550346895d9cdbb8/html5/thumbnails/18.jpg)
• 1/2+ 1/4 < 1
Geometric Series• How much is 1+2+4+8+...+2r-1
– Claim: 1+2+4+8+...+2r-1 < 2r
– Proof (by picture): Dividing by 2r, we need to show• 1/2r + 1/2r-1 + ... + 1/8 + 1/4 + 1/2 < 1• 1/2 + 1/4 + 1/8 + ... + 1/2r-1 + 1/2r < 1
1
1/2 + 1/4
1/4
![Page 19: Last Class](https://reader036.fdocuments.us/reader036/viewer/2022062517/56813578550346895d9cdbb8/html5/thumbnails/19.jpg)
19
1
1/2 + 1/4 + 1/8
1/8
Geometric Series
• 1/2 + 1/4 + 1/8 < 1
• How much is 1+2+4+8+...+2r-1
– Claim: 1+2+4+8+...+2r-1 < 2r
– Proof (by picture): Dividing by 2r, we need to show• 1/2r + 1/2r-1 + ... + 1/8 + 1/4 + 1/2 < 1• 1/2 + 1/4 + 1/8 + ... + 1/2r-1 + 1/2r < 1
![Page 20: Last Class](https://reader036.fdocuments.us/reader036/viewer/2022062517/56813578550346895d9cdbb8/html5/thumbnails/20.jpg)
20
1
1/2 + 1/4 + 1/8 + 1/16
1/16
Geometric Series
• 1/2 + 1/4 + 1/8 + 1/16 < 1
• How much is 1+2+4+8+...+2r-1
– Claim: 1+2+4+8+...+2r-1 < 2r
– Proof (by picture): Dividing by 2r, we need to show• 1/2r + 1/2r-1 + ... + 1/8 + 1/4 + 1/2 < 1• 1/2 + 1/4 + 1/8 + ... + 1/2r-1 + 1/2r < 1
![Page 21: Last Class](https://reader036.fdocuments.us/reader036/viewer/2022062517/56813578550346895d9cdbb8/html5/thumbnails/21.jpg)
21
1
1/2 + 1/4 + 1/8 + 1/16 + ... + 1/2r
1/2r
Geometric Series
• 1/2 + 1/4 + 1/8 + 1/16 + 1/2r < 1
• How much is 1+2+4+8+...+2r-1
– Claim: 1+2+4+8+...+2r-1 < 2r
– Proof (by picture): Dividing by 2r, we need to show• 1/2r + 1/2r-1 + ... + 1/8 + 1/4 + 1/2 < 1• 1/2 + 1/4 + 1/8 + ... + 1/2r-1 + 1/2r < 1
![Page 22: Last Class](https://reader036.fdocuments.us/reader036/viewer/2022062517/56813578550346895d9cdbb8/html5/thumbnails/22.jpg)
22
• Recall:– (i) j = 1 + i + i 2 + … + i r-1 = (i r-1)/(i-1)
Geometric Series
• Substituting i=2– (2)
j = 1 + 2 + 22 + … + 2 r-1 = (2 r-1)/(2-1)
= 2r-1
![Page 23: Last Class](https://reader036.fdocuments.us/reader036/viewer/2022062517/56813578550346895d9cdbb8/html5/thumbnails/23.jpg)
• Recall that 2r < 2n
• The number of elements copied during n add operations on an empty MyArrayList is–1+2+4+...+2r-1 < 2r < 2n
Doubling works well
Theorem (Doubling a.length): During a sequence of n add operations on an
empty MyArrayList, a total of at most 2n elements are copied from one array to
another.
Theorem (Doubling a.length): During a sequence of n add operations on an
empty MyArrayList, a total of at most 2n elements are copied from one array to
another.
![Page 24: Last Class](https://reader036.fdocuments.us/reader036/viewer/2022062517/56813578550346895d9cdbb8/html5/thumbnails/24.jpg)
• We save a lot by using doubling–O(n) copy operations versus O(n2) copy operation
Doubling versus Incrementing
n n(n-1)/2 2n
10 45 20100 4 950 200
1 000 499 500 2 00010 000 49 995 000 20 000
100 000 4 999 950 000 200 0001 000 000 499 999 500 000 2 000 000
![Page 25: Last Class](https://reader036.fdocuments.us/reader036/viewer/2022062517/56813578550346895d9cdbb8/html5/thumbnails/25.jpg)
• When n << a.length, a lot of space is wasted
• Each time an element is removed, we resize– if n < a.length/3 then we resize to 2*n
Shrinking
How good are grow() and shrink() when we have both add() and remove() operations?
![Page 26: Last Class](https://reader036.fdocuments.us/reader036/viewer/2022062517/56813578550346895d9cdbb8/html5/thumbnails/26.jpg)
• How many elements are copied from one array to another during a sequence of m add and remove operations?
Amortized analysis of grow() and shrink()
• Answer: It depends on the exact sequence of operations–We want an upper bound that holds for any sequence of m add() and remove() operations
![Page 27: Last Class](https://reader036.fdocuments.us/reader036/viewer/2022062517/56813578550346895d9cdbb8/html5/thumbnails/27.jpg)
• Suppose grow() is now reallocating array a– n = a.length elements are being copied from a
to b– How many add() operations occurred since the
last time a was reallocated?
Amortized analysis of grow()
– At least a.length/2 add() operations occurred since then– The number of copies caused by grow() is at
most twice the number of add() operations
Then:Now:
![Page 28: Last Class](https://reader036.fdocuments.us/reader036/viewer/2022062517/56813578550346895d9cdbb8/html5/thumbnails/28.jpg)
• Suppose shrink() is now reallocating array a– n < a.length / 3 elements are being copied– how many remove() operations occurred since
the last time a was reallocated
Amortized analysis of shrink()
– at least (a.length/2) - (a.length/3) = a.length/6– remove() operations have occurred since then– The number of copies caused by shrink() is at
most twice the number of remove() operations
Then:Now:
![Page 29: Last Class](https://reader036.fdocuments.us/reader036/viewer/2022062517/56813578550346895d9cdbb8/html5/thumbnails/29.jpg)
• The total number of array elements copied by grow() is at most twice the number of add() operations
Recap
• The total number of array elements copied by shrink() is at most twice the number of remove() operations
• If we perform a total of m add() and remove() operations then the total number of array elements copied by both grow() and shrink() is at most 2m
![Page 30: Last Class](https://reader036.fdocuments.us/reader036/viewer/2022062517/56813578550346895d9cdbb8/html5/thumbnails/30.jpg)
• Theorem: Starting with an empty MyArrayList, a sequence of m add() and remove() operations results in a total of at most 2m elements being copied from one array to another by grow() and shrink().
Summary Theorem
• Corollary (Stack Theorem): Starting with an empty MyArrayList, a sequence of m add(x) and remove(size()-1) operations takes O(m) time.
Stacks
![Page 31: Last Class](https://reader036.fdocuments.us/reader036/viewer/2022062517/56813578550346895d9cdbb8/html5/thumbnails/31.jpg)
Array-based lists do a lot of copying and moving of data–A for loop is not the best way to do this–Fastest methods use machine parallelism and special machine instructions to speed up copying and moving of blocks of array data– In Java, we can use
Practical Considerations
System.arraycopy(a, ia, b, ib, n)
![Page 32: Last Class](https://reader036.fdocuments.us/reader036/viewer/2022062517/56813578550346895d9cdbb8/html5/thumbnails/32.jpg)
protected void grow() { T[] b = f.newArray(a.length*2); System.arraycopy(a, 0, b, 0, n); a = b;}
public void add(int i, T x) { if (n + 1 > a.length) grow(); System.arraycopy(a, i, a, i+1, n-i); a[i] = x; n++;}
System.arraycopy (examples)
![Page 33: Last Class](https://reader036.fdocuments.us/reader036/viewer/2022062517/56813578550346895d9cdbb8/html5/thumbnails/33.jpg)
protected void shrink() { if (n > 0 && n < a.length / 3) { T[] b = f.newArray(n*2); System.arraycopy(a, 0, b, 0, n); a = b; }}
public T remove(int i) { T x = a[i]; System.arraycopy(a, i+1, a, i, n-i-1); n--; shrink(); return x;}
System.arraycopy (examples)
![Page 34: Last Class](https://reader036.fdocuments.us/reader036/viewer/2022062517/56813578550346895d9cdbb8/html5/thumbnails/34.jpg)
• MyArrayList: (JCF's ArrayList)
Summary
− A list implemented as an array that grows and shrinks
− Copying done by grow() and shrink() is proportional to number of add() and remove() operations− m add/remove ops. require at most 2m copy ops.●Fast get(i), set(i,x) for any value of i●Fast remove(i) and add(i,x) when i ~ size()
−shifting data is costly when i << size()− Useful as a stack
![Page 35: Last Class](https://reader036.fdocuments.us/reader036/viewer/2022062517/56813578550346895d9cdbb8/html5/thumbnails/35.jpg)
• MyArrayList is a bit wasteful of space– It might use an array of length 2n to store n
elements of data
Summary
• Not suitable for real-time applications (even as a stack)– Even though operations take constant time on
average [m operations take O(m) time], some operations [that reallocate a] take a long time.
• Works well as a stack, but not fast for– add(i,x) or remove(i) where i is small (near the
front)– Too much shifting of data
![Page 36: Last Class](https://reader036.fdocuments.us/reader036/viewer/2022062517/56813578550346895d9cdbb8/html5/thumbnails/36.jpg)
Next
Queue
First in First out (FIFO)
![Page 37: Last Class](https://reader036.fdocuments.us/reader036/viewer/2022062517/56813578550346895d9cdbb8/html5/thumbnails/37.jpg)
A queue would be easy to implement if we had an infinite array
d e fa b c...
..
.
ArrayQueue
public T poll() { T x = a[j]; j++; n--; return x;}
public boolean offer(T x) { a[j+n] = x; n++; return true;}
j j + (n-1)
![Page 38: Last Class](https://reader036.fdocuments.us/reader036/viewer/2022062517/56813578550346895d9cdbb8/html5/thumbnails/38.jpg)
Circular Array
• We don't have infinite arrays– But we do have arrays that can grow
• Use modular arithmetic to simulate an infinite array–wrap-around when we get to the end of the
array• Grow the array if the queue gets bigger than the array
da b ce f
(j+ n-1)% a.length
j
![Page 39: Last Class](https://reader036.fdocuments.us/reader036/viewer/2022062517/56813578550346895d9cdbb8/html5/thumbnails/39.jpg)
Modular Aritmetic
• "Clock arithmetic“– 8 + 5 ≡1 (mod 12)– (8 + 5) % 12 = 1• 8 + 5 = 13• 13 - 12 = 1
–% is the integer remainder operator• if x, y > 0 then (x % y) ϵ {0,...,y-1}
da b ce f
(j+ n-1)% a.length
j
![Page 40: Last Class](https://reader036.fdocuments.us/reader036/viewer/2022062517/56813578550346895d9cdbb8/html5/thumbnails/40.jpg)
ArrayQueue
public class ArrayQueue<T> extends AbstractQueue<T> { T[] a; int j; int n; ...}
• Represents a queue as an array a, and integers j and n– j ϵ {0,...,a.length-1} points to the head of the
queue–n is the number of elements stored in the
queue–elements stored at a[j], a[(j+1)%a.length], a[(j+2)%a.length], ... ,a[(j+n-1)%a.length]
![Page 41: Last Class](https://reader036.fdocuments.us/reader036/viewer/2022062517/56813578550346895d9cdbb8/html5/thumbnails/41.jpg)
ArrayQueue - offer(x) [add(x)]
public boolean offer(T x) { if (n + 1 > a.length) grow(); a[(j+n) % a.length] = x; n++; return true;}
• offer(x) [add(x)]– increase length of a if necessary–store x at a[(j+n)%a.length]– increment n
![Page 42: Last Class](https://reader036.fdocuments.us/reader036/viewer/2022062517/56813578550346895d9cdbb8/html5/thumbnails/42.jpg)
ArrayQueue - poll() [remove()]
public T peek() { T x = null; if (n > 0) { x = a[j]; } return x;}
• poll(), remove()–Return value in a[j]– increment j (mod a.length) and decrement n
public T poll() { T x = null; if (n > 0) { x = a[j]; j = (j + 1) % a.length; n--; shrink(); } return x;}
![Page 43: Last Class](https://reader036.fdocuments.us/reader036/viewer/2022062517/56813578550346895d9cdbb8/html5/thumbnails/43.jpg)
• grow() and shrink() are a bit trickier than before
Growing
da b c e f
fc d e a bj
j protected void grow() { T[] b = f.newArray(a.length * 2); for (int k = 0; k < n; k++) b[k] = a[(j+k) % a.length]; a = b; j = 0;}
![Page 44: Last Class](https://reader036.fdocuments.us/reader036/viewer/2022062517/56813578550346895d9cdbb8/html5/thumbnails/44.jpg)
a b c
a b c
a bc
a b c
Shrinking
protected void shrink() { if (n > 0 && n ≤ a.length / 4) { T[] b = f.newArray(n * 2); for (int k = 0; k < n; k++) b[k] = a[(j+k) % a.length]; a = b; j = 0; }}
![Page 45: Last Class](https://reader036.fdocuments.us/reader036/viewer/2022062517/56813578550346895d9cdbb8/html5/thumbnails/45.jpg)
• Theorem: – An ArrayQueue can perform a sequence of
m offer(), add(), poll(), and remove() operations in O(m) time.– If an upper-bound on the size of the queue is
known in advance, then we can eliminate need for grow() and shrink()
Summary Theorem
• Theorem: – A bounded ArrayQueue can perform each of
offer(), add(), poll(), and remove() operations in constant time per operation.
![Page 46: Last Class](https://reader036.fdocuments.us/reader036/viewer/2022062517/56813578550346895d9cdbb8/html5/thumbnails/46.jpg)
• An ArrayDeque uses modular arithmetic to implement the List interface.
ArrayDeque
• Why?
d e fa b c...
..
.
j j+n-1
– This allows modifications to be fast if they are• close to the end of the list– shift right and increment n
• close to the beginning of the list– shift left, decrement j, and increment n
![Page 47: Last Class](https://reader036.fdocuments.us/reader036/viewer/2022062517/56813578550346895d9cdbb8/html5/thumbnails/47.jpg)
ArrayDequeue get(i) and set(i,x)
public T get(int i) {
return a[(j+i)%a.length];}
• Get and set are easy (bounds-checking omitted)
public T set(int i, T x) {
T y = a[(j+i)%a.length]; a[(j+i)%a.length] = x;
return y;}
![Page 48: Last Class](https://reader036.fdocuments.us/reader036/viewer/2022062517/56813578550346895d9cdbb8/html5/thumbnails/48.jpg)
ArrayDequeue add(i,x)
• Decide whether it's better to–shift elements 0,...,i left; or–shift elements i+1,...,size()-1 right
48
d e fa b c...
..
.
d e fxa b c...
..
.
add(2,x);
d e fa b c...
..
.
d x e fba c...
..
.
add(4,x);
j-1 j+n
![Page 49: Last Class](https://reader036.fdocuments.us/reader036/viewer/2022062517/56813578550346895d9cdbb8/html5/thumbnails/49.jpg)
public void add(int i, T x) { if (n+1 > a.length) grow(); if (i < n/2) { // shift elements left j = (j == 0) ? a.length - 1 : j - 1; for (int k = 0; k < i-1; k++) a[(j+k)%a.length] = a[(j+k+1)%a.length]; } else { // shift elements right for (int k = n; k > i; k--) a[(j+k)%a.length] = a[(j+k-1)%a.length]; } a[(j+i)%a.length] = x; n++;}
ArrayDequeue add(i,x)
![Page 50: Last Class](https://reader036.fdocuments.us/reader036/viewer/2022062517/56813578550346895d9cdbb8/html5/thumbnails/50.jpg)
ArrayDequeue remove(i)• remove(i) is similar– if (i ≤ size()/2) then shift elements 0,...,i-1 right–else shift elements i+1,...,size()-1 left
50
d e fa b c...
..
.
d e fa b...
..
.
remove(2);
d e fa b c...
..
.
d fba c...
..
.
remove(4);
j+1
j+n-2
![Page 51: Last Class](https://reader036.fdocuments.us/reader036/viewer/2022062517/56813578550346895d9cdbb8/html5/thumbnails/51.jpg)
public T remove(int i) { T x = a[(j+i)%a.length]; if (i < n/2) {// shift elements right for (int k = i; k > 0; k--) a[(j+k)%a.length] = a[(j+k-1)%a.length]; j = (j + 1) % a.length; } else {// shift elements left for (int k = i; k < n-1; k++) a[(j+k)%a.length] = a[(j+k+1)%a.length]; } n--; shrink(); return x;}
ArrayDequeue remove(i)
![Page 52: Last Class](https://reader036.fdocuments.us/reader036/viewer/2022062517/56813578550346895d9cdbb8/html5/thumbnails/52.jpg)
• Theorem: – An ArrayDeque supports the operations• get(i) and put(i,x) in constant time per operation• add(i,x) and remove(i) in O(1 + min{i, size()-i}) amortized time per operation
ArrayDequeue Summary
![Page 53: Last Class](https://reader036.fdocuments.us/reader036/viewer/2022062517/56813578550346895d9cdbb8/html5/thumbnails/53.jpg)
• The % operator can be problematic– it is fairly slow, on most architectures•+, -, *, &, |, and ^ are all faster
– it doesn't handle negative values the way we expect• -1 % 12 = -1 [ we want 11]• -15 % 12 = -3 [ we want 9]
Practical Considerations
• We can replace % with branching– (j + k) % m equiv. to (j+k >= m) ? j+k-m : j+k– (j - k) % m equiv. to (j-k < 0) ? m-j+k : j-k• valid for j ϵ {0,...,m-1} and k ϵ {0,...,m}
![Page 54: Last Class](https://reader036.fdocuments.us/reader036/viewer/2022062517/56813578550346895d9cdbb8/html5/thumbnails/54.jpg)
• We can do better still if m (a.length) is a power of 2– In this case (j+k) % m = (j+k) & (m-1)•works for any values of k and j (even negative)•& is much faster than %•we can even store m-1 (=a.length-1) separately so we don't have to recompute it for every operation
Practical Considerations
• But this only works when a.length is a power of 2– The grow() method always doubles a.length– A modification to the shrink() method is needed
![Page 55: Last Class](https://reader036.fdocuments.us/reader036/viewer/2022062517/56813578550346895d9cdbb8/html5/thumbnails/55.jpg)
Example
00001000000
00000111111
00001000101
00000000101
00011000101
00000000101
(m=64)
(m-1=63)
(x=69=64+5)
(x&(m-1)=5)
(y=197=128+64+5=3*64+5)
(y&(m-1)=5)
![Page 56: Last Class](https://reader036.fdocuments.us/reader036/viewer/2022062517/56813578550346895d9cdbb8/html5/thumbnails/56.jpg)
• A DualArrayDeque is a data structure that turns two stacks into a dequeue.
DualArrayDequeue
• Main idea: Glue two stacks together back-to-back
0 1 2 3 4 5
front
back
public class DualArrayDeque<T> extends AbstractList<T> { List<T> front; List<T> back; ...}
push/poppush/pop
![Page 57: Last Class](https://reader036.fdocuments.us/reader036/viewer/2022062517/56813578550346895d9cdbb8/html5/thumbnails/57.jpg)
• The back stack stores elements in the same order they occur in the dequeue.
Ordering elements
• The front stack stores elements in reverse order
0 1 2 3 4 5
front
back
3 4 5
2 1 0front
back
push/poppush/pop
push/pop
push/pop
![Page 58: Last Class](https://reader036.fdocuments.us/reader036/viewer/2022062517/56813578550346895d9cdbb8/html5/thumbnails/58.jpg)
• The size of an DualArrayDeque is just the size of its two stacks.
DualArrayDequeue – size()
• Main idea: Glue two stacks together back-to-back
public int size() { return front.size() + back.size();}
3 4 5
2 1 0front
back
front.size()
back.size()
+
![Page 59: Last Class](https://reader036.fdocuments.us/reader036/viewer/2022062517/56813578550346895d9cdbb8/html5/thumbnails/59.jpg)
• For get(i) we need to determine if element i is stored in front or back.
DualArrayDequeue – get(i)
public T get(int i) { if (i < front.size()) { return front.get(front.size()-i-1); } else { return back.get(i-front.size()); }}
![Page 60: Last Class](https://reader036.fdocuments.us/reader036/viewer/2022062517/56813578550346895d9cdbb8/html5/thumbnails/60.jpg)
• The set(i,x) method is similar
DualArrayDequeue – set(i,x)
public T set(int i, T x) { if (i < front.size()) { return front.set(front.size()-i-1, x); } else { return back.set(i-front.size(), x); }}
![Page 61: Last Class](https://reader036.fdocuments.us/reader036/viewer/2022062517/56813578550346895d9cdbb8/html5/thumbnails/61.jpg)
• The add(i,x) is also similar.
DualArrayDequeue – add(i,x)
public void add(int i, T x) { if (i < front.size()) { front.add(front.size()-i, x); } else { back.add(i-front.size(), x); } balance();}
• Observe:• i = 0 → front.size()-1 → fast (push front)• i = size()-1 → back.size()-1 → fast (push back)
![Page 62: Last Class](https://reader036.fdocuments.us/reader036/viewer/2022062517/56813578550346895d9cdbb8/html5/thumbnails/62.jpg)
• The remove(i) method is similar– fast when i = 0 (pop front) or i = size()-1 (pop back)
DualArrayDequeue – remove (i)
public T remove(int i) { T x; if (i < front.size()) { x = front.remove(front.size()-i-1); } else { x = back.remove(i-front.size()); } balance(); return x;}
![Page 63: Last Class](https://reader036.fdocuments.us/reader036/viewer/2022062517/56813578550346895d9cdbb8/html5/thumbnails/63.jpg)
List<Integer> q = new DualArrayDeque<Integer>(Integer.class);... // some code that fills q upwhile (true) { q.add(x); q.remove(0);}
• This seems too easy–What happens when we try to use this as a
queue?• add(x) always appends to back• eventually remove(0) will empty front
DualArrayDequeue
3 4 5
2 1 0front
back
remove(0)
add(x)
– subsequent calls will translate to back.remove(0)»SLOW!
![Page 64: Last Class](https://reader036.fdocuments.us/reader036/viewer/2022062517/56813578550346895d9cdbb8/html5/thumbnails/64.jpg)
• This is why we call balance()
– If 3*front.size() < back.size() or
–3*back.size() < front.size()•rebalance: spread elements evenly between front and back
DualArrayDequeue
balance()
front
back
![Page 65: Last Class](https://reader036.fdocuments.us/reader036/viewer/2022062517/56813578550346895d9cdbb8/html5/thumbnails/65.jpg)
• a little tricker than it looks–when moving between front and back we have to reverse the order of elements
DualArrayDequeue – balance()
front
back
reverse
![Page 66: Last Class](https://reader036.fdocuments.us/reader036/viewer/2022062517/56813578550346895d9cdbb8/html5/thumbnails/66.jpg)
protected void balance() { int n = size(); if (3*front.size() < back.size()) { int s = n/2 - front.size(); List<T> l1 = newStack(); List<T> l2 = newStack(); l1.addAll(back.subList(0,s)); Collections.reverse(l1); l1.addAll(front); l2.addAll(back.subList(s, back.size())); front = l1; back = l2;} else if (3*back.size() < front.size()) { ... // code is similar}
ArrayDequeue - balance()
![Page 67: Last Class](https://reader036.fdocuments.us/reader036/viewer/2022062517/56813578550346895d9cdbb8/html5/thumbnails/67.jpg)
• size(), get(i), and set(i,x) each take constant time
DualArrayDeque - analysis
• add(i,x) and remove(i) take time–O(i + min{1, size()-i}) + time for balance()
• in the worst case, balance() moves size() elements– takes O(size()) time
• hopefully this doesn't happen too often
![Page 68: Last Class](https://reader036.fdocuments.us/reader036/viewer/2022062517/56813578550346895d9cdbb8/html5/thumbnails/68.jpg)
• Suppose balance() is performing rebalancing right now– Consider the situation right after the last time
balance() did some rebalancing.
Amortized analysis of balance()
– f0 = b0
– 3f1 = b1 [approximately]
now
thenf0 b0
f1 b1
![Page 69: Last Class](https://reader036.fdocuments.us/reader036/viewer/2022062517/56813578550346895d9cdbb8/html5/thumbnails/69.jpg)
• Claim: – front has gotten a lot smaller• lots of remove() operations.
– or back has gotten a lot bigger• lots of add() operations.
Amortized analysis of balance()
• Claim: – f0-f1 ≥ α(f1+b1) or b1-b0 ≥ α (f1+b1), for some
constant α > 0.• The total work done by balance() is O(f1+b1)
• The total number of add/remove operations since the last rebalance is at least a(f1+b1)
• The total work done by balance is proportional to the number of add/remove operations
![Page 70: Last Class](https://reader036.fdocuments.us/reader036/viewer/2022062517/56813578550346895d9cdbb8/html5/thumbnails/70.jpg)
• Theorem: Starting with an initially empty
DualArrayDeque and performing a sequence of
m add/remove operations,– add(i,x) and remove(i) take time•O(1 + min{i, size()-i}) + time for balance()
– the total time taken by balance() is O(m)
Summary of DualArrayDeque
• Theorem: Starting with an initially empty
DualArrayDeque, any sequence of m
pushFront, pushBack, popFront, and popBack operations takes a total of O(m) time
![Page 71: Last Class](https://reader036.fdocuments.us/reader036/viewer/2022062517/56813578550346895d9cdbb8/html5/thumbnails/71.jpg)
• Claim: Let w=f1+b1. Then f0-f1 ≥ aw or b1-b0 ≥ aw
Assume f0-f1 < aw [ f0 - aw < f1 ]
• b1 = 3f1 > 2f1 + f0 - aw = 2f1 + b0 - aw
• b1 - b0 > 2f1 - aw
•= f1 + b1/3 - aw
•> f1/3 + b1/3 - aw
•= w/3 - aw
•= aw for [a = 1/6]
Proof Claim
now
thenf0 b0
f1 b1
– f0 = b0
– 3f1 = b1 [ f1 = b1/3 ]
![Page 72: Last Class](https://reader036.fdocuments.us/reader036/viewer/2022062517/56813578550346895d9cdbb8/html5/thumbnails/72.jpg)
Alternate proof (potential function)
• Define the surplus– s = |front.size() - back.size()|
• Observe that, just after rebalancing,– s0 = |f0 - b0| = 0
• Just before the next rebalancing– s1 = |f1 - b1| = 2b1 ≥ (f1 + b1)/2
• Each add/remove operation increases s by at most 1
• Therefore, the number of add/remove operations
since last rebuilding is at least s1 - s0 = (f1+b1)/2
![Page 73: Last Class](https://reader036.fdocuments.us/reader036/viewer/2022062517/56813578550346895d9cdbb8/html5/thumbnails/73.jpg)
• ArrayList: Array-based implementation of a stack– grow() and shrink().
Summary
• ArrayDeque: Array-based implementation of a dequeue–grow() and shrink()–modular arithmetic (circular array)
• DualArrayDeque: Impl. of dequeue as two stacks– rebalance()–can use any kind of stack (ArrayList for example)
![Page 74: Last Class](https://reader036.fdocuments.us/reader036/viewer/2022062517/56813578550346895d9cdbb8/html5/thumbnails/74.jpg)
• All these structure offer constant time access–get(i), set(i) run in constant time
Pros and Cons
• Not suitable for real-time systems–Some individual operations can be very slow•grow(), shrink(), balance()
–Unless maximum size is known in advance• These can waste a lot of space–The array a can store as few as a.length/3 elements–a often stores only a.length/2 elements
![Page 75: Last Class](https://reader036.fdocuments.us/reader036/viewer/2022062517/56813578550346895d9cdbb8/html5/thumbnails/75.jpg)
• An array-based stack implementation that is– real-time [ in some languages ]–Only uses O(sqrt(size()) space beyond what is needed to store the data
Coming Up…
• Using these in a DualArrayDeque gives–a dequeue implementation that uses only O(sqrt(size()) space beyond what is needed to store the data