caml-list - the Caml user's mailing list
 help / color / mirror / Atom feed
From: Brian Hurt <brian.hurt@qlogic.com>
To: Stalkern 2 <stalkern2@tin.it>
Cc: <caml-list@inria.fr>
Subject: Re: [Caml-list] tree walking with... specular rec functions? what else?
Date: Fri, 9 May 2003 10:23:20 -0500 (CDT)	[thread overview]
Message-ID: <Pine.LNX.4.33.0305090959170.2037-100000@eagle.ancor.com> (raw)
In-Reply-To: <200305091156.47892.stalkern2@tin.it>

On Fri, 9 May 2003, Stalkern 2 wrote:

> Hello to everybody 
> 
> I've a simple tree structure and I want to walk it. Since in such a simple  
> tree structure I can go AFAIK only sidewards or upwards/downwards, and I need 
> to do both, I guess what can be an efficent way to do so.

Recursion is your friend.  Let's assume we have a type like:

type 'a tree = Leaf
             | Node of 'a * 'a tree * 'a tree

This is the most basic of tree data structures.  Data can be held in any 
node, the bottom of the tree is marked by leafs.  We want to define a walk 
function, which calls a function f on all elements of the tree, in a 
depth-first pattern.  This is simple:

let rec walk f tree =
    match tree with
        Leaf -> ()
        | Node(data, left, right) ->
            walk f left;
            f data;
            walk f right
;;

Obvious variations include which order you evaluate the last three 
statements as.  Equally valid would be: f data; walk f left; walk f right;
and walk f left; walk f right; f data; .

Doing a breadth first is a little bit more tricky, as you have to keep a 
list of the next nodes down:

let rec walk f tree =
    let rec inner lst accum =
        match lst with
            [] -> List.rev accum
            | Leaf :: t -> inner t accum
            | Node(data, left, right) :: t -> 
                f data;
                inner t (right :: left :: accum)
    in
    let rec outer lst =
        if (List.length lst) == 0 then ()
        else outer (inner lst [])
    in
    outer ( [ tree ] )
;;

Basically, I keep a list of the nodes at each level.  As I walk the list,
calling f on all non-leaf nodes, I create the list of the nodes at the
next level down.  Note the List.rev trick I pull, to keep the nodes in the
"expected" order.  

> 	2) I think that this approach isn't flexible. What if I had a
> tree where I can move in other directions as well? Or if I were
> dealing with 5-generation grandchildren only?

A variant of the breadth-first walking I did above could easily generate a
list of all nodes on level 5.  Dealing with multiple children is easy.  
Assume that instead of the binary tree structure we had above, we had an 
n'ary tree structure, like:

type 'a tree = Leaf
             | Node of 'a * 'a tree list

Each node holds data and a list of 0 or more children it has.  Depth first 
search would then become:

let rec walk f tree =
    let rec loop lst =
        match lst with
            [] -> ()
            | h :: t -> walk f h ; loop t
    in
    match tree with
        Leaf -> ()
        | Node(data, children) ->
            f data;
            loop children
;;

A similiar modification works to do breadth first walking.  More general
data structures aren't really trees anymore, they're graphs.  But graph
walking works more or less the same way.

Hope this helps.

Brian


-------------------
To unsubscribe, mail caml-list-request@inria.fr Archives: http://caml.inria.fr
Bug reports: http://caml.inria.fr/bin/caml-bugs FAQ: http://caml.inria.fr/FAQ/
Beginner's list: http://groups.yahoo.com/group/ocaml_beginners


  reply	other threads:[~2003-05-09 15:12 UTC|newest]

Thread overview: 9+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2003-05-09  9:56 Stalkern 2
2003-05-09 15:23 ` Brian Hurt [this message]
2003-05-12 12:57   ` John Carr
2003-05-12 13:35     ` Michal Moskal
2003-05-12 15:06       ` David Brown
2003-05-12 15:24         ` Xavier Leroy
2003-05-11 16:02 ` Xavier Leroy
2003-05-12  6:55   ` Stalkern 2
2003-05-12 10:14     ` Gérard Huet

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=Pine.LNX.4.33.0305090959170.2037-100000@eagle.ancor.com \
    --to=brian.hurt@qlogic.com \
    --cc=caml-list@inria.fr \
    --cc=stalkern2@tin.it \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).