Scopri se un albero è un albero di ricerca binario in 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)

Quello che voglio fare è scrivere una funzione per determinare se l'albero dato è un albero di ricerca binario, il mio metodo è quello di raggruppare tutti i valori in un elenco e importare Data.Liste quindi ordinare l'elenco per scoprire se sono uguali, ma è un po 'complicato. Possiamo farlo senza importare altri moduli?


Non definirei per flattenTreeprimo. Puoi tornare Falsepresto se un nodo viola la proprietà di ricerca senza dover attraversare l'intera sottostruttura radicata su quel nodo.
Chepner,

@chepner il problema è con sort, non con flattenTree, che è abbastanza pigro.
Will Ness,

Sì, mi è venuto in mente dopo aver visto alcune delle altre risposte.
Chepner,

Risposte:


13

Ecco un modo per farlo senza appiattire l'albero.

Dalla definizione, qui,

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

si può vedere che attraversare l'albero da sinistra a destra, ignorando Nodee le parentesi, ti dà una sequenza alternata di Nulls e as. Cioè, tra ogni due valori, c'è un Null.

Il mio piano è di verificare che ogni sottostruttura soddisfi i requisiti adeguati : possiamo affinare i requisiti in ciascuno di essi Node, ricordando quali valori ci troviamo tra, quindi testarli in ciascuno di essi Null. Dato che esiste una Nullcoppia di valori tra ogni in ordine, avremo verificato che tutte le coppie in ordine (da sinistra a destra) non sono decrescenti.

Qual è un requisito? È un limite inferiore e superiore allentato sui valori dell'albero. Per esprimere i requisiti, compresi quelli all'estremità più a sinistra e più a destra, possiamo estendere qualsiasi ordine con Bottom ed Topelementi, come segue:

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

Ora controlliamo che un determinato albero soddisfi i requisiti di essere sia in ordine sia tra determinati limiti.

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

Un albero di ricerca binario è un albero che è in ordine e tra Bote Top.

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

Il calcolo dei valori estremi effettivi in ogni sottostruttura, il loro gorgogliamento verso l'esterno, ti dà più informazioni di quante ne hai bisogno, ed è complicato nei casi limite in cui una sottostruttura sinistra o destra è vuota. Mantenere e verificare i requisiti , spingendoli verso l'interno, è piuttosto più uniforme.


6

Ecco un suggerimento: crea una funzione ausiliaria

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

dove BSTResult aè definito come

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

Dovresti essere in grado di procedere in modo ricorsivo, sfruttando i risultati sulle sottostrutture per guidare il calcolo, in particolare il minimo e il massimo.

Ad esempio, se hai tree = Node left 20 right, con isBSTree' left = NonEmptyBST 1 14e isBSTree' right = NonEmptyBST 21 45, allora isBSTree' treedovrebbe essere NonEmptyBST 1 45.

Nello stesso caso, tranne tree = Node left 24 right, dovremmo invece averlo isBSTree' tree = NotBST.

La conversione del risultato in Boolè quindi banale.


1
o definire l'ovvio Monoid BSTResult ae piegarlo in esso. :) (o anche se non è un Monoid legale ...)
Will Ness,

(ma è lecito, comunque, credo)
Will Ness,

3

, non è necessario ordinare l'elenco. Puoi verificare se ogni elemento è minore o uguale all'elemento successivo. Questo è più efficiente poiché possiamo farlo in O (n) , mentre la valutazione dell'elenco ordinato richiede completamente O (n log n) .

Possiamo quindi verificarlo con:

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

Quindi possiamo verificare se l'albero binario è un albero di ricerca binario con:

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

Penso che si possa affermare che esso Nullstesso è un albero di ricerca binario, dal momento che è un albero vuoto. Ciò significa quindi che per ogni nodo (non ci sono nodi) gli elementi nella sottostruttura sinistra sono inferiori o uguali al valore nel nodo e gli elementi nella sottostruttura destra sono tutti maggiori o uguali al valore nel nodo .


1

Possiamo procedere da sinistra a destra sull'albero in questo modo:

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

Ispirato da John McCarthy'sgopher .

L'elenco a discesa esplicito può essere eliminato con il passaggio di continuazione,

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)

Mantenere solo un elemento, il più grande finora , è sufficiente.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.