Hoe kan ik controleren of een BST is geldig?

stemmen
6

Hoe kan ik controleren of een BST geldig is, gelet op de definitie en het gebruik van een gegeneraliseerde versie van voudig voor BST?

data(Ord a, Show a, Read  a) => BST a = Void | Node {
    val :: a,
    left, right :: BST a
} deriving (Eq,  Ord,  Read, Show)


fold :: (Read a, Show a, Ord a) => (a -> b -> b ->  b) -> b -> BST a -> b
fold _ z Void         = z
fold f z (Node x l r) = f x (fold f z l) (fold f z r)

Het idee is om te controleren of een knooppunt-waarde groter dan alle waarden in de linker-subboom en kleiner dan alle waarden in de rechter deelboom. Dit moet Truevoor alle knooppunten in de boom. Een functie bstListeenvoudig output van de lijst (besteld) waarden in de BST.

Natuurlijk is zoiets als dit zal niet werken:

--isBST :: (Read a, Show a, Ord a) => BST a -> Bool
isBST t = fold (\x l r -> all (<x) (bstList l) && all (>x) (bstList r)) (True) t

omdat bijvoorbeeld het toepassen van de vouwfunctie naar het knooppunt 19eindigt all (<19) (bstList True) && all (>19) (bstList True).

een

De vraag is gesteld op 12/02/2011 om 23:22
bron van user
In andere talen...                            


4 antwoorden

stemmen
4

Uw probleem lijkt te zijn dat u informatie verliest omdat uw functie alleen een boolean terug bij het onderzoek van de linker en rechter substructuren. Dus verander het ook de minimale en maximale waarden van de substructuren terug te keren. (Dit is waarschijnlijk efficiënter als goed, omdat je niet hoeft te worden gebruikt bslistom alle elementen te controleren meer)

En maak een wrapper functie om deze "hulp" waarden negeren nadat u klaar bent, natuurlijk.

antwoordde op 12/02/2011 om 23:38
bron van user

stemmen
4

(Gelieve niet typeclass beperkingen op het datatype.)

Een BST geldt iff een involgorde traversal is monotoon stijgend.

flatten tree = fold (\a l r -> l . (a:) . r) id tree []

ordered list@(_:rest) = and $ zipWith (<) list rest
ordered _ = True

isBST = ordered . flatten
antwoordde op 13/02/2011 om 05:53
bron van user

stemmen
0

Als je niet aandringen op het gebruik een vouw je kunt doen als dit:

ord Void = True
ord (Node v l r) = every (< v) l && every (> v) r && ord l && ord r where
    every p Void = True
    every p (Node v l r) = p v && every p l && every p r
antwoordde op 13/02/2011 om 07:45
bron van user

stemmen
2

Een leuke manier van het coderen van dit is te leunen op de traversal door Data.Foldable.

{-# LANGUAGE DeriveFunctor, DeriveFoldable #-}
import Data.Foldable
import Data.Monoid

We kunnen een voorbeeld van deze automatisch met behulp van een verlenging af te leiden, maar we moeten de velden van de Node constructeur herschikken om ons te voorzien van een in-orde traversal.

Terwijl we toch bezig zijn, moeten we de beperkingen van het soort gegevens zelf te elimineren. Zij bieden in feite geen voordeel, en is uit de taal van Haskell 2011. verwijderd (Wanneer u dergelijke beperkingen te gebruiken moet je ze op gevallen van klassen, niet van het type data.)

data BST a 
  = Void
  | Node
    { left :: BST a
    , val :: a
    , right :: BST a 
    } deriving (Eq, Ord, Read, Show, Foldable)

Eerst bepalen we wat het betekent voor een lijst strikt te sorteren.

sorted :: Ord a => [a] -> Bool
sorted [] = True
sorted [x] = True
sorted (x:xs) = x < head xs && sorted xs 
-- head is safe because of the preceeding match.

Dan kunnen we het gebruiken toListmethode die door Data.Foldableen de hierboven helper.

isBST :: Ord a => BST a -> Bool
isBST = sorted . toList

We kunnen dit ook uit te voeren meer direct, als je dat vraagt. Aangezien wij de valse beperkingen van het type data verwijderd, kunnen we de definitie van uw fold te vereenvoudigen.

cata :: (b -> a -> b -> b) -> b -> BST a -> b
cata _ z Void         = z
cata f z (Node l x r) = f (cata f z l) x (cata f z r)

Nu moeten we een data type om het resultaat van onze catamorfisme, namelijk dat we ofwel hebben geen knooppunten (model Z), of een reeks van strikt stijgende knooppunten ( T) of hebben gefaald ( X)

data T a = Z | T a a | X deriving Eq

En we kunnen vervolgens in de praktijk isBSTdirect

isBST' :: Ord a => BST a -> Bool
isBST' b = cata phi Z b /= X where
  phi X _ _ = X
  phi _ _ X = X
  phi Z a Z = T a a
  phi Z a (T b c) = if a < b then T a c else X
  phi (T a b) c Z = if b < c then T a c else X
  phi (T a b) c (T d e) = if b < c && c < d then T a e else X

Dit is een beetje vervelend, dus misschien zou het beter zijn om de manier waarop we samen de interim-staten een beetje ontleden:

cons :: Ord a => a -> T a -> T a
cons _ X = X
cons a Z = T a a
cons a (T b c) = if a < b then T a c else X

instance Ord a => Monoid (T a) where
  mempty = Z
  Z `mappend` a = a
  a `mappend` Z = a
  X `mappend` _ = X
  _ `mappend` X = X
  T a b `mappend` T c d = if b < c then T a d else X

isBST'' :: Ord a => BST a -> Bool
isBST'' b = cata phi Z b /= X where
  phi l a r = l `mappend` cons a r

Persoonlijk zou ik waarschijnlijk gewoon gebruik maken van de Opvouwbare instantie.

antwoordde op 13/02/2011 om 16:31
bron van user

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more