Week 7 Arrays, Lists, Pointers and Rooted Trees General Remarks
Total Page:16
File Type:pdf, Size:1020Kb
CS 270 CS 270 Algorithms General remarks Algorithms Oliver Oliver Week 7 Kullmann Kullmann Binary Binary search search Arrays, lists, pointers and rooted trees Lists Lists Pointers Pointers Trees We conclude elementary data structures by discussing and Trees 1 Binary search Implementing implementing arrays, lists, pointers and trees. Implementing rooted trees rooted trees We also consider binary search. Tutorial Tutorial 2 Lists Reading from CLRS for week 7 3 Pointers 1 Chapter 10, Sections 10.2, 10.3, 10.4. 4 Trees 5 Implementing rooted trees 6 Tutorial CS 270 CS 270 Arrays Algorithms Vectors Algorithms Oliver Oliver Kullmann Kullmann Arrays are the most fundamental data structure: The dynamic form of an array (i.e., it can grow) can be called a Binary Binary search vector (as for C++; or “dynamic array”): search An array A is a static data-structure, with a fixed length Lists Lists The growth of the vector happens by internally holding an n N0, holding n objects of the same type. Pointers Pointers ∈ array, and when the need arises, to allocate a new, bigger Access to elements happens via A[i] for indices i, typically Trees Trees array, copy the old content, and delete the old array. 0-based (C-based languages), that is, i 0,..., n 1 , or Implementing Implementing ∈ { − } rooted trees When done “infrequently”, insertions (and deletions) at the rooted trees 1-based, that is, i 1,..., n . Tutorial Tutorial ∈ { } end of the vector require only amortised constant time; see This access, called random access, happens in constant the tutorial. time, and can be used for reading and writing. However insertions and deletions at the beginning of the Due to the fixed length of arrays, one cannot really speak of vector (or somewhere else) needs time linear in the current “insertion” and “deletion” for arrays. size of the vector, since the elements need to be shifted. Search in general is slow (one has to run through all A vector with additional structure, where also insertions and elements in the worst case), however fast in sorted arrays, deletions at the beginning happens in amortised constant via “binary search”. time, is typically called a deque (a “double-ended queue”). CS 270 CS 270 Searching in sorted vectors Algorithms Binary search Algorithms Searching in general vectors takes linear time (running through Oliver Oliver Kullmann class BinarySearch Kullmann all elements): { Binary public static int binary search( final int [] Binary search search 1 However, if the vector is sorted (we assume, as it is the A, int begin , int end , final int x) Lists { Lists default, ascending order), then it can be done in i f (A == null ) return 1; Pointers − Pointers logarithmic time (in the length n of the vector). i f (begin == end) return 1; Trees − Trees 2 We present the Java-function binary search, which while ( true ) Implementing { Implementing searches for an element x in an array A. rooted trees final int mid = (begin+end)/2; rooted trees Tutorial Tutorial 3 Instead of just returning true or false (for found or not), i f (A[mid] == x) return mid; i f (begin+1 == end) return 1; it is more informative to return an index i with A[i]= x, if − i f (A[mid] < x) found, and to return 1 otherwise. { − begin = mid+1; 4 Since it might not be so easy to (efficiently) form i f (begin == end) return 1; sub-arrays, our version of binary search allows to specify − a sub-array by its indices begin and end. } else end = mid; 5 As it is usually best, this so-called “range” is right-open, i.e., the beginning is included, but the ending excluded. } 6 The role model for that is begin = 0 and end = n. } CS 270 CS 270 Binary search (cont.) Algorithms Binary search with assertions Algorithms Oliver Oliver Kullmann public static int binary search( final int [] A Kullmann , int begin , int end , final int x) Binary { Binary search i f (A == null ) return 1; search − Lists assert(0 <= begin <= end <= A.length); Lists public static int binary search( final int [] Pointers i f (begin == end) return 1; Pointers − A, final int x) Trees while ( true ) Trees { { i f (A == null ) return 1; Implementing assert(0 <= begin < end <= A.length); Implementing − rooted trees rooted trees return binary search(A, 0, A.length, x); Tutorial final int mid = (begin+end)/2; Tutorial assert(begin <= mid < end); } i f (A[mid] == x) return mid; } i f (begin+1 == end) return 1; − assert(begin < mid) ; i f (A[mid] < x) begin = mid+1; { i f (begin == end) return 1; − } else end = mid; } } CS 270 CS 270 Analysing binary search Algorithms Analysing binary search (cont.) Algorithms Oliver Oliver Kullmann Kullmann Binary We obtain the second case of the Master Theorem Binary We have a divide-and-conquer algorithm, with the characteristic search search (log (1) = 0), whence recurrence Lists 2 Lists T (n)= T (n/2) + 1. Pointers Pointers Trees T (n) = Θ(lg n). Trees Implementing Implementing rooted trees Recall that this actually only implies an upper bound for the rooted trees That’s because we divide the array into two (nearly) equal Tutorial run-time of binary search — the lower bound implied by the Tutorial parts, i.e., b = 2 in the standard form of the recurrence for implicit Ω holds only for the recurrence, but not necessarily for the Master Theorem. the run-time. While we only need to investigate one of the two parts (due However, it is not too hard to see that also for the algorithm, to the sorting!), i.e., a = 1 for the Master Theorem. and actually for every possible search algorithm, we need at least Finally the work done for splitting happens in constant lg(n) comparisons. time, and thus c = 0 for the Master Theorem. CS 270 CS 270 Removing random access from vectors, gaining fast Algorithms Pointers to next and previous elements Algorithms Oliver Like a vector, the elements of a list are arranged in a linear order. Oliver general insertion and deletion: Linked lists Kullmann Kullmann Binary Binary search The basic idea here is that search With vectors we obtain random access — via indices, which are Lists each elements contains a pointer Lists just natural numbers, and thus arbitrary arithmetic can be Pointers to the next and the previous element of the list. Pointers performed with them — due to the contiguous and uniform Trees Trees storage scheme: underlying is an array, which is stored as one Implementing Implementing So a list-object x is a triple: contiguous block of memory cells, all of the same size. rooted trees rooted trees Tutorial Tutorial But to maintain contiguity, only deletions and insertions at the x.prev is a pointer to the previous element in the list; end of the vector are efficient (amortised constant-time) — if we x.next is a pointer to the next element in the list; give up contiguity, then we loose random access, but we gain x.key contains the key (or the data, if there is no “key”). efficient arbitrary deletions and insertions: (linked) lists. For the first element of the list, x.prev is NIL, and for the last Lists formally implement a dictionary (search, insertion, element, x.next is NIL. deletion), but, different from “real” dictionaries, search is slow, while insertion and deletion is very fast, i.e., constant-time. The whole list is represented by a pointer L to the first element (as usual, NIL if the list is empty). CS 270 CS 270 Searching Algorithms Excursion: Searching, in C++ Algorithms Oliver Oliver Kullmann For comparison, the same code in C++: Kullmann Binary Binary search const List search( const List L, const Key k) search ∗ ∗ { The SEARCH-function in Java-like code, using List as the Lists while (L != nullptr and L.key != k) Lists L = L.next; ∗ pointer-type (recall — nearly everything in Java is a pointer!): Pointers ∗ Pointers Trees return L; Trees static List search(List L, final Key k) { Implementing } Implementing while (L != null && L.key != k) rooted trees rooted trees L = L.next; Tutorial We see that in C/C++ we not only have pointers, but also Tutorial return L; values (as the ints!), and thus one can distinguish between pointers and values: The *-operator makes pointer-types from } value-types, and dereferences pointers (to values). Further Note that if x is not found, then L will automatically finally remarks: become NIL (that is, null for Java). “const List ” means that we do not change the values. ∗ More idiomatic would be the use of the > operator, − which makes for example L >key instead of L.key. − ∗ CS 270 CS 270 Insertion Algorithms Deletion Algorithms Oliver Oliver Kullmann Kullmann Binary Binary Inserting a list-object x into list L, at the beginning, again as search Deleting the list-element x from list L: search Java-code: Lists Lists Pointers static List delete(List L, final List x) Pointers static List insert(List L, final List x) { { Trees assert(x != null ); Trees assert(x != null ); Implementing assert(L != null ); Implementing x.next = L; rooted trees rooted trees Tutorial i f (x.prev != null ) x.prev.next = x.next; Tutorial x.prev = null ; else L = x.next; i f (L != null ) L.prev = x; i f (x.next != null ) x.next.prev = x.prev; L = x; return L; return L; } } Again the return-value is the new list. Note that the return-value is the new list. CS 270 CS 270 Other forms of linked lists Algorithms Final remarks on lists Algorithms Oliver Oliver Kullmann Kullmann Binary Binary search What we have outlined as the class List (see the lab session for search Our from of a linked list (the standard form) is more precisely Lists Lists the full implementation) would typically be considered as a type called doubly linked list, since we have back- and forth-pointers Pointers Pointers ListNode, while the List-class itself would be kind of a for every node.