Как я могу проверить, если BST действует?

голоса
6

Как я могу проверить, если BST является допустимым, учитывая его определение и использование обобщенной версии складки для 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)

Идея , чтобы проверить , что значение узла больше , то все значения в левом поддереве и меньше всех значений в его правой поддерево. Это должно быть Trueдля всех узлов в дереве. Функция bstListпросто вывести список (упорядоченных) значений в BST.

Конечно, что-то вроде этого не будет работать:

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

потому что, например, применяя функцию сгиба к узлу 19заканчивается all (<19) (bstList True) && all (>19) (bstList True).

BST

Задан 12/02/2011 в 23:22
источник пользователем
На других языках...                            


4 ответов

голоса
4

Ваша проблема , кажется, что вы теряете информацию , потому что ваша функция возвращает только логическое значение , когда он рассматривает левые и правые поддеревья. Таким образом изменить его и вернуть минимальные и максимальные значения поддеревьев. (Это, вероятно , более эффективным , а также, так как вам не нужно использоваться , bslistчтобы проверить все элементы больше)

И сделать функцию обертки, чтобы игнорировать это «вспомогательное» значение после того, как вы сделали, конечно.

Ответил 12/02/2011 в 23:38
источник пользователем

голоса
4

(Пожалуйста , не ставьте ограничения на класс типов в dataтип.)

BST действует тогда и только тогда в-порядке обхода монотонно возрастает.

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

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

isBST = ordered . flatten
Ответил 13/02/2011 в 05:53
источник пользователем

голоса
0

Если вы не настаиваете на использовании раз вы можете сделать это следующим образом:

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
Ответил 13/02/2011 в 07:45
источник пользователем

голоса
2

Хороший способ кодирования это опираться на обходе, предоставленной Data.Foldable.

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

Мы можем получить экземпляр этого автоматически, используя расширение, но нам нужно изменить порядок полей конструктора узла, чтобы обеспечить нам в обход заказ.

В то время как мы в этом, мы должны устранить ограничения на самом типе данных. На самом деле они не дают никакой пользы, и были удалены из языка по состоянию на Haskell 2011. (Если вы хотите использовать такие ограничения, вы должны поместить их на экземплярах классов, а не от типа данных.)

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

Сначала определим , что это значит для списка будут отсортированы строго.

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.

Тогда мы можем использовать toListметод , предоставленный Data.Foldableи выше помощник.

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

Мы также можем осуществить это более непосредственно, как вы просили. Так как мы удалили ложные ограничения на типе данных, мы можем упростить определение вашей складки.

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)

Теперь нам нужен тип данных для моделирования результата нашего катаморфизма, которая является то , что мы либо не имеют узлов ( Z), или диапазон строго возрастающие узлы ( T) или не удались ( X)

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

И мы можем реализовать isBSTнапрямую

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

Это немного утомительно, так что, возможно, было бы лучше, чтобы разложить так, как мы сочинить Временные государства немного:

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

Лично я бы, наверное, просто использовать Складная экземпляр.

Ответил 13/02/2011 в 16:31
источник пользователем

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