1 / 75

Last Class

Last Class. Summary of Implementations. Collection. Set. SortedSet. Map. SortedMap. List. Queue. Comming up. ArrayList ArrayQueue ArrayDequeue DualArrayDequeue. Array based implementations for List and Queue. Lists versus Arrays. Lists. Arrays. get(i) and put(i,x).

Download Presentation

Last Class

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. LastClass

  2. Summary of Implementations Collection Set SortedSet Map SortedMap List Queue

  3. Comming up • ArrayList • ArrayQueue • ArrayDequeue • DualArrayDequeue Array based implementations for List and Queue

  4. Listsversus Arrays Lists Arrays • get(i) and put(i,x) • a[i] and a[i] = x • add(x) adds elements to the list • size is specified at time of creation - can't grow • size is specified at time of creation - can't grow • add(i,x) inserts and element into the list • remove(i) requires shifting a[i+1],a[i+2],...a[i+a.length-1] • remove(i) removes an element

  5. Using arrays to implement 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 publicclassArrayList<T> extendsAbstractList<T> { T[] a; // data goes in here intn; // the number of elements in the list ... }

  6. Using arrays to implement List • List element i is stored in a[i] public T get(inti) { if (i < 0 || i > n - 1) thrownewIndexOutOfBoundsException(); returna[i]; } public T set(inti, T x) { if (i < 0 || i > n - 1) throw new IndexOutOfBoundsException(); T y = a[i]; a[i] = x; returny; }

  7. Appending an element • To append an element x • grow a first if necessary • store x in a[n] and increment n publicboolean add(T x) { if (n + 1 > a.length) resize(); // increase length of a a[n++] = x; returntrue; }

  8. Inserting an element • To insert element i • Grow a if necessary • shift • Increment n a b c d e add(1,x) a x b c d e publicvoid add(inti, T x) { if (n + 1 > a.length) resize(); for (int j = n; j > i; j--) a[j] = a[j-1]; a[i] = x; n++; }

  9. Removing an element • To remove element i • shift • decrement n • shrink a if desired a x b c d e remove(1) a b c d e public T remove(inti) { T x = a[i]; for (intj = i; j < n-1; j++) a[j] = a[j+1]; n--; if (a.length >= 3*n) resize(); returnx; }

  10. Growing the array a - first try • To grow a • allocate a larger array b • copy everything into b protectedvoid resize() { T[] b = makeArray(n+1); for (inti = 0; i < n; i++) { b[i] = a[i]; } a = b; }

  11. Growing the array a - first try • 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 List<Integer> l = newMyArrayList<Integer>(); for (inti = 0;i < n; i++) { l.add(new Integer(i)); ...

  12. 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

  13. 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.

  14. Growing the array a – second try • Grow the array faster, so that we have to copy less often protectedvoid resize() { T[] b = makeArray(2*n); for (inti = 0; i < n; i++) { b[i] = a[i]; } a = b; }

  15. Growing the array a – second try • 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 How many elements are copied during a sequence of n add operations?

  16. How much is 1+2+4+8+...+2r-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 1

  17. 1/2 < 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/2

  18. 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/4 1/2 + 1/4

  19. 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/2 + 1/4 + 1/8 < 1 1 1/8 1/2 + 1/4 + 1/8

  20. 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/2 + 1/4 + 1/8 + 1/16 < 1 1 1/16 1/2 + 1/4 + 1/8 + 1/16

  21. 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/2 + 1/4 + 1/8 + 1/16 + 1/2r < 1 1 1/2r 1/2 + 1/4 + 1/8 + 1/16 + ... + 1/2r

  22. Recall: (i) j= 1 + i + i2 + … + ir-1 = (ir-1)/(i-1) Geometric Series • Substituting i=2 • (2) j = 1 + 2 + 22 + … + 2 r-1 = (2 r-1)/(2-1) = 2r-1

  23. Doubling works well • 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 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.

  24. Doubling versus Incrementing • We save a lot by using doubling • O(n) copy operations versus O(n2) copy operation

  25. Shrinking • 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 How good are grow() and shrink() when we have both add()and remove()operations?

  26. Amortized analysis of grow() and shrink() • How many elements are copied from one array to another during a sequence of madd and remove operations? • 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

  27. Amortized analysis of grow() • 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? Then: Now: • 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

  28. Amortized analysis of shrink() • 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 Then: Now: • 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

  29. Recap • The total number of array elements copied by grow() is at most twice the number of add() operations • 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

  30. Summary Theorem • 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(). • Corollary (Stack Theorem): Starting with an empty MyArrayList, a sequence of m add(x) and remove(size()-1) operations takes O(m) time. Stacks

  31. Practical Considerations 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 System.arraycopy(a, ia, b, ib, n)

  32. System.arraycopy (examples) publicvoid add(inti, T x) { if (n + 1 > a.length) grow(); System.arraycopy(a, i, a, i+1, n-i); a[i] = x; n++; } protectedvoid grow() { T[] b = f.newArray(a.length*2); System.arraycopy(a, 0, b, 0, n); a = b; }

  33. System.arraycopy (examples) public T remove(inti) { T x = a[i]; System.arraycopy(a, i+1, a, i, n-i-1); n--; shrink(); returnx; } protectedvoid shrink() { if (n > 0 && n < a.length / 3) { T[] b = f.newArray(n*2); System.arraycopy(a, 0, b, 0, n); a = b; } }

  34. Summary • MyArrayList:(JCF's ArrayList) • 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

  35. Summary • MyArrayList is a bit wasteful of space • It might use an array of length 2n to store n elements of data • 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

  36. Next Queue First in First out (FIFO)

  37. ArrayQueue A queue would be easy to implement if we had an infinite array ... ... a b c d e f j j + (n-1) publicboolean offer(T x) { a[j+n] = x; n++; returntrue; } public T poll() { T x = a[j]; j++; n--; returnx; }

  38. 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 e f a b c d (j+ n-1)% a.length j

  39. 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} e f a b c d (j+ n-1)% a.length j

  40. ArrayQueue • 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] publicclassArrayQueue<T> extendsAbstractQueue<T> { T[] a; intj; intn; ... }

  41. ArrayQueue- offer(x) [add(x)] • offer(x) [add(x)] • increase length of a if necessary • store x at a[(j+n)%a.length] • increment n publicboolean offer(T x) { if (n + 1 > a.length) grow(); a[(j+n) % a.length] = x; n++; returntrue; }

  42. ArrayQueue- poll() [remove()] • poll(), remove() • Return value in a[j] • increment j (mod a.length) and decrement n public T peek() { T x = null; if (n > 0) { x = a[j]; } returnx; } public T poll() { T x = null; if (n > 0) { x = a[j]; j = (j + 1) % a.length; n--; shrink(); } returnx; }

  43. Growing • grow() and shrink() are a bit trickier than before c d e f a b j a b c d e f j protectedvoid grow() { T[] b = f.newArray(a.length * 2); for (intk = 0; k < n; k++) b[k] = a[(j+k) % a.length]; a = b; j = 0; }

  44. Shrinking a b c a b c c a b protectedvoid shrink() { if (n > 0 && n ≤ a.length / 4) { T[] b = f.newArray(n * 2); for (intk = 0; k < n; k++) b[k] = a[(j+k) % a.length]; a = b; j = 0; } } a b c

  45. Summary Theorem • Theorem: • An ArrayQueue can perform a sequence of moffer(), 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() • Theorem: • A bounded ArrayQueue can perform each of offer(), add(), poll(), and remove() operations in constant time per operation.

  46. ArrayDeque • An ArrayDeque uses modular arithmetic to implement the List interface. • Why? • 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 ... ... a b c d e f j j+n-1

  47. ArrayDequeueget(i) and set(i,x) • Get and set are easy (bounds-checking omitted) public T get(inti) { returna[(j+i)%a.length]; } public T set(inti, T x) { T y = a[(j+i)%a.length]; a[(j+i)%a.length] = x; returny; }

  48. ArrayDequeueadd(i,x) • Decide whether it's better to • shift elements 0,...,ileft; or • shift elements i+1,...,size()-1 right ... ... a b c d e f add(2,x); ... ... a b x c d e f ... ... a b c d e f j+n add(4,x); j-1 ... ... a b c d x e f

  49. ArrayDequeueadd(i,x) publicvoid add(inti, 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++; }

  50. ArrayDequeueremove(i) • remove(i) is similar • if (i ≤ size()/2) then shift elements 0,...,i-1 right • else shift elements i+1,...,size()-1 left ... ... a b c d e f remove(2); ... ... a b d e f ... ... a b c d e f j+1 j+n-2 remove(4); ... ... a b c d f

More Related