Wie kann ich überprüfen, ob ein BST gültig ist?

stimmen
6

Wie kann ich überprüfen, ob ein BST gültig ist, seine Definition gegeben und eine verallgemeinerte Version von Falten für BST mit?

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)

Die Idee ist zu prüfen, ob ein Knotenwert ist größer als alle Werte in der linken Unterbaum und kleiner als alle Werte in dem rechten Unterbaum. Dies muss Truefür alle Knoten im Baum. Eine Funktion , bstListeinfach die Liste der Ausgang (geordnet) Werte in der BST.

so etwas wie dies natürlich nicht funktionieren:

--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

weil zum Beispiel der Falzfunktion zum Knoten Anwendung 19endet all (<19) (bstList True) && all (>19) (bstList True).

ein

Veröffentlicht am 12/02/2011 um 23:22
quelle vom benutzer
In anderen Sprachen...                            


4 antworten

stimmen
4

Ihr Problem scheint zu sein , dass Sie Informationen verlieren , weil Ihre Funktion nur einen Booleschen Wert zurück , wenn sie die linken und rechten Teilbäume untersucht. So ändern , um auch die Minimal- und Maximalwerte der Teilbäume zurück. (Dies ist wahrscheinlich effizienter als gut, da Sie nicht verwendet müssen bslistalle Elemente mehr zu überprüfen)

Und stellen Sie eine Wrapper-Funktion, diese „Hilfs“ Werte zu ignorieren, wenn Sie fertig sind, natürlich.

Beantwortet am 12/02/2011 um 23:38
quelle vom benutzer

stimmen
4

(Bitte setzen Sie nicht typeclass Beschränkungen für die dataArt.)

Ein BST gilt iff eine In-Order-Traversal monoton zunimmt.

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

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

isBST = ordered . flatten
Beantwortet am 13/02/2011 um 05:53
quelle vom benutzer

stimmen
0

Wenn Sie eine Falte nicht darauf bestehen, auf verwenden, können Sie es wie folgt tun:

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
Beantwortet am 13/02/2011 um 07:45
quelle vom benutzer

stimmen
2

Eine gute Möglichkeit, diese Codierung ist auf dem Traversal von Data.Foldable vorgesehen lehnen.

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

Wir können eine Instanz davon ableiten automatisch eine Erweiterung verwenden, aber wir müssen die Felder der Knoten Konstruktor neu zu ordnen uns in Ordnung Traversal zu liefern.

Während wir gerade dabei sind, sollten wir die Beschränkungen für den Datentyp selbst beseitigen. Sie bieten tatsächlich keinen Nutzen, und hat sich von der Sprache ab Haskell 2011 entfernt worden ist (Wenn Sie solche Einschränkungen verwenden möchten, sollten Sie sie auf Instanzen von Klassen setzen, nicht auf den Datentyp.)

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

Zuerst definieren wir , was es bedeutet , für eine Liste streng sortiert werden.

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.

Dann können wir die Verwendung toListMethode zur Verfügung gestellt Data.Foldableund die oben Helfer.

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

Wir können auch diese implementieren mehr direkt, wie Sie gefragt. Da wir die falschen Beschränkungen für den Datentyp entfernt, können wir die Definition Ihrer Falte vereinfachen.

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)

Jetzt brauchen wir einen Datentyp das Ergebnis unserer catamorphism zu modellieren, das ist , dass wir entweder keine Knoten ( Z) oder eine Reihe von streng monoton wachsend Knoten ( T) oder ausgefallen ist ( X)

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

Und wir können dann implementieren isBSTdirekt

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

Das ist ein bisschen langweilig, vielleicht wäre es besser, den Weg zu zerlegen wir die Zwischenzustände ein wenig zusammensetzen:

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

Persönlich würde ich wahrscheinlich nur die faltbare Instanz.

Beantwortet am 13/02/2011 um 16:31
quelle vom benutzer

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