Purely Functional Data Structures
Format: PDF / Kindle (mobi) / ePub
Most books on data structures assume an imperative language such as C or C++. However, data structures for these languages do not always translate well to functional languages such as Standard ML, Haskell, or Scheme. This book describes data structures from the point of view of functional languages, with examples, and presents design techniques that allow programmers to develop their own functional data structures. The author includes both classical data structures, such as red-black trees and binomial queues, and a host of new data structures developed exclusively for functional languages. All source code is given in Standard ML and Haskell, and most of the programs are easily adaptable to other functional languages. This handy reference for professional programmers working with functional languages can also be used as a tutorial or for self-study.
every multiway node into a binary node whose left child represents the leftmost child of the multiway node and whose right child represents the sibling to the immediate right of the multiway node. If either the leftmost child or the right sibling of the multiway node is missing, then the corresponding field in the binary node is empty. (Note that this implies that the right child of the root is always empty in the binary representation.) Applying this transformation to pairing heaps yields
= O N E t:: ts | consTree (tu O N E t2 :: ts) = ZERO :: consTree (link (tu t2), ts) The link helper function constructs a new tree from two equal-sized subtrees and automatically calculates the size of the new tree. Deleting an element from a binary random-access list (using tail) is analogous to decrementing a binary number. Recall the decrement function on dense binary numbers: fun dec [ O N E ] =  | dec ( O N E :: ds) = ZERO :: ds | dec (ZERO :: ds) = O N E :: dec ds The corresponding
problem. Lazy binary numbers can serve as template for many other data structures. In Chapter 11, we will generalize this template into a design technique called implicit recursive slowdown. Exercise 9.8 Prove that inc and dec both run in 0(1) amortized time using a debit invariant that allows one debit per ONE and zero debits per ZERO or Two. Exercise 9.9 Implement cons, head, and tail for random-access lists based on zeroless redundant binary numbers, using the type datatype a Digit = O N E of
can insert a new element in O (1) time. Wefirstcompare the ranks of the two smallest trees. If they are the same, we skew link the new element with these two trees. Otherwise, we make a new singleton tree and add it to the front of the list. fun insert (x, ts as h :: t2 :: rest) = if rank h = rank t2 then skewLink (x, tu t2):: rest else NODE (0, x, [ ] , [ ] ) : : ts | insert (x, ts) = NODE (0, x, [ ] , [ ] ) : : ts The remaining functions are nearly identical to their counterparts from ordinary
ChapterNotes Myers [Mye82, Mye84] used copying and sharing to implement persistent binary search trees (in his case, AVL trees). Sarnak and Tarjan [ST86a] coined the term path copying for the general technique of implementing persistent 16 Persistence signature FINITEMAP = sig type Key type a Map val empty : a Map vai bind : Key x a x a Map -»• a Map val lookup : Key x a Map -> a (* ra/se NOTFOUND /f /rey /s nof fo^nof *) end Figure 2.10. Signature forfinitemaps. data structures by copying