木がHaskellの二分探索木かどうかを調べる


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)

私がやりたいことは、指定されたツリーがバイナリ検索ツリーであるかどうかを判別する関数を書くことです。私の方法は、リスト内のすべての値をグループ化してインポートData.Listし、リストをソートしてそれらが等しいかどうかを見つけることですが、それは少し複雑です。他のモジュールをインポートせずにこれを行うことはできますか?


flattenTree最初に定義するつもりはありません。Falseノードがルートになっているサブツリー全体をたどる必要がなく、ノードが検索プロパティに違反している場合は、早期に戻ることができます。
chepner

@chepner問題はでありsort、ではなくflattenTree、これは十分に怠惰です。
ネスは

ええ、それは他のいくつかの答えを見た後に私に起こりました。
chepner

回答:


13

ツリーを平坦化せずにそれを行う方法を次に示します。

定義から、ここでは、

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

ツリーを左から右にトラバースしNode、括弧を無視すると、Nullsとasの交互のシーケンスが得られることがわかります。つまり、2つの値の間にがありNullます。

私の計画は、各サブツリーを満たし適していることを確認することです要件:私たちができる洗練それぞれの要件Node我々が間にある値覚えが、その後、テストごとにそれらをNullNullすべての順序の値のペアの間にaがあるため、すべての順序(左から右)のペアが減少しないことをテストします。

要件とは何ですか?これは、ツリー内の値の緩やかな下限と上限です。左端と右端の要件を含む要件を表現するために、次のように、BottomとTop要素を使用して任意の順序を拡張できます。

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

ここで、指定されたツリーが、順序付けと指定された境界の間にあるという要件を満たしていることを確認します。

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

二分探索木は、順番にとの間にある木であるBotTop

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

各サブツリーの実際の極値を計算し、それらを外側にバブリングすると、必要以上の情報が得られ、左または右のサブツリーが空であるエッジの場合は面倒です。要件を維持およびチェックし、それらを内側にプッシュすることは、かなり均一です。


6

ここにヒントがあります:補助関数を作る

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

どこBSTResult aのように定義されます

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

サブツリーの結果を利用して、特に最小値と最大値を計算して、再帰的に処理できるはずです。

あなたが持っている場合たとえば、tree = Node left 20 rightと、isBSTree' left = NonEmptyBST 1 14isBSTree' right = NonEmptyBST 21 45、その後isBSTree' treeでなければなりませんNonEmptyBST 1 45

を除いて同じケースではtree = Node left 24 right、代わりにが必要isBSTree' tree = NotBSTです。

結果をに変換するのBoolは簡単です。


1
または明白なモノイドを定義し、BSTResult aそれに折り込みます。:)(またはそれが合法的なモノイドない場合でも....)
ウィルネス

(しかし、とにかく合法であると思います)
Will Ness、

3

はい、リストを並べ替える必要はありません。すべての要素が次の要素以下かどうかを確認できます。これはO(n)で実行できるため、より効率的ですが、並べ替えられたリストの評価には完全O(n log n)が必要です。

したがって、これを次のように確認できます。

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

ですから、二分木が二分探索木であるかどうかをチェックすることができます:

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

Nullそれは空のツリーなので、それ自体がバイナリ検索ツリーであると主張できると思います。つまり、これは、すべてのノード(ノードがない)で、左側のサブツリーの要素がノードの値以下であり、右側のサブツリーの要素がすべてノードの値以上であることを意味します。 。


1

次のようにツリーを左から右に進めることができます。

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にgopher触発されました。

明示的なプッシュダウンリストは、継続渡しで削除できます。

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)

これまで最大の要素を1つ維持するだけで十分です。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.