algorithm - 我需要一种算法来遍历带有可选节点和替代节点的树,以计算所有可能的路径

标签 algorithm tree-traversal

给定以下树,它是一种 Backus-Nauf 形式的符号,其中 |表示或(所以B是F或G)和[]表示可选(所以H是可选的)

Def: A B C
A: D E
B: F | G
C: [H] I
D: a b
E: c d
F: e f
G: g h
H: i j
I: k l

a: a
b: b
c: c
d: d
e: e
f: f
g: g
h: h
i: i
j: j
k: k
l: l    

可以看作

              Def
    A          B          C
 D     E    F  |  G   [H]    I
a b   c d  e f   g h  i j   k l

我需要遍历提取叶节点的树并转换为下面给出可能路径的树

 Def
     a
         b
             c
                 d
                     e
                         f
                             i
                                 j
                                     k
                                         l
                             k
                                 l
                     g
                         h
                             i
                                 j
                                     k
                                         l
                             k
                                 l

所以可能的路径是

abcdefijkl

abcdefkl

abcdghijkl

abcdghkl

我有一个 repo一个失败的 C# 单元测试(设置树并调用一个基本的 recusive walker)应该有望澄清我想要实现的目标。

我想不通的是如何在可选节点和替代节点处分支,同时保持正确的叶子以将后续叶子附加到。

最佳答案

非递归广度优先搜索可能看起来像这样(伪代码)。通过调用 findAllLeafPaths(Def) 开始:

var allPathsFound = {}
function findAllLeafPaths(startNode) {
    var tokenSequenceQueue = {
        createTokenSequenceFrom(startNode)
    }
    while (tokenSequenceQueue.isNotEmpty()) {
        var tokenSequence = tokenSequenceQueue.removeFirst()
        var allLeaves = true
        for (every token T in tokenSequence) {
            if isLeafNode(T)
                continue
            else if T's rule is "T: Y Z" {
                allLeaves = false
                tokenSequenceQueue.append(tokenSequence.replace(T, Y + Z))
            } else if T's rule is "T: [Y] Z" {
                allLeaves = false
                tokenSequenceQueue.append(tokenSequence.replace(T, Y + Z))
                tokenSequenceQueue.append(tokenSequence.replace(T, Z))
            } else if T's rule "T: Y | Z" {
                allLeaves = false
                tokenSequenceQueue.append(tokenSequence.replace(T, Y))
                tokenSequenceQueue.append(tokenSequence.replace(T, Z))
            }
        }
        if (allLeaves) {
            allPathsFound.add(tokenSequence)
        }
    }
}

这里还有一个递归的深度优先版本。我更喜欢第一个,因为递归使您的堆栈受到结果路径的最大可能长度的支配:

var allPathsFound = {}
function toLeafNodes(tokenSequence) {
    var allLeaves = true
    for every token T in tokenSequence {
        if isLeafNode(T)
            continue
        else if T's rule is "T: Y Z" {
            allLeaves = false
            toLeafNodes(tokenSequence.replace(T, Y + Z)
        } else if T's rule is "T: [Y] Z" {
            allLeaves = false
            toLeafNode(tokenSequence.replace(T, Y + Z)
            toLeafNode(tokenSequence.replace(T, Z)
        } else if T's rule "T: Y | Z" {
            allLeaves = false
            toLeafNode(tokenSequence.replace(T, Y)
            toLeafNode(tokenSequence.replace(T, Z)
        }
    }
    if (allLeaves) {
        allPathsFound.add(tokenSequence)
    }
}

[编辑] 非递归版本目前一次替换一个,并立即将结果序列放入队列。它可以进一步优化,一次完成所有可能的替换。

关于algorithm - 我需要一种算法来遍历带有可选节点和替代节点的树,以计算所有可能的路径,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50100971/

相关文章:

c - 给定层序遍历如何构造树?

algorithm - 在树中搜索具有特定属性的节点并分配树的属性的有效方法

tree - 使用抽象基类类型遍历整个 JAXB 对象树

c++ - 在二维数组的矩形区域内快速找到最大值的方法

algorithm - 为什么中序和先序遍历对于创建算法来确定 T2 是否是 T1 的子树很有用

algorithm - 根据 morris inorder,这棵树的下一步是什么?

ruby 遍历哈希

java - 给定一个整数数组,找到所有 "maximal"子集

algorithm - 如果形成循环的一条边已知,则列出图中形成循环的所有边的最快方法

c# - 从存储的数据构造链表的最有效方法?