Comment puis-je vérifier si un BST est valide?

voix
6

Comment puis-je vérifier si un BST est valide, étant donné sa définition et en utilisant une version généralisée de fois pour 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)

L' idée est de vérifier qu'une valeur de nœud est supérieure à toutes les valeurs en sous - arbre gauche et plus petit que toutes les valeurs de son-sous - arbre droit. Cela doit être Truepour tous les nœuds dans l'arborescence. Une fonction des bstListvaleurs de sortie simplement la liste des (ordonnée) du BST.

Bien sûr, quelque chose comme cela ne fonctionnera pas:

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

parce que, par exemple, en appliquant la fonction de pliage vers le noeud se 19termine all (<19) (bstList True) && all (>19) (bstList True).

un

Créé 12/02/2011 à 23:22
source utilisateur
Dans d'autres langues...                            


4 réponses

voix
4

Votre problème semble être que vous perdez des informations parce que votre fonction retourne uniquement un booléen quand il examine les sous - arbres gauche et à droite. Donc changer pour revenir aussi les valeurs minimales et maximales des sous - arbres. (Ceci est probablement plus efficace aussi bien, puisque vous ne devez utiliser bslistpour vérifier tous les éléments plus)

Et faire une fonction wrapper pour ignorer ces valeurs « auxiliaires » après que vous avez terminé, bien sûr.

Créé 12/02/2011 à 23:38
source utilisateur

voix
4

(S'il vous plaît ne pas mettre des contraintes sur le classe de types de datatype.)

Un BST est valide ssi un dans l'ordre traversal augmente de façon monotone.

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

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

isBST = ordered . flatten
Créé 13/02/2011 à 05:53
source utilisateur

voix
0

Si vous ne tenez pas à l'aide d'un pli, vous pouvez le faire comme ceci:

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
Créé 13/02/2011 à 07:45
source utilisateur

voix
2

Une belle façon de coder ceci est de se pencher sur le parcours fourni par Data.Foldable.

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

On peut en déduire une instance de automatiquement à l'aide d'une extension, mais nous devons réorganiser les champs du constructeur de nœud pour nous fournir un ordre dans traversal.

Alors que nous sommes, nous devons éliminer les contraintes qui pèsent sur le type de données lui-même. Ils fournissent en fait aucun avantage, et a été retiré de la langue de Haskell 2011. (Si vous voulez utiliser ces contraintes que vous devez les mettre sur des instances de classes, et non sur le type de données.)

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

D' abord , nous définissons ce que cela signifie pour une liste à strictement triée.

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.

Ensuite , nous pouvons utiliser la toListméthode fournie par Data.Foldableet l'assistant ci - dessus.

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

Nous pouvons également mettre en œuvre ce plus directement, comme vous avez demandé. Étant donné que nous avons supprimé les contraintes parasites sur le type de données, nous pouvons simplifier la définition de votre pli.

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)

Maintenant , nous avons besoin d' un type de données pour modéliser le résultat de notre catamorphisme, qui est que nous avons soit pas de nœuds ( Z), ou une gamme de nœuds strictement croissantes ( T) ou ont échoué ( X)

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

Et nous pouvons mettre en œuvre isBSTdirectement

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

Ceci est un peu fastidieux, il serait peut-être préférable de décomposer la façon dont nous composons les états intermédiaires un peu:

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

Personnellement, je serais probablement juste utiliser l'instance Pliable.

Créé 13/02/2011 à 16:31
source utilisateur

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