我的树遍历代码出了什么问题?

时间:2011-02-26 08:30:11

标签: algorithm f# tree traversal

我有一个简单的树,如此定义:

type BspTree =
    | Node of Rect * BspTree * BspTree
    | Null

我可以像这样获得叶子节点(我的树“dungeon”中的房间)的集合,它似乎有效:

let isRoom = function
    | Node(_, Null, Null) -> true
    | _ -> false

let rec getRooms dungeon =
    if isRoom dungeon then
        seq { yield dungeon }
    else
        match dungeon with
        | Node(_, left, right) ->
            seq { for r in getRooms left -> r
                  for r in getRooms right -> r }
        | Null -> Seq.empty

但是现在我正在尝试让姐妹叶节点房间,所以我可以将它们与走廊连接起来,而且我失败了(我经常这样做)。这是我的尝试:

let rec getCorridors dungeon =
    match dungeon with
    | Null -> failwith "Unexpected null room"
    | Node(_, left, right) ->
        match left, right with
        | Null, Null -> Seq.empty
        | Node(leftRect, _, _), Node(rightRect, _, _) ->
            if isRoom left && isRoom right
            then seq { yield makeCorridor leftRect rightRect }
            else seq { for l in getCorridors left -> l
                       for r in getCorridors right -> r }
        | _ -> failwith "Unexpected!"

我最后得到一个空的seq。无论如何,这一切都伤害了我的大脑,而且我知道任何人都不会勉强通过它,但我认为这不会让人感到伤心。

1 个答案:

答案 0 :(得分:4)

正如罗伯特评论的那样,也许你的makeCorridor功能需要一些关注。 我已经调整了你的代码,制作了我自己的makeCorridor函数并用int替换了Rect。

我使用了活动模式来确定BspTree何时是一个房间。我还使用yield! sequence代替for x in sequence -> x。这些修改导致相同的行为。我只想展示一个活动模式可以做什么:

type BspTree =
    | Node of int * BspTree * BspTree
    | Null

let (|IsRoom|_|) dungeon = 
    match dungeon with
    | Node(_,Null,Null) -> Some dungeon
    | _ -> None

let rec getRooms = function
    | IsRoom dungeon -> Seq.singleton dungeon
    | Null -> Seq.empty
    | Node (_, left, right) -> seq { yield! getRooms left
                                     yield! getRooms right }

let makeCorridor leftNode rightNode =
    match leftNode, rightNode with
    | Node(left,Null,Null), Node(right,Null,Null) -> 
        sprintf "(%d) -> (%d)" left right
    | _ -> failwith "Illegal corridor!"

let rec getCorridors = function
    | Null -> failwith "Unexpected null room"
    | Node(_, Null, Null) -> Seq.empty
    | Node(_, IsRoom left, IsRoom right) -> seq { yield makeCorridor left right }
    | Node(_, left, right) -> seq { yield! getCorridors left
                                    yield! getCorridors right }

示例:

let dungeon = 
    Node(1, Node(2, Node(4,Null,Null), 
                    Node(5,Node(8,Null,Null),
                           Node(9,Null,Null))),
            Node(3, Node(6,Null,Null), 
                    Node(7,Null,Null)))

FSI的结果:

> getCorridors dungeon;;
val it : seq<string> = seq ["(8) -> (9)"; "(6) -> (7)"]