1 / 52

Vectors, Lists and Sequence Stacks, queues, deques -- access elements only at the “ends”

Lectures 12-14-15-16. Vectors, Lists and Sequence Stacks, queues, deques -- access elements only at the “ends” Useful for applications that involve serially processing incoming data in some specific order Sequences, lists, vectors -- access elements in the “middle”, too

rose-ramsey
Download Presentation

Vectors, Lists and Sequence Stacks, queues, deques -- access elements only at the “ends”

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. Lectures 12-14-15-16 • Vectors, Lists and Sequence • Stacks, queues, deques -- access elements only at the “ends” • Useful for applications that involve serially processing incoming data in some specific order • Sequences, lists, vectors -- access elements in the “middle”, too • Useful for storing items that might be needed in any order

  2. The Vector ADT “before” “after” • The rank of an item in a vector is a count of the number of items that occur before it: Seattle Rome Montreal Paris • Vectors support the following methods:- size(), isEmpty() as usual-elemAtRank(r): Return the element with rank r; exception thrown if r<0 or r  size() -replaceAtRank(r,e): Replace the element at rank r with e and return the old element; exception thrown if r<0 or r  size() -insertAtRank(r,e): Insert a new element into S which will have rank r (and therefore ranks of subsequent elements will increase!);exception thrown if r<0 or r  size() -removeAtRank(r): Remove the element at rank r (and therefore ranks of subsequent elements will decrease); exception if r<0, r  size() Rank = 0 1 2 3

  3. Vector interface public interface Vector { public int size();public boolean isEmpty(); public Object elemAtRank(int r) throws InvalidRankException;public Object replaceAtRank(int r, Object o) throws InvalidRankException; public void insertAtRank(int r, Object o) throws InvalidRankException; public Object removeAtRank(int r) throws InvalidRankException; }

  4. Implementing Vectors with Arrays … public class ArrayVector implements Vector { … protected int N; // max capacity protected int n; // no. elements stored protected Object S[]; public ArrayVector(int capacity) { N = capacity; n = 0; S = new Object[N]; } … } used inactive rank(S[i])  i

  5. Some pseudo code For simplicity,exception-throwingcode not shown Algorithm elemAtRank(r): return S[r]; Algorithm replaceAtRank(r,e): x = elemAtRank(r); S[r]=e; return x; shift elements to the rightin order to squeeze “e” in here Algorithm insertAtRank(r,e): for i = n - 1, n - 2, ... , r do S[i+1]  s[i] S[r]  e n  n + 1 Algorithm removeAtRank(r): e  S[r] for i = r, r + 1, ... , n - 2 do S[i]  S[i + 1] n  n - 1 return e shift elements left tofill the gap left by e here

  6. Array-Based Implementation (contd.) • Time complexity of the various methods: remember, O(1) means “constant” (independent of n) Ouch!

  7. Problems with ArrayVector • 1. As just mentioned, some methods are expensive [O(n) complexity instead of O(1)]; we’ll deal with this later • 2. Predefined fixed capacity.One solution: “extendable(‘self-extending’) arrays”: if we ever run out of room, just create more!

  8. Extendable arrays • 1. During initialization, use fixed capacity as before (either application-supplied argument or some default value) • 2. When run out of room, allocate a new array of size (say) double the current size; copy over all the old elements to the new array • 3. Carry on as before…. • (4. Could also clean up wasted space if the vector is persistently under-capacity; but we won’t bother)

  9. ExtendableArrayVector class ExtendableArrayVector extends ArrayVector { // all we need to do is overload one method! public insertAtRank(int r, Object o) { if (n = = N) { // over capacity! N *= 2; Object S2[] = new Object[N]; for (int i=0; i<n; i++) S2[i]=S[i]; S = S2; } // now the original implementation does the job! super.insertAtRank(r,o); // call ArrayVector’s method } } See “Vector” demo for complete details

  10. Linked-list implementation of Vector • A second problem with the Array implementation is the need to slide elements during insert & remove -> causes O(n) [instead of O(1)] performance • Sliding not needed if we use a doubly-linked listpublic class LinkedListVector implements Vector { private DLNode header; private DLNode trailer; public LinkedListVector() { header = new DLNode(null,null,null); trailer = new DLNode(null,header,null); header.setNext(trailer); } } …

  11. Vector Implementation with a Doubly Linked List 1. the list before insertion 3. after insertion: 2. creating a new node

  12. Some Java public void insertAtRank (int r, Object o) throws InvalidRankException { if (r < 0 || r > size()) throw new InvalidRankException() DLNode next = nodeAtRank(r); // the new node will be right before ‘next’ DLNode prev = next.getPrev(); // the new node willl be right after ‘prev’ DLNode node = new DLNode(o, prev, next); // new node knows about its next & prev. Now // we tell next & prev about the new node. next.setPrev(node); prev.setNext(node); size++; }

  13. Deletion from Doubly Linked List the list before deletion: deleting a node after deletion:

  14. More Java public Object removeAtRank (int r) throws InvalidRankException { if (r < 0 || r > size()-1) throw new InvalidRankException(); DLNode node = nodeAtRank(rank); // node to be removed DLNode next = node.getNext(); // node before node to be removed DLNode prev = node.getPrev(); // node after node to be removed prev.setNext(next); next.setPrev(prev); size--; return node.getElement(); // returns the element of the deleted node }

  15. One last Java detail… • code for finding the node at a given rank r private DLNode nodeAtRank (int r) { DLNode node; // start at the node closest to the desired rank if (r <= size()/2) { //scan forward from header node = header.getNext(); for (int i=0; i < r; i++) node = node.getNext(); } else { // scan backward from trailer node = trailer.getPrev(); for (int i=0; i < size()-r-1 ; i++) node = node.getPrev(); } return node; } very common“pointer walking”expression either way, as many as n/2 iterations of this loop, therefore this method is O(n). Therefore….

  16. LinkedList Vector- Analysis • Time complexity of the various methods: O(n)O(n) Ouch! Compare with slide #7Oops, now all methods run slowly!

  17. Vector Summary • Simple Vector ADT - access/remove elements by “rank” • Leads to simple array-based implementation • 2 problems: • Q1. Can we get unlimited capacity? - yes - use “extendable” array that creates more space on demand as needed • Q2. Can we avoid shifting elements during insert/remove? - ?? - linked lists save this shifting cost, but add new cost of needing to walk list to find elements by rank; overall, linked-list implementation is worse!

  18. Lecture 14 Lists • Lists are a generalization of Vectors:Instead of the “rank” of an element in a list; use the more generic notion of “position” of an element in a list • The goal: ensure that access/insert/remove methods run in O(1) time! a list of 5 words the dog sat on my cat position(the) is the first positionposition(cat) is the last positionposition(dog) is before position(sat) position(on) is after position(on)

  19. Position ADT • Positions are very simple “helper” data-type • One operation! element() returns the data-value element associated with the position (seem a bit like magic -- How can a Position possibly know?!?!! -- but it will all make sense soon…)

  20. List ADT size() & isEmpty() as usual…first() returns the Position of the first element throws InvalidPositionException if empty last() returns the Position of the last element throws InvalidPositionException if empty isFirst(p) is p the first position? isLast(p) is p the last position? before(p) return the Position immediately before p; throws InvalidPositionException if p is first after(p) return the Position immediately after p throws InvalidPositionException if p is last insertFirst(e) insert e at the first entry, and return the Position of this new first entry insertLast(e) insert e at the last entry, and return the Position of this new last entry insertBefore(p,e) insert e immediately before Position p and return Position object for e insertAfter(p,e) insert e immediately before Position p and return Position object for e remove(p) remove element at Position p; return the removed element Unlike ranks, note that Positions of ‘unaffected’ elements aren’t modified!

  21. Implementing Lists with Doubly Linked-Lists • pages 199-205: class NodeList implements List • Code in the book is somewhat more complicated than I’ve said so far • 3 kinds of exceptions instead of 1 • Details like determining that a Position is “valid” (ie, a member of this’s list, not some other list)

  22. Details interface Position { Object element(); } our linked lists will be built from node objects which will “double” as our Position objects: public class DNode implements Position { // page 199 // first, stuff related to Position private Object element; Object element() { return element; } // next, stuff related to linked list node private DNode next; private DNode prev; … }

  23. More details Why so complicated??!? Where went the distinction between abstract Positions and concrete Nodes?!!? The intent is that your application shouldn’t need to know that List is implemented using a linked list. But obviously there is a direct correspondence between Positions in the List abstraction, and nodes in the linked list implementation. So we’ll use a single class that serves both purposes, and use ‘private’ to prevent application for learning implementation-specific details. your application inside NodeList implementation your applicationcan interpretthese objectsonly as Positions DNode components for building linked lists

  24. NodeList analysis Horray!All methodsare fast(constant-time) O(1) all List methods (first, last, isFirst, isLast, before, after, replaceElement, swapElements, insertFirst, insertLast, insertBefore, insertAfter, remove) However, what if our application needs bothrank and position-based access.That’s where Sequence comes in…

  25. Lec 15 Sequences • Sequence = Vector  List • This week: - finish P6 - start P7 - finish Chapter 5 Next week: - finish P7 - start P8 - start Chapter 6

  26. Sequence • Provides both rank- and position-based access, and “bridge” methods for converting between them “sat” is at rank 2 “my” is at rank 4 0 1 2 3 4 5 the dog sat on my cat “dog” is in this position“cat” is in this position after rank 4 (“bridge”)

  27. Sequence ADT • Everything required for Vector and List,plus two new methods: • atRank(r) return the Position associated with the given rank • rankOf(p) return the rank associated with Position p

  28. Sequence Interface interface Sequence extends List, Vector { Position atRank(int r); int rankOf(Position p); } Multiple inheritance - this interface has two parents!?!?! Actually, Java permits only a very weak form: only interfaces can have multiple super-classes - ie, only “promises” can be inherited. Other languages (Lisp, C++, Smalltalk, …) allow classes to have multiple super-classes; ie, actual methods can be inherited from multiple parents.

  29. Interface vs class multiple inheritance interface X { int x(); String y(int a); void z(String u); } interface Y { String p(int a); double q(); void z(String u); } C must implement allthese methods;no problempromising z twice class C implements X, Y { … } class X { int x() {…} String y(int a) {…} void z(String u) {…} } class Y { String p(int a) {…} double q() {…} void z(String u) {…} } C inherits allthese methods… class C extends X, Y { } C c = … c.z(“fishfood”); which implementation ofz should be called?!?!! …but

  30. Implementing Sequence with Doubly Linked List G&T page 208 L14,pp 199-205 class NodeSequence extends NodeList implements Sequence (why do we need to specify both extends and implements?) • Inherited from NodeList • first, last, isFirst, isLast, before, after, replaceElement, swapElements, insertFirst, insertLast, insertBefore, insertAfter, remove • Defined in NodeSequence(not inherited) • atRank, rankOf, [next slide…] elementAtRank, [next slide…]insertAtRank, removeAtRank [p 208]

  31. NodeSequence [cont] both run in time O(n) ! • bridge methods Position atRank(int rank) [see p 208 for Java]repeat: jump from header, to header.next, to header.next.next, …,until ‘rank’ nodes have been passedreturn currrent node int rankOf(Position p)repeat jump from from p to p.prev, to p.prev.prev, …,until header node is encounteredreturn the number of nodes passed atRank(2) 0 1 2 p 3 2 1

  32. rankOf - Java int rankOf(Position p) { DNode n = (DNode) p;int rank = 0; while (n != header) { n = n.getPrev(); rank++; } return rank; } we know this Position is in fact a DNode, so this casting is OK

  33. NodeSequence [cont] • With bridge methods in place, the methods required by Vector are very simple:[exception-handling code omitted for simplicity] Object elemAtRank(int rank) { return atRank(rank).element() } void insertAtRank(int rank, Object element) { insertBefore(atRank(rank), element); } Object removeAtRank(int rank) { return remove(atRank(rank)); } Object replaceAtRank(int rank, Object element) { return replaceElement(atRank(rank),element); } [see p 208for details]

  34. Analysis of NodeSequence O(n)O(n) Vector methods Slow because bridge method atRank is slow! O(1) all List methods (first, last, isFirst, isLast, before, after, replaceElement, swapElements, insertFirst, insertLast, insertBefore, insertAfter, remove)

  35. Implementing Sequence with Array • The ArrayList -vs- NodeList implementations of List suggest that linked-lists implementations are inherently slow for rank-based access, and array-based implements are inherently slow for position-based access. Is this O(n) -vs- O(1) tradeoff is inevitable? • No … advanced data structures you’ll learn about in the future such as hash tables can give fast access in both cases… but they’re too complicated for now… • As a suggestion of things to come… ArraySequenceuses arrays instead of linked lists, but with a clever special ‘trick’ to improve complexity of some of the methods

  36. ArraySequence - naïve version class ArrayPosition implements Position{ Object A[]; index i; ArrayPosition(Object[] B, int j) {A=B; I=j;} Object element() {return A[i];} } ArrayPosition object for “on” A:  i: 3 0 1 2 3 4 5 the dog sat on my cat ArrayPosition object for “dog” A:  i: 1

  37. ArraySequence: inserting an element p • These ArrayPositions • Aren’t stored in the • ArraySequence; the • application must store • them for later use. A:  i: 0 A:  i: 2 A:  i: 3 A:  i: 4 A:  i: 5 A:  i: 6 0 1 2 3 4 5 the dog sat on my cat Sequence s = new ArraySequence(); … other elements inserted … Position p = s.insertLast(“cat”); s.insertBefore(p, “fat”);

  38. Insertion, continued p A:  i: 0 A:  i: 1 A:  i: 2 A:  i: 3 A:  i: 4 A:  i: 5 0 1 2 3 4 5 6 the dog sat on my cat Slide existing elements (just like ArrayVector.insertAtRank) Yikes!Need toincrementranks… But how??!?! A:  i: 0 A:  i: 1 A:  i:2 A:  i: 3 A:  i: 4 A:  i: 5 A:  i: 5 0 1 2 3 4 5 6 the dog sat on my fat cat

  39. ArraySequence.insertAtRank • Algorithm insertBefore(Position p, Object o) • For r = size(), size()-1, …, rankOf(p)+2, rankOf(p)+1: A[r] = A[r-1]; • A[r] = o; • size++ • // yikes! We need to update Positions corresponding to ranks #size down to #rankOf(p)+1 -- but the ArraySequence doesn’t keep a list of the Positions -- that’s the application’s responsibility! • Return new ArrayPosition(A,r); This naïve approach doesn’t work!!

  40. L16 Sequences, continued • Where are we? Vector - rank-based access array-based implementation - insert/remove are slow linked-list implementation - all methods slow! List - position-based access linked-list implementation - all methods fast! Sequence - both kinds of access linked-list implementation - as before, rank-based methods are slow started array-based implementation but hit dead-end to do: a better array-based implementation

  41. ArraySequence: Cleverer approach class ArrayPosition implements Position {int rank;Object element;ArrayPosition(int r, Object e) {rank=r; element=e;}Object element() {return element;} } element: “the” rank: 0 element: “dog” rank: 1 element: “sat” rank: 2 element: “on” rank: 3 element: “my” rank: 4 element: “cat” rank: 5 0 1 2 3 4 5

  42. Cleverer ArraySequence • Still need to shift elements during insert/remove. • But now… since the SequenceArray “remembers” the ArrayPositions it has “exported” to the application, there’s no problem to modify the ranks of the moved elements.

  43. ArraySequence vs NodeSequence: Analysis • OperationArrayNodesize, isEmpty O(1) O(1)atRank, rankOf, elemAtRankO(1) O(n)first, last, before, after O(1) O(1)replaceElement, swapElements O(1) O(1)replaceAtRank O(1) O(n)insertAtRank, removeAtRank O(n) O(n)insertFirst, insertLast O(1) O(1)insertAfter, insertBeforeO(n) O(1)remove O(n) O(1) There’s no free lunch… If you need these operations, use ArraySequence If you need these operations, use NodeSequence

  44. Application example: Sorting • Sorting: Given some sequence (Sally, John, Dave, Ellen, Pat), output a permutation of the elements in order (Dave, Ellen, John, Pat, Sally) • Dozens of algorithms; person-centuries of research • Well known result: the fastest possible sorting algorithm runs in time O(n· log n) to sort n items • A very simple algorithm: Bubble Sort - O(n2) • The point isn’t to build a great algorithm, but to show how the Sequence ADT might be used in practice

  45. Bubble sort First pass: Start at top, compare adjacent pairs, swap larger toward bottom if needed 10 8 1 4 6 8 10 1 4 6 8 1 10 4 6 8 1 4 10 6 8 1 4 6 10 At the end of the first pass,largest element is guaranteedto be at bottom 2nd pass: Start at top, compare adjacent pairs, swap larger toward bottom if needed 8 1 4 6 10 1 8 4 6 10 1 4 8 6 10 1 4 6 8 10 At the end of the 2nd pass,2nd-largest element is guaranteedto be at 2nd-from-bottom done 1 4 6 8 10 1 4 6 8 10 1 4 6 8 10 1 4 6 8 10 1 4 6 8 10 1 4 6 8 10 4th pass (no swaps needed) 3rd pass (no swaps needed)

  46. Bubble-sort using ranks void bubbleSort(Sequence S) { int n = S.size(); for (int i = 0; i<n; i++) { // i’th pass for (int j = 1; j<n-i; j++) if (valAtRank(S,j-1) > valAtRank(S,j)) S.swapElements(S.atRank(j-1), S.atRank(j)); } } int valAtRank(Sequence S, int i) { return ((Integer) S.elemAtRank(i)).intValue(); } Assume S contains Integer objects

  47. Bubble-sort using positions void bubbleSort(Sequence S) { int n = S.size(); for (int i = 0; i<n; i++) { // i’th pass Position prec = S.first(), succ; for (int j = 1; j<n-i; j++) { succ = S.after(prec); if (valAtPos(prec) > valAtPos(succ)) S.swapElements(prec,succ); prec = succ; } } } int valAtPos(Position p) { return ((Integer) p.element()).intValue(); }

  48. Iterators • A common operation on a sequence is to perform some operation on each item in turn. • Print out each element, add 1 to each element in a list of integers, remove spaces from each element in a list of strings, … • Iterator(also known as Enumerator) is an ADT encapsulating this notion of “walking along the elements of a list”.Two operations: • hasNext() Are there more items? • nextObject() Returns next object (if there is one)

  49. SequenceIterator interface ObjectIterator { boolean hasNext(); Object nextIterator(); } class SequenceIterator implements ObjectIterator { Sequence S; // the sequence over which we’re iterating DNode node; // current position in S SequenceIterator(Sequence _S) { S = _S; node = (DNode) S.first(); } boolean hasNext() { return node != S.trailer; } Object nextObject() { Object o = node.element(); node = node.getNext(); return o; } }

  50. Iterator: example • Now you can say… Sequence S = … SequenceIterator si = new SequenceIterator(S); while (si.hasNext()) { System.out.println(si.nextObject() + “, “); }

More Related