Πώς μπορώ να ελέγξω αν ένα 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).

μια

Δημοσιεύθηκε 12/02/2011 στις 23:22
πηγή χρήστη
Σε άλλες γλώσσες...                            


4 απαντήσεις

ψήφοι
4

Το πρόβλημά σας φαίνεται να είναι ότι μπορείτε να χάσετε πληροφορίες, επειδή η λειτουργία σας επιστρέφει μόνο μια δυαδική όταν εξετάζει τα αριστερά και δεξιά υποδένδρων. Έτσι το αλλάξετε για να επιστρέψει και τις ελάχιστες και μέγιστες τιμές των υποδένδρων. (Αυτό είναι ίσως πιο αποτελεσματική, καθώς, δεδομένου ότι δεν χρειάζεται να χρησιμοποιηθεί bslistγια τον έλεγχο όλων των στοιχείων πια)

Και κάνει μια λειτουργία περιτύλιγμα να αγνοήσει αυτές τις «βοηθητικές» τιμές αφού τελειώσετε, φυσικά.

Απαντήθηκε 12/02/2011 στις 23:38
πηγή χρήστη

ψήφοι
4

(Παρακαλώ μην θέσει typeclass περιορισμούς στο 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)

Τώρα χρειαζόμαστε έναν τύπο δεδομένων για να διαμορφώσει το αποτέλεσμα της catamorphism μας, η οποία είναι ότι έχουμε είτε δεν κόμβους ( 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