{-# OPTIONS_GHC -fglasgow-exts #-} ----------------------------------------------------------------------------- -- | -- Module : Data.Tree.AVL.Types -- Copyright : (c) Adrian Hey 2004,2005 -- License : BSD3 -- -- Maintainer : http://homepages.nildram.co.uk/~ahey/em.png -- Stability : stable -- Portability : portable -- -- AVL Tree data type definition and a few simple utility functions. ----------------------------------------------------------------------------- module Data.Tree.AVL.Types ( -- * Types. AVL(..), -- * Simple AVL related utilities. empty,isEmpty,isNonEmpty,singleton,pair,tryGetSingleton, ) where import Prelude -- so haddock finds the symbols there import Data.Typeable #if __GLASGOW_HASKELL__ > 604 import Data.Foldable import Data.Monoid #endif -- | AVL tree data type. -- -- The balance factor (BF) of an 'AVL' tree node is defined as the difference between the height of -- the left and right sub-trees. An 'AVL' tree is ALWAYS height balanced, such that |BF| <= 1. -- The functions in this library ("Data.Tree.AVL") are designed so that they never construct -- an unbalanced tree (well that's assuming they're not broken). The 'AVL' tree type defined here -- has the BF encoded the constructors. -- -- Some functions in this library return 'AVL' trees that are also \"flat\", which (in the context -- of this library) means that the sizes of left and right sub-trees differ by at most one and -- are also flat. Flat sorted trees should give slightly shorter searches than sorted trees which -- are merely height balanced. Whether or not flattening is worth the effort depends on the number -- of times the tree will be searched and the cost of element comparison. -- -- In cases where the tree elements are sorted, all the relevant 'AVL' functions follow the -- convention that the leftmost tree element is least and the rightmost tree element is -- the greatest. Bear this in mind when defining general comparison functions. It should -- also be noted that all functions in this library for sorted trees require that the tree -- does not contain multiple elements which are \"equal\" (according to whatever criterion -- has been used to sort the elements). -- -- It is important to be consistent about argument ordering when defining general purpose -- comparison functions (or selectors) for searching a sorted tree, such as .. -- -- @ -- myComp :: (k -> e -> Ordering) -- -- or.. -- myCComp :: (k -> e -> COrdering a) -- @ -- -- In these cases the first argument is the search key and the second argument is an element of -- the 'AVL' tree. For example.. -- -- @ -- key \`myCComp\` element -> Lt implies key < element, proceed down the left sub-tree -- key \`myCComp\` element -> Gt implies key > element, proceed down the right sub-tree -- @ -- -- This convention is same as that used by the overloaded 'compare' method from 'Ord' class. -- -- WARNING: The constructors of this data type are exported from this module but not from -- the top level 'AVL' wrapper ("Data.Tree.AVL"). Don't try to construct your own 'AVL' -- trees unless you're sure you know what your doing. If you end up creating and using -- 'AVL' trees that aren't you'll break most of the functions in this library. -- -- Controlling Strictness. -- -- The 'AVL' data type is declared as non-strict in all it's fields, -- but all the functions in this library behave as though it is strict in its -- recursive fields (left and right sub-trees). Strictness in the element field is -- controlled either by using the strict variants of functions (defined in this library -- where appropriate), or using strict variants of the combinators defined in "Data.COrdering", -- or using 'seq' etc. in your own code (in any combining comparisons you define, for example). -- -- The Eq and Ord instances. -- -- Begining with version 3.0 these are now derived, and hence are defined in terms of -- strict structural equality, rather than observational equivalence. The reason for -- this change is that the observational equivalence abstraction was technically breakable -- with the exposed API. But since this change, some functions which were previously -- considered unsafe have become safe to expose (those that measure tree height). -- data AVL e = E -- ^ Empty Tree | N (AVL e) e (AVL e) -- ^ BF=-1 (right height > left height) | Z (AVL e) e (AVL e) -- ^ BF= 0 | P (AVL e) e (AVL e) -- ^ BF=+1 (left height > right height) deriving(Eq,Ord,Show,Read) -- A name for the AVL type constructor, fully qualified avlTyConName :: String avlTyConName = "Data.Tree.AVL.AVL" -- A Typeable1 instance instance Typeable1 AVL where typeOf1 _ = mkTyConApp (mkTyCon avlTyConName) [] #ifndef __GLASGOW_HASKELL__ -- A Typeable instance (not needed by ghc, but Haddock fails to document this instance) instance Typeable e => Typeable (AVL e) where typeOf = typeOfDefault #endif #if __GLASGOW_HASKELL__ > 604 instance Foldable AVL where foldMap _f E = mempty foldMap f (N l v r) = foldMap f l `mappend` f v `mappend` foldMap f r foldMap f (Z l v r) = foldMap f l `mappend` f v `mappend` foldMap f r foldMap f (P l v r) = foldMap f l `mappend` f v `mappend` foldMap f r #endif -- | The empty AVL tree. {-# INLINE empty #-} empty :: AVL e empty = E -- | Returns 'True' if an AVL tree is empty. -- -- Complexity: O(1) {-# INLINE isEmpty #-} isEmpty :: AVL e -> Bool isEmpty E = True isEmpty _ = False -- | Returns 'True' if an AVL tree is non-empty. -- -- Complexity: O(1) {-# INLINE isNonEmpty #-} isNonEmpty :: AVL e -> Bool isNonEmpty E = False isNonEmpty _ = True -- | Creates an AVL tree with just one element. -- -- Complexity: O(1) {-# INLINE singleton #-} singleton :: e -> AVL e singleton e = Z E e E -- | Create an AVL tree of two elements, occuring in same order as the arguments. {-# INLINE pair #-} pair :: e -> e -> AVL e pair e0 e1 = P (Z E e0 E) e1 E -- | If the AVL tree is a singleton (has only one element @e@) then this function returns @('Just' e)@. -- Otherwise it returns Nothing. -- -- Complexity: O(1) {-# INLINE tryGetSingleton #-} tryGetSingleton :: AVL e -> Maybe e tryGetSingleton (Z E e _) = Just e -- Right subtree must be E too, but no need to waste time checking tryGetSingleton _ = Nothing