Haskell'de bir ağacın ikili arama ağacı olup olmadığını bulma


10
  type BSTree a = BinaryTree a

  data BinaryTree a = Null | Node (BinaryTree a) a (BinaryTree a)
                      deriving Show

  flattenTree :: BinaryTree a -> [a]
  flattenTree  tree = case tree of
      Null -> []
      Node left val right -> (flattenTree left) ++ [val] ++ (flattenTree right)

  isBSTree :: (Ord a) => BinaryTree a -> Bool
  isBSTree btree = case btree of
      Null -> False
      tree -> (flattenTree tree) == sort (flattenTree tree)

Ne yapmak istediğim, verilen ağacın bir ikili arama ağacı olup olmadığını belirlemek için bir işlev yazmak, benim yöntemim bir listedeki tüm değerleri gruplandırmak ve almak Data.Listve sonra eşit olup olmadığını bulmak için listeyi sıralamaktır, ancak biraz karmaşık. Bunu başka bir modülü ithal etmeden yapabilir miyiz?


flattenTreeİlk olarak tanımlamazdım . FalseBir düğüm, o düğümdeki köklü tüm alt ağacı geçmeden arama özelliğini ihlal ederse erken dönebilirsiniz .
chepner

@ chepner ile sorun sort, değil flattenTree, yeterince tembel.
Ness

Evet, bu diğer cevaplara baktıktan sonra başıma geldi.
chepner

Yanıtlar:


13

İşte ağacı düzleştirmeden yapmanın bir yolu.

Tanımdan, burada,

data BinaryTree a = Null | Node (BinaryTree a) a (BinaryTree a)
     deriving Show

ağacı soldan sağa çevirmenin, görmezden gelmenin Nodeve parantezlerin size alternatif bir Nulls ve as dizisi sağladığını görebilirsiniz . Yani, her iki değer arasında bir Null.

Planım her alt ağaç tatmin uygun olduğunu kontrol etmektir gereksinimleri : Biz yapabilirsiniz rafine her birinde gereklerini Nodebiz arasındadır değerleri hatırlayarak, daha sonra test etmek her onları Null. NullSırayla her bir değer çifti arasında bir tane olduğu için , tüm sıralı (soldan sağa) çiftlerin azalmadığını test ettik.

Gereklilik nedir? Bu bir var gevşek alt ve üst ağacında değerlere bağlı. En soldaki ve en sağdaki uçlar da dahil olmak üzere gereksinimleri ifade etmek için Bottom ve Topelemanları ile herhangi bir siparişi aşağıdaki gibi uzatabiliriz :

data TopBot a = Bot | Val a | Top deriving (Show, Eq, Ord)

Şimdi belirli bir ağacın hem sırayla hem de verilen sınırlar arasında olma gereksinimlerini karşıladığını kontrol edelim.

ordBetween :: Ord a => TopBot a -> TopBot a -> BinaryTree a -> Bool
  -- tighten the demanded bounds, left and right of any Node
ordBetween lo hi (Node l x r) = ordBetween lo (Val x) l && ordBetween (Val x) hi r
  -- check that the demanded bounds are in order when we reach Null
ordBetween lo hi Null         = lo <= hi

Bir ikili arama ağacı sırayla ve aralarında bir ağaçtır Botve Top.

isBSTree :: Ord a => BinaryTree a -> Bool
isBSTree = ordBetween Bot Top

Her alt ağaçtaki gerçek uç değerlerin hesaplanması , dışa doğru köpürtülmesi, ihtiyacınız olandan daha fazla bilgi verir ve sol veya sağ alt ağacın boş olduğu uç durumlarda hareketsizdir. İhtiyaçları korumak ve kontrol etmek, içe doğru itmek, daha homojendir.


6

İşte bir ipucu: yardımcı bir işlev yapın

isBSTree' :: (Ord a) => BinaryTree a -> BSTResult a

nerede BSTResult aolarak tanımlanır

data BSTResult a
   = NotBST             -- not a BST
   | EmptyBST           -- empty tree (hence a BST)
   | NonEmptyBST a a    -- nonempty BST with provided minimum and maximum

Özellikle minimum ve maksimum olmak üzere hesaplamayı yönlendirmek için alt ağaçlardaki sonuçları kullanarak yinelemeli olarak ilerleyebilmelisiniz.

Eğer varsa Örneğin, tree = Node left 20 rightbirlikte isBSTree' left = NonEmptyBST 1 14ve isBSTree' right = NonEmptyBST 21 45daha sonra isBSTree' treeolmalıdır NonEmptyBST 1 45.

Aynı durumda tree = Node left 24 right, bunun yerine, sahip olmalıyız isBSTree' tree = NotBST.

Sonucun dönüştürülmesi Boolönemsizdir.


1
veya açık Monoid'i tanımlayın BSTResult ave içine katlayın. :) (veya yasal bir Monoid olmasa bile ...)
Ness

(ama yine de yasal olduğunu düşünüyorum)
Will Ness

3

Evet , listeyi sıralamanız gerekmez. Her öğenin bir sonraki öğeye eşit veya ondan küçük olup olmadığını kontrol edebilirsiniz. Biz bunu yapabilirsiniz beri bu daha verimlidir O (n) sıralı liste değerlendirirken ise tamamen alır (n O log n) .

Böylece bunu aşağıdakilerle kontrol edebiliriz:

ordered :: Ord a => [a] -> Bool
ordered [] = True
ordered xa@(_:xs) = and (zipWith (<=) xa xs)

Böylece, ikili ağacın aşağıdakileri içeren bir ikili arama ağacı olup olmadığını kontrol edebiliriz:

isBSTree :: Ord a => BinaryTree a -> Bool
isBSTree = ordered . flattenTree

Bence Nullboş bir ağaç olduğu için kendisinin ikili bir arama ağacı olduğunu iddia edebilir . Bu, her düğüm için (düğüm yok), sol alt ağaçtaki öğelerin düğümdeki değerden küçük veya ona eşit olduğu ve sağ alt ağaçtaki öğelerin düğümdeki değerden büyük veya ona eşit olduğu anlamına gelir. .


1

Ağacın üzerinde soldan sağa şu şekilde ilerleyebiliriz:

isBSTtreeG :: Ord a => BinaryTree a -> Bool
isBSTtreeG t = gopher Nothing [Right t]
    where
    gopher  _   []                        =  True
    gopher  x   (Right Null:ts)           =  gopher x ts
    gopher  x   (Right (Node lt v rt):ts) =  gopher x (Right lt:Left v:Right rt:ts)
    gopher Nothing   (Left v:ts)          =  gopher (Just v) ts
    gopher (Just y)  (Left v:ts)          =  y <= v && gopher (Just v) ts

John McCarthy'ningopher esin kaynağı .

Açık aşağı itme listesi, devam geçişiyle ortadan kaldırılabilir,

isBSTtreeC :: Ord a => BinaryTree a -> Bool
isBSTtreeC t = gopher Nothing t (const True)
    where
    gopher  x   Null           g  =  g x 
    gopher  x   (Node lt v rt) g  =  gopher x lt (\case
                                       Nothing -> gopher (Just v) rt g
                                       Just y  -> y <= v && gopher (Just v) rt g)

Şimdiye kadarki en büyük bir elementi korumak yeterlidir.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.