Reputation: 31
what is another way to test whether a binary tree is balanced other than recursively calling the size function on the left and right subtrees. abs(size left - size right) <= 1 for the tree to be balanced. I must write an efficient function to satisfy the requirement but like i said does not recursively call the size function on the left and right subtrees.
Upvotes: 1
Views: 3422
Reputation: 24814
You could use a type guaranteed Red-Black Tree. No need to check if it is balanced because the types assure it.
isBalanced = const True
Upvotes: 1
Reputation: 47072
The point about efficiently determining whether a tree is balanced without paying attention to its size, is that once you know the right branch is more than one level deeper than the left branch, it doesn't matter exactly how much deeper it is. 2 levels deeper? 3? 100? We don't care, and it could be considered inefficient to find out only to throw away the result.
isBalanced :: BinaryTree a -> Bool
isBalanced = and . treeToBalanceSize
treeToBalanceSize :: BinaryTree a -> BalanceSize
treeToBalanceSize Empty = []
treeToBalanceSize (Node l r) = True : mergeBalanceSizes (treeToBalanceSize l) (treeToBalanceSize r)
mergeBalanceSizes :: BalanceSize -> BalanceSize -> BalanceSize
mergeBalanceSizes [] [] = []
mergeBalanceSizes [x] [] = [x]
mergeBalanceSizes [] [y] = [y]
mergeBalanceSizes (x : xs) (y : ys) = (x && y) : mergeBalanceSizes xs ys
mergeBalanceSizes _ _ = [False]
type BalanceSize = [Bool]
Satisfy yourself that
tree
is balanced and of size size
, then treeToBalanceSize tree = replicate size True
.tree
is unbalanced, then treeToBalanceSize tree
will end with a False
.mergeBalanceSizes [True] list
does not cause list
to be evaluated beyond its third element.Upvotes: 0
Reputation: 3513
You could define a new binary tree that stores it's depth. Depth is updated on insert and removal, and you can tell if it's balanced by looking at the stored depth value.
It is a nicer solution to calculate recursively depending on how often you are updating the tree. It's cleaner anyway.
Upvotes: 0
Reputation: 204994
So it's pretty easy with recursion, isn't it?
import Data.Maybe (isJust)
getBalancedSize :: (Monad m, Num b, Ord b) => BinaryTree a -> m b
getBalancedSize Empty = return 0
getBalancedSize (Node _ l r) = do
sizeL <- getBalancedSize l
sizeR <- getBalancedSize r
if abs (sizeL - sizeR) <= 1
then return $ sizeL + sizeR + 1
else fail "tree is not balanced"
isBalanced :: BinaryTree a -> Bool
isBalanced = isJust . getBalancedSize
Now suppose you have
fold :: (a -> b -> b -> b) -> b -> Tree a -> b
fold _ b Empty = b
fold f b (Node a l r) = f a (fold f b l) (fold f b r)
There's an obvious way to refactor getBalancedSize
to be a single call to fold
.
getBalancedSize = fold f (return 0) where
f _ l r = do
sizeL <- getBalancedSize l
sizeR <- getBalancedSize r
if abs (sizeL - sizeR) <= 1
then return $ sizeL + sizeR + 1
else fail "tree is not balanced"
But you do need some recursive function to walk the recursive tree structure.
Upvotes: 2
Reputation: 5
It depends on how your binary tree is represented in Haskell. If it's a recursive data structure, recursion is your only weapon...
Upvotes: 1