Joe
Joe

Reputation: 365

Finding a leaf with value x in a binary tree

I have this question to do:

"Define a function findpath:: BTree a -> a -> Path (where Btree a is defined as in the previous questions) that, given a binary tree t and a value x, returns a path from the root of t to a leaf with value x if there is one, and the value Nothing otherwise. The running time of your program should be linear in the number of nodes in the tree."

So far I have:

data Maybe a = Nothing | Just a
data BTree a = Leaf a | Fork (BTree a) (BTree a)
type Path = Maybe [Dir]
data Dir = Left | Right

findpath :: Eq a => BTree a -> a -> Path
findpath (Leaf y) x = if y==x then ??? else Nothing
findpath (Fork l r) x = nodepath (findpath l x) (findpath r x) where
   nodepath :: Path -> Path -> Path
   nodepath Nothing Nothing = Nothing
   nodepath Nothing pathr = Just [R]
   nodepath pathl Nothing = Just [L]

I still can't work how to build the final answer in the (Leaf y) case

Upvotes: 0

Views: 1482

Answers (1)

pigworker
pigworker

Reputation: 43383

Your language, about what you thought the program should do, suggests to me that you need help to escape from the trap of imperative thinking. Let me try to offer some help, based on thinking about what things are, not what things do.

For findpath (Leaf y) x, you're heading in the right direction. You just need to give if a lowercase i, and think about what the correct Path to a Leaf must be.

Now, let's think about the other possibility. You know more than that it's some t. You know that you're really trying to figure out what

findpath (Node l r) x

is (what it =, indeed), because that's the other possibility for a BTree. Think of splitting the problem by asking "Is this BTree a (Leaf y) or a (Node l r)?" as one conceptual step of program design. Now, in order to figure out what the above left-hand side equals, you're entitled to some recursively computed information, namely what

findpath l x

and

findpath r x

are. If you know Path information for both l and r, can you say what the Path for the whole Node l r is? Let me rephrase that question by writing it in Haskell:

findpath :: Eq a => BTree a -> a -> Path
findpath (Leaf y)   x = if y==x then ??? else Nothing
findpath (Node l r) x = nodepath (findpath l x) (findpath r x) where
  nodepath :: Path -> Path -> Path
  nodepath ???

I have expressed my question by introducing a helper function nodepath which takes as arguments the recursively computed information. Now you can try to implement nodepath by pattern matching on those two paths for the left and right subtrees, respectively. If you know whether they are (Just p) or Nothing, then you should be able to say what the path for the whole node must be.

Lesson one, the useful thoughts are of the form: "If this is like such-and-such, then that must be so-and-so.". Being, not doing.

Lesson two, the basic method of programming over a datatype is: split into constructor cases (Leaf versus Node, Just versus Nothing); collect useful information from any substructures by recursive calls; say what the value for the whole structure must be.

If you follow my advice and figure out what nodepath should be, you may find that it's simple enough not to merit being a separate named definition. In that case, just replace the nodepath call with its meaning and cut out the where-clause. But it's good to start by introducing nodepath, as it expresses a useful conceptual step towards solving the problem.

Upvotes: 13

Related Questions