{-# OPTIONS_GHC -fglasgow-exts #-} ----------------------------------------------------------------------------- -- | -- Module : Data.Tree.AVL.Zipper -- Copyright : (c) Adrian Hey 2004,2005 -- License : BSD3 -- -- Maintainer : http://homepages.nildram.co.uk/~ahey/em.png -- Stability : stable -- Portability : portable -- ----------------------------------------------------------------------------- module Data.Tree.AVL.Zipper (-- * The AVL Zipper -- | An implementation of \"The Zipper\" for AVL trees. This can be used like -- a functional pointer to a serial data structure which can be navigated -- and modified, without having to worry about all those tricky tree balancing -- issues. See JFP Vol.7 part 5 or .. -- -- -- -- Notes about efficiency: -- -- The functions defined here provide a useful way to achieve those awkward -- operations which may not be covered by the rest of this package. They're -- reasonably efficient (mostly O(log n) or better), but zipper flexibility -- is bought at the expense of keeping path information explicitly as a heap -- data structure rather than implicitly on the stack. Since heap storage -- probably costs more, zipper operations will are likely to incur higher -- constant factors than equivalent non-zipper operations (if available). -- -- Some of the functions provided here may appear to be weird combinations of -- functions from a more logical set of primitives. They are provided because -- they are not really simple combinations of the corresponding primitives. -- They are more efficient, so you should use them if possible (e.g combining -- deleting with Zipper closing). -- -- Also, consider using the 'BAVL' as a cheaper alternative if you don't -- need to navigate the tree. -- ** Types ZAVL,PAVL, -- ** Opening assertOpenL,assertOpenR, tryOpenL,tryOpenR, genAssertOpen,genTryOpen, genTryOpenGE,genTryOpenLE, genOpenEither, -- ** Closing close,fillClose, -- ** Manipulating the current element. getCurrent,putCurrent,applyCurrent,applyCurrent', -- ** Moving assertMoveL,assertMoveR,tryMoveL,tryMoveR, -- ** Inserting elements insertL,insertR,insertMoveL,insertMoveR,fill, -- ** Deleting elements delClose, assertDelMoveL,assertDelMoveR,tryDelMoveR,tryDelMoveL, delAllL,delAllR, delAllCloseL,delAllCloseR, delAllIncCloseL,delAllIncCloseR, -- ** Inserting AVL trees insertTreeL,insertTreeR, -- ** Current element status isLeftmost,isRightmost, sizeL,sizeR, -- ** Operations on whole zippers sizeZAVL, -- ** A cheaper option is to use BAVL -- | These are a cheaper but more restrictive alternative to using the full Zipper. -- They use \"Binary Paths\" (Ints) to point to a particular element of an 'AVL' tree. -- Use these when you don't need to navigate the tree, you just want to look at a -- particular element (and perhaps modify or delete it). The advantage of these is -- that they don't create the usual Zipper heap structure, so they will be faster -- (and reduce heap burn rate too). -- -- If you subsequently decide you need a Zipper rather than a BAVL then some conversion -- utilities are provided. -- *** Types BAVL, -- *** Opening and closing genOpenBAVL,closeBAVL, -- *** Inspecting status fullBAVL,emptyBAVL,tryReadBAVL,readFullBAVL, -- *** Modifying the tree pushBAVL,deleteBAVL, -- *** Converting to BAVL to Zipper -- | These are O(log n) operations but with low constant factors because no comparisons -- are required (and the tree nodes on the path will most likely still be in cache as -- a result of opening the BAVL in the first place). fullBAVLtoZAVL,emptyBAVLtoPAVL,anyBAVLtoEither, ) where import Prelude -- so haddock finds the symbols there import Data.Tree.AVL.Types(AVL(..)) import Data.Tree.AVL.Size(size,addSize) import Data.Tree.AVL.Internals.DelUtils(deletePath,popRN,popRZ,popRP,popLN,popLZ,popLP) import Data.Tree.AVL.Internals.HeightUtils(height,addHeight) import Data.Tree.AVL.Internals.HJoin(spliceH,joinH) import Data.Tree.AVL.Internals.HPush(pushHL,pushHR) import Data.Tree.AVL.Internals.BinPath(BinPath(..),genOpenPath,writePath,insertPath,sel,goL,goR) #ifdef __GLASGOW_HASKELL__ import GHC.Base #include "ghcdefs.h" #else #include "h98defs.h" #endif -- N.B. Zippers are always opened using relative heights for efficiency reasons. On the -- whole this causes no problems, except when inserting entire AVL trees or substituting -- the empty tree. (These cases have some minor height computation overhead). -- | Abstract data type for a successfully opened AVL tree. All ZAVL\'s are non-empty! -- A ZAVL can be tought of as a functional pointer to an AVL tree element. data ZAVL e = ZAVL (Path e) (AVL e) !UINT e (AVL e) !UINT -- | Abstract data type for an unsuccessfully opened AVL tree. -- A PAVL can be thought of as a functional pointer to the gap -- where the expected element should be (but isn't). You can fill this gap using -- the 'fill' function, or fill and close at the same time using the 'fillClose' function. data PAVL e = PAVL (Path e) !UINT data Path e = EP -- Empty Path | LP (Path e) e (AVL e) !UINT -- Left subtree was taken | RP (Path e) e (AVL e) !UINT -- Right subtree was taken -- Local Closing Utility close_ :: Path e -> AVL e -> UINT -> AVL e close_ EP t _ = t close_ (LP p e r hr) l hl = case spliceH l hl e r hr of UBT2(t,ht) -> close_ p t ht close_ (RP p e l hl) r hr = case spliceH l hl e r hr of UBT2(t,ht) -> close_ p t ht -- Local Utility to remove all left paths from a path noLP :: Path e -> Path e noLP EP = EP noLP (LP p _ _ _ ) = noLP p noLP (RP p e l hl) = let p_ = noLP p in p_ `seq` RP p_ e l hl -- Local Utility to remove all right paths from a path noRP :: Path e -> Path e noRP EP = EP noRP (LP p e r hr) = let p_ = noRP p in p_ `seq` LP p_ e r hr noRP (RP p _ _ _ ) = noRP p -- Local Closing Utility which ignores all left paths closeNoLP :: Path e -> AVL e -> UINT -> AVL e closeNoLP EP t _ = t closeNoLP (LP p _ _ _ ) l hl = closeNoLP p l hl closeNoLP (RP p e l hl) r hr = case spliceH l hl e r hr of UBT2(t,ht) -> closeNoLP p t ht -- Local Closing Utility which ignores all right paths closeNoRP :: Path e -> AVL e -> UINT -> AVL e closeNoRP EP t _ = t closeNoRP (LP p e r hr) l hl = case spliceH l hl e r hr of UBT2(t,ht) -> closeNoRP p t ht closeNoRP (RP p _ _ _ ) r hr = closeNoRP p r hr -- Add size of all path elements. addSizeP :: Int -> Path e -> Int addSizeP n EP = n addSizeP n (LP p _ r _) = addSizeP (addSize (n+1) r) p addSizeP n (RP p _ l _) = addSizeP (addSize (n+1) l) p -- Add size of all RP path elements. addSizeRP :: Int -> Path e -> Int addSizeRP n EP = n addSizeRP n (LP p _ _ _) = addSizeRP n p addSizeRP n (RP p _ l _) = addSizeRP (addSize (n+1) l) p -- Add size of all LP path elements. addSizeLP :: Int -> Path e -> Int addSizeLP n EP = n addSizeLP n (LP p _ r _) = addSizeLP (addSize (n+1) r) p addSizeLP n (RP p _ _ _) = addSizeLP n p -- | Opens a sorted AVL tree at the element given by the supplied selector. This function -- raises an error if the tree does not contain such an element. -- -- Complexity: O(log n) genAssertOpen :: (e -> Ordering) -> AVL e -> ZAVL e genAssertOpen c t = op EP L(0) t where -- Relative heights !! -- op :: (Path e) -> UINT -> AVL e -> ZAVL e op _ _ E = error "genAssertOpen: No matching element." op p h (N l e r) = case c e of LT -> let p_ = LP p e r DECINT1(h) in p_ `seq` op p_ DECINT2(h) l EQ -> ZAVL p l DECINT2(h) e r DECINT1(h) GT -> let p_ = RP p e l DECINT2(h) in p_ `seq` op p_ DECINT1(h) r op p h (Z l e r) = case c e of LT -> let p_ = LP p e r DECINT1(h) in p_ `seq` op p_ DECINT1(h) l EQ -> ZAVL p l DECINT1(h) e r DECINT1(h) GT -> let p_ = RP p e l DECINT1(h) in p_ `seq` op p_ DECINT1(h) r op p h (P l e r) = case c e of LT -> let p_ = LP p e r DECINT2(h) in p_ `seq` op p_ DECINT1(h) l EQ -> ZAVL p l DECINT1(h) e r DECINT2(h) GT -> let p_ = RP p e l DECINT1(h) in p_ `seq` op p_ DECINT2(h) r -- | Attempts to open a sorted AVL tree at the element given by the supplied selector. -- This function returns 'Nothing' if there is no such element. -- -- Note that this operation will still create a zipper path structure on the heap (which -- is promptly discarded) if the search fails, and so is potentially inefficient if failure -- is likely. In cases like this it may be better to use 'genOpenBAVL', test for \"fullness\" -- using 'fullBAVL' and then convert to a 'ZAVL' using 'fullBAVLtoZAVL'. -- -- Complexity: O(log n) genTryOpen :: (e -> Ordering) -> AVL e -> Maybe (ZAVL e) genTryOpen c t = op EP L(0) t where -- Relative heights !! -- op :: (Path e) -> UINT -> AVL e -> Maybe (ZAVL e) op _ _ E = Nothing op p h (N l e r) = case c e of LT -> let p_ = LP p e r DECINT1(h) in p_ `seq` op p_ DECINT2(h) l EQ -> Just $! ZAVL p l DECINT2(h) e r DECINT1(h) GT -> let p_ = RP p e l DECINT2(h) in p_ `seq` op p_ DECINT1(h) r op p h (Z l e r) = case c e of LT -> let p_ = LP p e r DECINT1(h) in p_ `seq` op p_ DECINT1(h) l EQ -> Just $! ZAVL p l DECINT1(h) e r DECINT1(h) GT -> let p_ = RP p e l DECINT1(h) in p_ `seq` op p_ DECINT1(h) r op p h (P l e r) = case c e of LT -> let p_ = LP p e r DECINT2(h) in p_ `seq` op p_ DECINT1(h) l EQ -> Just $! ZAVL p l DECINT1(h) e r DECINT2(h) GT -> let p_ = RP p e l DECINT1(h) in p_ `seq` op p_ DECINT2(h) r -- | Attempts to open a sorted AVL tree at the least element which is greater than or equal, according to -- the supplied selector. This function returns 'Nothing' if the tree does not contain such an element. -- -- Complexity: O(log n) genTryOpenGE :: (e -> Ordering) -> AVL e -> Maybe (ZAVL e) genTryOpenGE c t = op EP L(0) t where -- Relative heights !! -- op :: (Path e) -> UINT -> AVL e -> ZAVL e op p h E = backupR p E h where backupR EP _ _ = Nothing backupR (LP p_ e r hr) l hl = Just $! ZAVL p_ l hl e r hr backupR (RP p_ e l hl) r hr = case spliceH l hl e r hr of UBT2(t_,ht_) -> backupR p_ t_ ht_ op p h (N l e r) = case c e of LT -> let p_ = LP p e r DECINT1(h) in p_ `seq` op p_ DECINT2(h) l EQ -> Just $! ZAVL p l DECINT2(h) e r DECINT1(h) GT -> let p_ = RP p e l DECINT2(h) in p_ `seq` op p_ DECINT1(h) r op p h (Z l e r) = case c e of LT -> let p_ = LP p e r DECINT1(h) in p_ `seq` op p_ DECINT1(h) l EQ -> Just $! ZAVL p l DECINT1(h) e r DECINT1(h) GT -> let p_ = RP p e l DECINT1(h) in p_ `seq` op p_ DECINT1(h) r op p h (P l e r) = case c e of LT -> let p_ = LP p e r DECINT2(h) in p_ `seq` op p_ DECINT1(h) l EQ -> Just $! ZAVL p l DECINT1(h) e r DECINT2(h) GT -> let p_ = RP p e l DECINT1(h) in p_ `seq` op p_ DECINT2(h) r -- | Attempts to open a sorted AVL tree at the greatest element which is less than or equal, according to -- the supplied selector. This function returns _Nothing_ if the tree does not contain such an element. -- -- Complexity: O(log n) genTryOpenLE :: (e -> Ordering) -> AVL e -> Maybe (ZAVL e) genTryOpenLE c t = op EP L(0) t where -- Relative heights !! -- op :: (Path e) -> UINT -> AVL e -> ZAVL e op p h E = backupL p E h where backupL EP _ _ = Nothing backupL (LP p_ e r hr) l hl = case spliceH l hl e r hr of UBT2(t_,ht_) -> backupL p_ t_ ht_ backupL (RP p_ e l hl) r hr = Just $! ZAVL p_ l hl e r hr op p h (N l e r) = case c e of LT -> let p_ = LP p e r DECINT1(h) in p_ `seq` op p_ DECINT2(h) l EQ -> Just $! ZAVL p l DECINT2(h) e r DECINT1(h) GT -> let p_ = RP p e l DECINT2(h) in p_ `seq` op p_ DECINT1(h) r op p h (Z l e r) = case c e of LT -> let p_ = LP p e r DECINT1(h) in p_ `seq` op p_ DECINT1(h) l EQ -> Just $! ZAVL p l DECINT1(h) e r DECINT1(h) GT -> let p_ = RP p e l DECINT1(h) in p_ `seq` op p_ DECINT1(h) r op p h (P l e r) = case c e of LT -> let p_ = LP p e r DECINT2(h) in p_ `seq` op p_ DECINT1(h) l EQ -> Just $! ZAVL p l DECINT1(h) e r DECINT2(h) GT -> let p_ = RP p e l DECINT1(h) in p_ `seq` op p_ DECINT2(h) r -- | Opens a non-empty AVL tree at the leftmost element. -- This function raises an error if the tree is empty. -- -- Complexity: O(log n) assertOpenL :: AVL e -> ZAVL e assertOpenL E = error "assertOpenL: Empty tree." assertOpenL (N l e r) = openLN EP L(0) l e r -- Relative heights !! assertOpenL (Z l e r) = openLZ EP L(0) l e r -- Relative heights !! assertOpenL (P l e r) = openL_ (LP EP e r L(0)) L(1) l -- Relative heights !! -- | Attempts to open a non-empty AVL tree at the leftmost element. -- This function returns 'Nothing' if the tree is empty. -- -- Complexity: O(log n) tryOpenL :: AVL e -> Maybe (ZAVL e) tryOpenL E = Nothing tryOpenL (N l e r) = Just $! openLN EP L(0) l e r -- Relative heights !! tryOpenL (Z l e r) = Just $! openLZ EP L(0) l e r -- Relative heights !! tryOpenL (P l e r) = Just $! openL_ (LP EP e r L(0)) L(1) l -- Relative heights !! -- Local utility for opening at the leftmost element, using current path and height. openL_ :: (Path e) -> UINT -> AVL e -> ZAVL e openL_ _ _ E = error "openL_: Bug0" openL_ p h (N l e r) = openLN p h l e r openL_ p h (Z l e r) = openLZ p h l e r openL_ p h (P l e r) = let p_ = LP p e r DECINT2(h) in p_ `seq` openL_ p_ DECINT1(h) l -- Open leftmost of (N l e r), where l may be E openLN :: (Path e) -> UINT -> AVL e -> e -> AVL e -> ZAVL e openLN p h E e r = ZAVL p E DECINT2(h) e r DECINT1(h) openLN p h (N ll le lr) e r = let p_ = LP p e r DECINT1(h) in p_ `seq` openLN p_ DECINT2(h) ll le lr openLN p h (Z ll le lr) e r = let p_ = LP p e r DECINT1(h) in p_ `seq` openLZ p_ DECINT2(h) ll le lr openLN p h (P ll le lr) e r = let p_ = LP p e r DECINT1(h) p__ = p_ `seq` LP p_ le lr DECINT4(h) in p__ `seq` openL_ p__ DECINT3(h) ll -- Open leftmost of (Z l e r), where l may be E openLZ :: (Path e) -> UINT -> AVL e -> e -> AVL e -> ZAVL e openLZ p h E e r = ZAVL p E DECINT1(h) e r DECINT1(h) openLZ p h (N ll le lr) e r = let p_ = LP p e r DECINT1(h) in p_ `seq` openLN p_ DECINT1(h) ll le lr openLZ p h (Z ll le lr) e r = let p_ = LP p e r DECINT1(h) in p_ `seq` openLZ p_ DECINT1(h) ll le lr openLZ p h (P ll le lr) e r = let p_ = LP p e r DECINT1(h) p__ = p_ `seq` LP p_ le lr DECINT3(h) in p__ `seq` openL_ p__ DECINT2(h) ll -- | Opens a non-empty AVL tree at the rightmost element. -- This function raises an error if the tree is empty. -- -- Complexity: O(log n) assertOpenR :: AVL e -> ZAVL e assertOpenR E = error "assertOpenR: Empty tree." assertOpenR (N l e r) = openR_ (RP EP e l L(0)) L(1) r -- Relative heights !! assertOpenR (Z l e r) = openRZ EP L(0) l e r -- Relative heights !! assertOpenR (P l e r) = openRP EP L(0) l e r -- Relative heights !! -- | Attempts to open a non-empty AVL tree at the rightmost element. -- This function returns 'Nothing' if the tree is empty. -- -- Complexity: O(log n) tryOpenR :: AVL e -> Maybe (ZAVL e) tryOpenR E = Nothing tryOpenR (N l e r) = Just $! openR_ (RP EP e l L(0)) L(1) r -- Relative heights !! tryOpenR (Z l e r) = Just $! openRZ EP L(0) l e r -- Relative heights !! tryOpenR (P l e r) = Just $! openRP EP L(0) l e r -- Relative heights !! -- Local utility for opening at the rightmost element, using current path and height. openR_ :: (Path e) -> UINT -> AVL e -> ZAVL e openR_ _ _ E = error "openR_: Bug0" openR_ p h (N l e r) = let p_ = RP p e l DECINT2(h) in p_ `seq` openR_ p_ DECINT1(h) r openR_ p h (Z l e r) = openRZ p h l e r openR_ p h (P l e r) = openRP p h l e r -- Open rightmost of (P l e r), where r may be E openRP :: (Path e) -> UINT -> AVL e -> e -> AVL e -> ZAVL e openRP p h l e E = ZAVL p l DECINT1(h) e E DECINT2(h) openRP p h l e (N rl re rr) = let p_ = RP p e l DECINT1(h) p__ = p_ `seq` RP p_ re rl DECINT4(h) in p__ `seq` openR_ p__ DECINT3(h) rr openRP p h l e (Z rl re rr) = let p_ = RP p e l DECINT1(h) in p_ `seq` openRZ p_ DECINT2(h) rl re rr openRP p h l e (P rl re rr) = let p_ = RP p e l DECINT1(h) in p_ `seq` openRP p_ DECINT2(h) rl re rr -- Open rightmost of (Z l e r), where r may be E openRZ :: (Path e) -> UINT -> AVL e -> e -> AVL e -> ZAVL e openRZ p h l e E = ZAVL p l DECINT1(h) e E DECINT1(h) openRZ p h l e (N rl re rr) = let p_ = RP p e l DECINT1(h) p__ = p_ `seq` RP p_ re rl DECINT3(h) in p__ `seq` openR_ p__ DECINT2(h) rr openRZ p h l e (Z rl re rr) = let p_ = RP p e l DECINT1(h) in p_ `seq` openRZ p_ DECINT1(h) rl re rr openRZ p h l e (P rl re rr) = let p_ = RP p e l DECINT1(h) in p_ `seq` openRP p_ DECINT1(h) rl re rr -- | Returns @('Right' zavl)@ if the expected element was found, @('Left' pavl)@ if the -- expected element was not found. It's OK to use this function on empty trees. -- -- Complexity: O(log n) genOpenEither :: (e -> Ordering) -> AVL e -> Either (PAVL e) (ZAVL e) genOpenEither c t = op EP L(0) t where -- Relative heights !! -- op :: (Path e) -> UINT -> AVL e -> Either (PAVL e) (ZAVL e) op p h E = Left $! PAVL p h op p h (N l e r) = case c e of LT -> let p_ = LP p e r DECINT1(h) in p_ `seq` op p_ DECINT2(h) l EQ -> Right $! ZAVL p l DECINT2(h) e r DECINT1(h) GT -> let p_ = RP p e l DECINT2(h) in p_ `seq` op p_ DECINT1(h) r op p h (Z l e r) = case c e of LT -> let p_ = LP p e r DECINT1(h) in p_ `seq` op p_ DECINT1(h) l EQ -> Right $! ZAVL p l DECINT1(h) e r DECINT1(h) GT -> let p_ = RP p e l DECINT1(h) in p_ `seq` op p_ DECINT1(h) r op p h (P l e r) = case c e of LT -> let p_ = LP p e r DECINT2(h) in p_ `seq` op p_ DECINT1(h) l EQ -> Right $! ZAVL p l DECINT1(h) e r DECINT2(h) GT -> let p_ = RP p e l DECINT1(h) in p_ `seq` op p_ DECINT2(h) r -- | Fill the gap pointed to by a 'PAVL' with the supplied element, which becomes -- the current element of the resulting 'ZAVL'. The supplied filling element should -- be \"equal\" to the value used in the search which created the 'PAVL'. -- -- Complexity: O(1) fill :: e -> PAVL e -> ZAVL e fill e (PAVL p h) = ZAVL p E h e E h -- | Essentially the same operation as 'fill', but the resulting 'ZAVL' is closed -- immediately. -- -- Complexity: O(log n) fillClose :: e -> PAVL e -> AVL e fillClose e (PAVL p h) = close_ p (Z E e E) INCINT1(h) -- | Closes a Zipper. -- -- Complexity: O(log n) close :: ZAVL e -> AVL e close (ZAVL p l hl e r hr) = case spliceH l hl e r hr of UBT2(t,ht) -> close_ p t ht -- | Deletes the current element and then closes the Zipper. -- -- Complexity: O(log n) delClose :: ZAVL e -> AVL e delClose (ZAVL p l hl _ r hr) = case joinH l hl r hr of UBT2(t,ht) -> close_ p t ht -- | Gets the current element of a Zipper. -- -- Complexity: O(1) getCurrent :: ZAVL e -> e getCurrent (ZAVL _ _ _ e _ _) = e -- | Overwrites the current element of a Zipper. -- -- Complexity: O(1) putCurrent :: e -> ZAVL e -> ZAVL e putCurrent e (ZAVL p l hl _ r hr) = ZAVL p l hl e r hr -- | Applies a function to the current element of a Zipper (lazily). -- See also 'applyCurrent'' for a strict version of this function. -- -- Complexity: O(1) applyCurrent :: (e -> e) -> ZAVL e -> ZAVL e applyCurrent f (ZAVL p l hl e r hr) = ZAVL p l hl (f e) r hr -- | Applies a function to the current element of a Zipper strictly. -- See also 'applyCurrent' for a non-strict version of this function. -- -- Complexity: O(1) applyCurrent' :: (e -> e) -> ZAVL e -> ZAVL e applyCurrent' f (ZAVL p l hl e r hr) = let e_ = f e in e_ `seq` ZAVL p l hl e_ r hr -- | Moves one step left. -- This function raises an error if the current element is already the leftmost element. -- -- Complexity: O(1) average, O(log n) worst case. assertMoveL :: ZAVL e -> ZAVL e assertMoveL (ZAVL p E _ e r hr) = case pushHL e r hr of UBT2(t,ht) -> cR p t ht where cR EP _ _ = error "assertMoveL: Can't move left." cR (LP p_ e_ r_ hr_) l_ hl_ = case spliceH l_ hl_ e_ r_ hr_ of UBT2(t,ht) -> cR p_ t ht cR (RP p_ e_ l_ hl_) r_ hr_ = ZAVL p_ l_ hl_ e_ r_ hr_ assertMoveL (ZAVL p (N ll le lr) hl e r hr) = let p_ = RP (LP p e r hr) le ll DECINT2(hl) in p_ `seq` openR_ p_ DECINT1(hl) lr assertMoveL (ZAVL p (Z ll le lr) hl e r hr) = openRZ (LP p e r hr) hl ll le lr assertMoveL (ZAVL p (P ll le lr) hl e r hr) = openRP (LP p e r hr) hl ll le lr -- | Attempts to move one step left. -- This function returns 'Nothing' if the current element is already the leftmost element. -- -- Complexity: O(1) average, O(log n) worst case. tryMoveL :: ZAVL e -> Maybe (ZAVL e) tryMoveL (ZAVL p E _ e r hr) = case pushHL e r hr of UBT2(t,ht) -> cR p t ht where cR EP _ _ = Nothing cR (LP p_ e_ r_ hr_) l_ hl_ = case spliceH l_ hl_ e_ r_ hr_ of UBT2(t,ht) -> cR p_ t ht cR (RP p_ e_ l_ hl_) r_ hr_ = Just $! ZAVL p_ l_ hl_ e_ r_ hr_ tryMoveL (ZAVL p (N ll le lr) hl e r hr) = Just $! let p_ = RP (LP p e r hr) le ll DECINT2(hl) in p_ `seq` openR_ p_ DECINT1(hl) lr tryMoveL (ZAVL p (Z ll le lr) hl e r hr) = Just $! openRZ (LP p e r hr) hl ll le lr tryMoveL (ZAVL p (P ll le lr) hl e r hr) = Just $! openRP (LP p e r hr) hl ll le lr -- | Moves one step right. -- This function raises an error if the current element is already the rightmost element. -- -- Complexity: O(1) average, O(log n) worst case. assertMoveR :: ZAVL e -> ZAVL e assertMoveR (ZAVL p l hl e E _ ) = case pushHR l hl e of UBT2(t,ht) -> cL p t ht where cL EP _ _ = error "assertMoveR: Can't move right." cL (RP p_ e_ l_ hl_) r_ hr_ = case spliceH l_ hl_ e_ r_ hr_ of UBT2(t,ht) -> cL p_ t ht cL (LP p_ e_ r_ hr_) l_ hl_ = ZAVL p_ l_ hl_ e_ r_ hr_ assertMoveR (ZAVL p l hl e (N rl re rr) hr) = openLN (RP p e l hl) hr rl re rr assertMoveR (ZAVL p l hl e (Z rl re rr) hr) = openLZ (RP p e l hl) hr rl re rr assertMoveR (ZAVL p l hl e (P rl re rr) hr) = let p_ = LP (RP p e l hl) re rr DECINT2(hr) in p_ `seq` openL_ p_ DECINT1(hr) rl -- | Attempts to move one step right. -- This function returns 'Nothing' if the current element is already the rightmost element. -- -- Complexity: O(1) average, O(log n) worst case. tryMoveR :: ZAVL e -> Maybe (ZAVL e) tryMoveR (ZAVL p l hl e E _ ) = case pushHR l hl e of UBT2(t,ht) -> cL p t ht where cL EP _ _ = Nothing cL (RP p_ e_ l_ hl_) r_ hr_ = case spliceH l_ hl_ e_ r_ hr_ of UBT2(t,ht) -> cL p_ t ht cL (LP p_ e_ r_ hr_) l_ hl_ = Just $! ZAVL p_ l_ hl_ e_ r_ hr_ tryMoveR (ZAVL p l hl e (N rl re rr) hr) = Just $! openLN (RP p e l hl) hr rl re rr tryMoveR (ZAVL p l hl e (Z rl re rr) hr) = Just $! openLZ (RP p e l hl) hr rl re rr tryMoveR (ZAVL p l hl e (P rl re rr) hr) = Just $! let p_ = LP (RP p e l hl) re rr DECINT2(hr) in p_ `seq` openL_ p_ DECINT1(hr) rl -- | Returns 'True' if the current element is the leftmost element. -- -- Complexity: O(1) average, O(log n) worst case. isLeftmost :: ZAVL e -> Bool isLeftmost (ZAVL p E _ _ _ _) = iL p where iL EP = True iL (LP p_ _ _ _) = iL p_ iL (RP _ _ _ _) = False isLeftmost (ZAVL _ _ _ _ _ _) = False -- | Returns 'True' if the current element is the rightmost element. -- -- Complexity: O(1) average, O(log n) worst case. isRightmost :: ZAVL e -> Bool isRightmost (ZAVL p _ _ _ E _) = iR p where iR EP = True iR (RP p_ _ _ _) = iR p_ iR (LP _ _ _ _) = False isRightmost (ZAVL _ _ _ _ _ _) = False -- | Inserts a new element to the immediate left of the current element. -- -- Complexity: O(1) average, O(log n) worst case. insertL :: e -> ZAVL e -> ZAVL e insertL e0 (ZAVL p l hl e1 r hr) = case pushHR l hl e0 of UBT2(l_,hl_) -> ZAVL p l_ hl_ e1 r hr -- | Inserts a new element to the immediate left of the current element and then -- moves one step left (so the newly inserted element becomes the current element). -- -- Complexity: O(1) average, O(log n) worst case. insertMoveL :: e -> ZAVL e -> ZAVL e insertMoveL e0 (ZAVL p l hl e1 r hr) = case pushHL e1 r hr of UBT2(r_,hr_) -> ZAVL p l hl e0 r_ hr_ -- | Inserts a new element to the immediate right of the current element. -- -- Complexity: O(1) average, O(log n) worst case. insertR :: ZAVL e -> e -> ZAVL e insertR (ZAVL p l hl e0 r hr) e1 = case pushHL e1 r hr of UBT2(r_,hr_) -> ZAVL p l hl e0 r_ hr_ -- | Inserts a new element to the immediate right of the current element and then -- moves one step right (so the newly inserted element becomes the current element). -- -- Complexity: O(1) average, O(log n) worst case. insertMoveR :: ZAVL e -> e -> ZAVL e insertMoveR (ZAVL p l hl e0 r hr) e1 = case pushHR l hl e0 of UBT2(l_,hl_) -> ZAVL p l_ hl_ e1 r hr -- | Inserts a new AVL tree to the immediate left of the current element. -- -- Complexity: O(log n), where n is the size of the inserted tree. insertTreeL :: AVL e -> ZAVL e -> ZAVL e insertTreeL E zavl = zavl insertTreeL t@(N l _ _) zavl = insertLH t (addHeight L(2) l) zavl -- Absolute height required!! insertTreeL t@(Z l _ _) zavl = insertLH t (addHeight L(1) l) zavl -- Absolute height required!! insertTreeL t@(P _ _ r) zavl = insertLH t (addHeight L(2) r) zavl -- Absolute height required!! -- Local utility to insert an AVL to the immediate left of the current element. -- This operation carries a minor overhead in that we must convert the absolute -- AVL height into a relative height with the same offset as the rest of the ZAVL. -- This requires calculation of the absolute height at the current position, but -- this should be relatively cheap because the overwhelming majority of elements will -- be close to the bottom of any tree. insertLH :: AVL e -> UINT -> ZAVL e -> ZAVL e insertLH t ht (ZAVL p l hl e r hr) = let offset = case COMPAREUINT hl hr of -- chose smaller sub-tree to calculate absolute height LT -> SUBINT(hl,height l) EQ -> SUBINT(hl,height l) GT -> SUBINT(hr,height r) in case joinH l hl t ADDINT(ht,offset) of UBT2(l_,hl_) -> ZAVL p l_ hl_ e r hr -- | Inserts a new AVL tree to the immediate right of the current element. -- -- Complexity: O(log n), where n is the size of the inserted tree. insertTreeR :: ZAVL e -> AVL e -> ZAVL e insertTreeR zavl E = zavl insertTreeR zavl t@(N l _ _) = insertRH t (addHeight L(2) l) zavl -- Absolute height required!! insertTreeR zavl t@(Z l _ _) = insertRH t (addHeight L(1) l) zavl -- Absolute height required!! insertTreeR zavl t@(P _ _ r) = insertRH t (addHeight L(2) r) zavl -- Absolute height required!! -- Local utility to insert an AVL to the immediate right of the current element. -- This operation carries a minor overhead in that we must convert the absolute -- AVL height into a relative height with the same offset as the rest of the ZAVL. -- This requires calculation of the absolute height at the current position, but -- this should be relatively cheap because the overwhelming majority of elements will -- be close to the bottom of any tree. insertRH :: AVL e -> UINT -> ZAVL e -> ZAVL e insertRH t ht (ZAVL p l hl e r hr) = let offset = case COMPAREUINT hl hr of -- chose smaller sub-tree to calculate absolute height LT -> SUBINT(hl,height l) EQ -> SUBINT(hr,height r) GT -> SUBINT(hr,height r) in case joinH t ADDINT(ht,offset) r hr of UBT2(r_,hr_) -> ZAVL p l hl e r_ hr_ -- | Deletes the current element and moves one step left. -- This function raises an error if the current element is already the leftmost element. -- -- Complexity: O(1) average, O(log n) worst case. assertDelMoveL :: ZAVL e -> ZAVL e assertDelMoveL (ZAVL p E _ _ r hr) = dR p r hr where dR EP _ _ = error "assertDelMoveL: Can't move left." dR (LP p_ e_ r_ hr_) l_ hl_ = case spliceH l_ hl_ e_ r_ hr_ of UBT2(t,ht) -> dR p_ t ht dR (RP p_ e_ l_ hl_) r_ hr_ = ZAVL p_ l_ hl_ e_ r_ hr_ assertDelMoveL (ZAVL p (N ll le lr) hl _ r hr) = case popRN ll le lr of UBT2(l,e) -> case l of Z _ _ _ -> ZAVL p l DECINT1(hl) e r hr N _ _ _ -> ZAVL p l hl e r hr _ -> error "assertDelMoveL: Bug0" -- impossible assertDelMoveL (ZAVL p (Z ll le lr) hl _ r hr) = case popRZ ll le lr of UBT2(l,e) -> case l of E -> ZAVL p l DECINT1(hl) e r hr -- Don't use E!! N _ _ _ -> error "assertDelMoveL: Bug1" -- impossible _ -> ZAVL p l hl e r hr assertDelMoveL (ZAVL p (P ll le lr) hl _ r hr) = case popRP ll le lr of UBT2(l,e) -> case l of E -> error "assertDelMoveL: Bug2" -- impossible Z _ _ _ -> ZAVL p l DECINT1(hl) e r hr _ -> ZAVL p l hl e r hr -- | Attempts to delete the current element and move one step left. -- This function returns 'Nothing' if the current element is already the leftmost element. -- -- Complexity: O(1) average, O(log n) worst case. tryDelMoveL :: ZAVL e -> Maybe (ZAVL e) tryDelMoveL (ZAVL p E _ _ r hr) = dR p r hr where dR EP _ _ = Nothing dR (LP p_ e_ r_ hr_) l_ hl_ = case spliceH l_ hl_ e_ r_ hr_ of UBT2(t,ht) -> dR p_ t ht dR (RP p_ e_ l_ hl_) r_ hr_ = Just $! ZAVL p_ l_ hl_ e_ r_ hr_ tryDelMoveL (ZAVL p (N ll le lr) hl _ r hr) = Just $! case popRN ll le lr of UBT2(l,e) -> case l of Z _ _ _ -> ZAVL p l DECINT1(hl) e r hr N _ _ _ -> ZAVL p l hl e r hr _ -> error "tryDelMoveL: Bug0" -- impossible tryDelMoveL (ZAVL p (Z ll le lr) hl _ r hr) = Just $! case popRZ ll le lr of UBT2(l,e) -> case l of E -> ZAVL p l DECINT1(hl) e r hr -- Don't use E!! N _ _ _ -> error "tryDelMoveL: Bug1" -- impossible _ -> ZAVL p l hl e r hr tryDelMoveL (ZAVL p (P ll le lr) hl _ r hr) = Just $! case popRP ll le lr of UBT2(l,e) -> case l of E -> error "tryDelMoveL: Bug2" -- impossible Z _ _ _ -> ZAVL p l DECINT1(hl) e r hr _ -> ZAVL p l hl e r hr -- | Deletes the current element and moves one step right. -- This function raises an error if the current element is already the rightmost element. -- -- Complexity: O(1) average, O(log n) worst case. assertDelMoveR :: ZAVL e -> ZAVL e assertDelMoveR (ZAVL p l hl _ E _ ) = dL p l hl where dL EP _ _ = error "delMoveR: Can't move right." dL (LP p_ e_ r_ hr_) l_ hl_ = ZAVL p_ l_ hl_ e_ r_ hr_ dL (RP p_ e_ l_ hl_) r_ hr_ = case spliceH l_ hl_ e_ r_ hr_ of UBT2(t,ht) -> dL p_ t ht assertDelMoveR (ZAVL p l hl _ (N rl re rr) hr) = case popLN rl re rr of UBT2(e,r) -> case r of E -> error "delMoveR: Bug0" -- impossible Z _ _ _ -> ZAVL p l hl e r DECINT1(hr) _ -> ZAVL p l hl e r hr assertDelMoveR (ZAVL p l hl _ (Z rl re rr) hr) = case popLZ rl re rr of UBT2(e,r) -> case r of E -> ZAVL p l hl e r DECINT1(hr) -- Don't use E!! P _ _ _ -> error "delMoveR: Bug1" -- impossible _ -> ZAVL p l hl e r hr assertDelMoveR (ZAVL p l hl _ (P rl re rr) hr) = case popLP rl re rr of UBT2(e,r) -> case r of Z _ _ _ -> ZAVL p l hl e r DECINT1(hr) P _ _ _ -> ZAVL p l hl e r hr _ -> error "delMoveR: Bug2" -- impossible -- | Attempts to delete the current element and move one step right. -- This function returns 'Nothing' if the current element is already the rightmost element. -- -- Complexity: O(1) average, O(log n) worst case. tryDelMoveR :: ZAVL e -> Maybe (ZAVL e) tryDelMoveR (ZAVL p l hl _ E _ ) = dL p l hl where dL EP _ _ = Nothing dL (LP p_ e_ r_ hr_) l_ hl_ = Just $! ZAVL p_ l_ hl_ e_ r_ hr_ dL (RP p_ e_ l_ hl_) r_ hr_ = case spliceH l_ hl_ e_ r_ hr_ of UBT2(t,ht) -> dL p_ t ht tryDelMoveR (ZAVL p l hl _ (N rl re rr) hr) = Just $! case popLN rl re rr of UBT2(e,r) -> case r of E -> error "tryDelMoveR: Bug0" -- impossible Z _ _ _ -> ZAVL p l hl e r DECINT1(hr) _ -> ZAVL p l hl e r hr tryDelMoveR (ZAVL p l hl _ (Z rl re rr) hr) = Just $! case popLZ rl re rr of UBT2(e,r) -> case r of E -> ZAVL p l hl e r DECINT1(hr) -- Don't use E!! P _ _ _ -> error "tryDelMoveR: Bug1" -- impossible _ -> ZAVL p l hl e r hr tryDelMoveR (ZAVL p l hl _ (P rl re rr) hr) = Just $! case popLP rl re rr of UBT2(e,r) -> case r of Z _ _ _ -> ZAVL p l hl e r DECINT1(hr) P _ _ _ -> ZAVL p l hl e r hr _ -> error "tryDelMoveR: Bug2" -- impossible -- | Delete all elements to the left of the current element. -- -- Complexity: O(log n) delAllL :: ZAVL e -> ZAVL e delAllL (ZAVL p l hl e r hr) = let hE = case COMPAREUINT hl hr of -- Calculate relative offset and use this as height of empty tree LT -> SUBINT(hl,height l) EQ -> SUBINT(hr,height r) GT -> SUBINT(hr,height r) p_ = noRP p -- remove right paths (current element becomes leftmost) in p_ `seq` ZAVL p_ E hE e r hr -- | Delete all elements to the right of the current element. -- -- Complexity: O(log n) delAllR :: ZAVL e -> ZAVL e delAllR (ZAVL p l hl e r hr) = let hE = case COMPAREUINT hl hr of -- Calculate relative offset and use this as height of empty tree LT -> SUBINT(hl,height l) EQ -> SUBINT(hl,height l) GT -> SUBINT(hr,height r) p_ = noLP p -- remove left paths (current element becomes rightmost) in p_ `seq` ZAVL p_ l hl e E hE -- | Similar to 'delAllL', in that all elements to the left of the current element are deleted, -- but this function also closes the tree in the process. -- -- Complexity: O(log n) delAllCloseL :: ZAVL e -> AVL e delAllCloseL (ZAVL p _ _ e r hr) = case pushHL e r hr of UBT2(t,ht) -> closeNoRP p t ht -- | Similar to 'delAllR', in that all elements to the right of the current element are deleted, -- but this function also closes the tree in the process. -- -- Complexity: O(log n) delAllCloseR :: ZAVL e -> AVL e delAllCloseR (ZAVL p l hl e _ _) = case pushHR l hl e of UBT2(t,ht) -> closeNoLP p t ht -- | Similar to 'delAllCloseL', but in this case the current element and all -- those to the left of the current element are deleted. -- -- Complexity: O(log n) delAllIncCloseL :: ZAVL e -> AVL e delAllIncCloseL (ZAVL p _ _ _ r hr) = closeNoRP p r hr -- | Similar to 'delAllCloseR', but in this case the current element and all -- those to the right of the current element are deleted. -- -- Complexity: O(log n) delAllIncCloseR :: ZAVL e -> AVL e delAllIncCloseR (ZAVL p l hl _ _ _) = closeNoLP p l hl -- | Counts the number of elements to the left of the current element -- (this does not include the current element). -- -- Complexity: O(n), where n is the count result. sizeL :: ZAVL e -> Int sizeL (ZAVL p l _ _ _ _) = addSizeRP (size l) p -- | Counts the number of elements to the right of the current element -- (this does not include the current element). -- -- Complexity: O(n), where n is the count result. sizeR :: ZAVL e -> Int sizeR (ZAVL p _ _ _ r _) = addSizeLP (size r) p -- | Counts the total number of elements in a ZAVL. -- -- Complexity: O(n) sizeZAVL :: ZAVL e -> Int sizeZAVL (ZAVL p l _ _ r _) = addSizeP (addSize (addSize 1 l) r) p {-------------------- BAVL stuff below ----------------------------------} -- | A 'BAVL' is like a pointer reference to somewhere inside an 'AVL' tree. It may be either \"full\" -- (meaning it points to an actual tree node containing an element), or \"empty\" (meaning it -- points to the position in a tree where an element was expected but wasn\'t found). data BAVL e = BAVL (AVL e) (BinPath e) -- | Search for an element in a /sorted/ 'AVL' tree using the supplied selector. -- Returns a \"full\" 'BAVL' if a matching element was found, otherwise returns an \"empty\" 'BAVL'. -- -- Complexity: O(log n) genOpenBAVL :: (e -> Ordering) -> AVL e -> BAVL e {-# INLINE genOpenBAVL #-} genOpenBAVL c t = bp `seq` BAVL t bp where bp = genOpenPath c t -- | Returns the original tree, extracted from the 'BAVL'. Typically you will not need this, as -- the original tree will still be in scope in most cases. -- -- Complexity: O(1) closeBAVL :: BAVL e -> AVL e {-# INLINE closeBAVL #-} closeBAVL (BAVL t _) = t -- | Returns 'True' if the 'BAVL' is \"full\" (a corresponding element was found). -- -- Complexity: O(1) fullBAVL :: BAVL e -> Bool {-# INLINE fullBAVL #-} fullBAVL (BAVL _ (FullBP _ _)) = True fullBAVL (BAVL _ (EmptyBP _ )) = False -- | Returns 'True' if the 'BAVL' is \"empty\" (no corresponding element was found). -- -- Complexity: O(1) emptyBAVL :: BAVL e -> Bool {-# INLINE emptyBAVL #-} emptyBAVL (BAVL _ (FullBP _ _)) = False emptyBAVL (BAVL _ (EmptyBP _ )) = True -- | Read the element value from a \"full\" 'BAVL'. -- This function returns 'Nothing' if applied to an \"empty\" 'BAVL'. -- -- Complexity: O(1) tryReadBAVL :: BAVL e -> Maybe e {-# INLINE tryReadBAVL #-} tryReadBAVL (BAVL _ (FullBP _ e)) = Just e tryReadBAVL (BAVL _ (EmptyBP _ )) = Nothing -- | Read the element value from a \"full\" 'BAVL'. -- This function raises an error if applied to an \"empty\" 'BAVL'. -- -- Complexity: O(1) readFullBAVL :: BAVL e -> e {-# INLINE readFullBAVL #-} readFullBAVL (BAVL _ (FullBP _ e)) = e readFullBAVL (BAVL _ (EmptyBP _ )) = error "readFullBAVL: Empty BAVL." -- | If the 'BAVL' is \"full\", this function returns the original tree with the corresponding -- element replaced by the new element (first argument). If it\'s \"empty\" the original tree is returned -- with the new element inserted. -- -- Complexity: O(log n) pushBAVL :: e -> BAVL e -> AVL e {-# INLINE pushBAVL #-} pushBAVL e (BAVL t (FullBP p _)) = writePath p e t pushBAVL e (BAVL t (EmptyBP p )) = insertPath p e t -- | If the 'BAVL' is \"full\", this function returns the original tree with the corresponding -- element deleted. If it\'s \"empty\" the original tree is returned unmodified. -- -- Complexity: O(log n) (or O(1) for an empty 'BAVL') deleteBAVL :: BAVL e -> AVL e {-# INLINE deleteBAVL #-} deleteBAVL (BAVL t (FullBP p _)) = deletePath p t deleteBAVL (BAVL t (EmptyBP _ )) = t -- | Converts a \"full\" 'BAVL' as a 'ZAVL'. Raises an error if applied to an \"empty\" 'BAVL'. -- -- Complexity: O(log n) fullBAVLtoZAVL :: BAVL e -> ZAVL e fullBAVLtoZAVL (BAVL t (FullBP i _)) = openFull i EP L(0) t -- Relative heights !! fullBAVLtoZAVL (BAVL _ (EmptyBP _ )) = error "fullBAVLtoZAVL: Empty BAVL." -- Local Utility openFull :: UINT -> (Path e) -> UINT -> AVL e -> ZAVL e openFull _ _ _ E = error "openFull: Bug0." openFull i p h (N l e r) = case sel i of LT -> let p_ = LP p e r DECINT1(h) in p_ `seq` openFull (goL i) p_ DECINT2(h) l EQ -> ZAVL p l DECINT2(h) e r DECINT1(h) GT -> let p_ = RP p e l DECINT2(h) in p_ `seq` openFull (goR i) p_ DECINT1(h) r openFull i p h (Z l e r) = case sel i of LT -> let p_ = LP p e r DECINT1(h) in p_ `seq` openFull (goL i) p_ DECINT1(h) l EQ -> ZAVL p l DECINT1(h) e r DECINT1(h) GT -> let p_ = RP p e l DECINT1(h) in p_ `seq` openFull (goR i) p_ DECINT1(h) r openFull i p h (P l e r) = case sel i of LT -> let p_ = LP p e r DECINT2(h) in p_ `seq` openFull (goL i) p_ DECINT1(h) l EQ -> ZAVL p l DECINT1(h) e r DECINT2(h) GT -> let p_ = RP p e l DECINT1(h) in p_ `seq` openFull (goR i) p_ DECINT2(h) r -- | Converts an \"empty\" 'BAVL' as a 'PAVL'. Raises an error if applied to a \"full\" 'BAVL'. -- -- Complexity: O(log n) emptyBAVLtoPAVL :: BAVL e -> PAVL e emptyBAVLtoPAVL (BAVL _ (FullBP _ _)) = error "emptyBAVLtoPAVL: Full BAVL." emptyBAVLtoPAVL (BAVL t (EmptyBP i )) = openEmpty i EP L(0) t -- Relative heights !! -- Local Utility openEmpty :: UINT -> (Path e) -> UINT -> AVL e -> PAVL e openEmpty _ p h E = PAVL p h -- Test for i==0 ?? openEmpty i p h (N l e r) = case sel i of LT -> let p_ = LP p e r DECINT1(h) in p_ `seq` openEmpty (goL i) p_ DECINT2(h) l EQ -> error "openEmpty: Bug0" GT -> let p_ = RP p e l DECINT2(h) in p_ `seq` openEmpty (goR i) p_ DECINT1(h) r openEmpty i p h (Z l e r) = case sel i of LT -> let p_ = LP p e r DECINT1(h) in p_ `seq` openEmpty (goL i) p_ DECINT1(h) l EQ -> error "openEmpty: Bug1" GT -> let p_ = RP p e l DECINT1(h) in p_ `seq` openEmpty (goR i) p_ DECINT1(h) r openEmpty i p h (P l e r) = case sel i of LT -> let p_ = LP p e r DECINT2(h) in p_ `seq` openEmpty (goL i) p_ DECINT1(h) l EQ -> error "openEmpty: Bug2" GT -> let p_ = RP p e l DECINT1(h) in p_ `seq` openEmpty (goR i) p_ DECINT2(h) r -- | Converts a 'BAVL' to either a 'PAVL' or 'ZAVL' (depending on whether it is \"empty\" or \"full\"). -- -- Complexity: O(log n) anyBAVLtoEither :: BAVL e -> Either (PAVL e) (ZAVL e) anyBAVLtoEither (BAVL t (FullBP i _)) = Right (openFull i EP L(0) t) -- Relative heights !! anyBAVLtoEither (BAVL t (EmptyBP i )) = Left (openEmpty i EP L(0) t) -- Relative heights !!