Jak mogę sprawdzić, czy BST jest ważny?

głosy
6

Jak mogę sprawdzić, czy BST jest ważny jeden, biorąc pod uwagę jego definicji i korzystania z uogólnioną wersję krotnie dla 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)

Pomysłem jest sprawdzenie, czy wartość jest większa niż węzeł wszystkich wartości w lewym poddrzewie i mniejsze niż wszystkie wartości w jego prawym poddrzewie. To musi być Truedla wszystkich węzłów w drzewie. Funkcja bstListpo prostu wyjście lista (zamówić) wartości w BST.

Oczywiście coś takiego nie będzie działać:

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

ponieważ, na przykład, stosując podwójną funkcję węzła 19kończy się all (<19) (bstList True) && all (>19) (bstList True).

BST

Utwórz 12/02/2011 o 23:22
źródło użytkownik
W innych językach...                            


4 odpowiedzi

głosy
4

Twój problem wydaje się, że stracisz informacji, ponieważ funkcja zwraca tylko wartość logiczną, gdy analizuje lewego i prawego poddrzewa. Więc go zmienić również zwrócić minimalne i maksymalne wartości dla poddrzew. (Jest to prawdopodobnie bardziej efektywne, jak również, ponieważ nie trzeba stosować bslist, aby sprawdzić wszystkie elementy już)

I uczynić funkcja otoki ignorować te „pomocnicze” wartości po zakończeniu, oczywiście.

Odpowiedział 12/02/2011 o 23:38
źródło użytkownik

głosy
4

(Proszę nie umieszczać typeclass ograniczenia na datatyp.)

BST jest ważny MFF w-celu przejścia jest monotonicznie rosnącą.

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

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

isBST = ordered . flatten
Odpowiedział 13/02/2011 o 05:53
źródło użytkownik

głosy
0

Jeśli nie nalegać na użyciu fałdę można zrobić to tak:

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
Odpowiedział 13/02/2011 o 07:45
źródło użytkownik

głosy
2

Jest to dobry sposób kodowania jest oprzeć się na przechodzenie dostarczonych przez Data.Foldable.

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

Możemy czerpać wystąpienie to automatycznie za pomocą rozszerzenia, ale musimy zmienić kolejność pól konstruktora węzła do zapewnienia nam przechodzenie na zamówienie.

Chociaż już przy tym jesteśmy, powinniśmy wyeliminować ograniczenia dotyczące samego typu danych. Oni rzeczywiście nie daje żadnych korzyści, a została usunięta z języka począwszy od Haskell 2011 roku (kiedy chcesz używać takich ograniczeń należy umieścić je na instancje klas, a nie od typu danych.)

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

Najpierw musimy zdefiniować, co to znaczy dla lista być ściśle sortowane.

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.

Wtedy możemy użyć toListmetody zalecanej przez Data.Foldablei powyższy pomocnika.

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

Możemy również zaimplementować to w bardziej bezpośredni sposób, jak prosiłeś. Ponieważ usunięte fałszywe ograniczenia na typ danych, możemy uprościć definicję swojej owczarni.

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)

Teraz musimy typ danych do modelowania wynik naszej catamorphism, co jest, że nie mamy jeszcze węzły ( Z) lub szeregu ściśle rosnących węzłów ( T) lub nie udało ( X)

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

I możemy następnie wdrożyć isBSTbezpośrednio

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 jest trochę uciążliwe, więc może lepiej byłoby, aby rozłożyć nasz sposób skomponować stanach Interim kawałek:

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

Osobiście pewnie wystarczy użyć Składany instancji.

Odpowiedział 13/02/2011 o 16:31
źródło użytkownik

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