Bir BST geçerli olup olmadığını nasıl kontrol edebilirim?

oy
6

Nasıl bir BST tanımı ve BST için kat genelleştirilmiş bir sürümünü kullanarak verilen, geçerli bir biriyse kontrol edebilirim?

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)

Fikir bir düğüm değeri sağ alt ağaçtaki tüm değerlerden daha sol alt ağaçtaki tüm değerlerin ardından büyüktür ve daha küçük olup olmadığını kontrol etmektir. Bu olmalı Trueağacındaki bütün düğümler için. Bir fonksiyon bstListBST içinde (sıralı) değerlerinin listesi kolayca çıktı.

Tabii böyle bir şey çalışmaz:

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

Örneğin, bir düğüm kat fonksiyonun uygulanması nedeniyle 19sona erer all (<19) (bstList True) && all (>19) (bstList True).

bir

Oluştur 12/02/2011 saat 23:22
kaynak kullanıcı
Diğer dillerde...                            


4 cevaplar

oy
4

Senin sorunun bu sol ve sağ alt ağaçlar inceler zaman işlevi yalnızca bir boolean döndüren çünkü bilgi kaybetmek gibi görünüyor. Yani aynı zamanda alt ağaçlar minimum ve maksimum değerler döndürmek için değiştirin. Eğer kullanılan gerekmez çünkü (Bu, hem muhtemelen daha etkilidirbslist tüm unsurları kontrol etmek artık)

Ve tabii ki, yapıldıktan sonra bir sarıcı işlevi bu "yardımcı" değerlerini görmezden olun.

Cevap 12/02/2011 saat 23:38
kaynak kullanıcı

oy
4

(Üzerine typeclass kısıtlamalar koymayınız datatürü.)

Bir BST bir in-sipariş geçişi monoton artan bir IFF geçerlidir.

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

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

isBST = ordered . flatten
Cevap 13/02/2011 saat 05:53
kaynak kullanıcı

oy
0

Eğer bir kat kullanmakta ısrar yoksa bunu şöyle yapabilirsiniz:

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
Cevap 13/02/2011 saat 07:45
kaynak kullanıcı

oy
2

Bu kodlama hoş bir yolu Data.Foldable tarafından sağlanan kastetmek dayanacağı etmektir.

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

Biz otomatik bir uzantı kullanarak bunun bir örneğini elde edebilirsiniz, ama biz bize bir in-sipariş geçişini sağlamak üzere Düğüm yapıcı alanlarını yeniden düzenlemek gerekir.

Biz bunu yaparken, biz yeni veri türünde üzerindeki kısıtlamaları ortadan kaldırmak gerekir. Onlar aslında hiçbir yarar sağlamak ve Haskell 2011 itibarıyla dilinden kaldırıldı (eğer böyle bir sınırlaması kullanmak istediğinizde değil veri türüne, sınıfların örneklerinde koydu olmalıdır.)

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

Önce bir için ne anlama geldiğini tanımlamak liste kesinlikle sıralanmasını.

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.

Sonra kullanabilirsiniz toListtarafından sağlanan yöntem Data.Foldableve yukarıdaki yardımcı.

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

İstediğin gibi Ayrıca, daha doğrudan uygulayabilirsiniz. Biz veri türüne sahte kısıtlamalar kaldırıldı yaptığı için, kat tanımını kolaylaştırabilir.

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)

Şimdi bizim biz ya hiç düğümleri (olması catamorphism, sonucunu modellemek için bir veri türünü gerek Z) veya kesin artan düğümler bir dizi ( T() veya başarısız X)

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

Ve sonra uygulayabilirsiniz isBSTdoğrudan

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

Bu biraz sıkıcı, bu yüzden belki de biz geçici devletlere biraz oluşturmak yolu ayrıştırmak için daha iyi olurdu:

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

Şahsen, muhtemelen sadece Katlanabilir örneğini kullanmayı tercih ediyorum.

Cevap 13/02/2011 saat 16:31
kaynak kullanıcı

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