Jak mohu zkontrolovat, zda BST je platná?

hlasů
6

Jak mohu zkontrolovat, zda BST je platná jeden, vzhledem k jeho definice a použití všeobecného verzi záhybu pro 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)

Idea je ověřit, zda je hodnota uzlu je větší než všechny hodnoty v levém podstromu a menší než všechny hodnoty v jeho pravém subtree. To musí být Truepro všechny uzly ve stromu. Funkce bstListprostě výstupní seznam (na objednávku) hodnot v BST.

Samozřejmě něco takového nebude fungovat:

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

proto, že, například, použití skládací funkci uzlu 19skončí all (<19) (bstList True) && all (>19) (bstList True).

BST

Položena 12/02/2011 v 23:22
zdroj uživatelem
V jiných jazycích...                            


4 odpovědí

hlasů
4

Váš problém se zdá být to, že ztratíte informace, protože váš vrací pouze boolean, když zkoumá levé a pravé podstromy. Takže změnit jej také vrátit hodnoty minimální a maximální jednotlivých podstromů. (To je pravděpodobně efektivnější stejně, protože nemusíte se používá bslistke kontrole všechny prvky už)

A provést funkci wrapper ignorovat tyto „pomocné“ hodnoty poté, co jste udělal, samozřejmě.

Odpovězeno 12/02/2011 v 23:38
zdroj uživatelem

hlasů
4

(Prosím, nedávejte typové třídy omezení na datatypu.)

BST platí právě tehdy, když v-pořadí traversal se monotónně zvyšuje.

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

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

isBST = ordered . flatten
Odpovězeno 13/02/2011 v 05:53
zdroj uživatelem

hlasů
0

Pokud nechcete trvat na použití záhyb, můžete to udělat takto:

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
Odpovězeno 13/02/2011 v 07:45
zdroj uživatelem

hlasů
2

Příjemný způsob kódování je to, aby opřít o průchod poskytované Data.Foldable.

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

Můžeme odvodit její instanci automaticky pomocí rozšíření, ale musíme změnit pořadí polí konstruktoru uzlu nám poskytnout Traversal in-pořadí.

I když už jsme u toho, měli bychom odstranit překážky, které brání datového typu sám. Jsou to vlastně poskytovat žádnou výhodu, a byl odstraněn z jazyce jako Haskell 2011. (Pokud chcete používat takové omezení byste měli dát na instance tříd, a to na typu dat.)

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

Nejprve jsme definovat, co to znamená pro seznam musí být striktně řazeny.

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.

Pak můžeme použít toListmetodu poskytovanou Data.Foldablea výše pomocníka.

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

Můžeme také implementovat toto přímější, jako jsi chtěl. Vzhledem k tomu, abychom odstranili rušivé překážky na typu dat, můžeme zjednodušit definici svého stáda.

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)

Nyní potřebujeme datový typ modelovat výsledek naší catamorphism, což je to, že jsme buď nemají žádné uzly ( Z), nebo rozmezí striktně rostoucích uzlů ( T) nebo není v pořádku ( X)

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

A pak můžeme realizovat isBSTpřímo

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

To je trochu únavné, takže možná, že by bylo lepší, aby se rozložil, jak jsme skládat Prozatímní státům trochu:

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

Osobně bych asi stačí použít Skládací instanci.

Odpovězeno 13/02/2011 v 16:31
zdroj uživatelem

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