鉴于以下树是一种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#单元测试(设置树并调用一个基本的重复漫步者),这应该有希望澄清我想要实现的目标。
我无法弄清楚如何在可选节点和替代节点上进行分支,同时保持正确的叶子以附加后续叶子。
答案 0 :(得分:1)
非递归广度优先搜索可能会沿着这些行看(伪代码)。通过致电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)
}
}
[编辑]非递归版本目前一次替换一个,并立即将结果序列放在队列中。它可以进一步优化,一次性完成所有可能的替换。
答案 1 :(得分:0)
还有另一种方法可以根据您的定义构建树。考虑:
void printStuff(int x){
while(true){
std::cout <<" Hi from thread 1 in group " << x << std::endl;
boost::this_thread::sleep( boost::posix_time::milliseconds(1000) );
}
}
void pstwo(int x){
while(true){
std::cout <<" Hi from thread 2 in group " << x << std::endl;
boost::this_thread::sleep( boost::posix_time::milliseconds(1500) );
}
}
int main()
{
boost::asio::io_service io_service;
boost::asio::io_service::work work(io_service);
boost::asio::io_service io_service2;
boost::asio::io_service::work work2(io_service2);
boost::thread_group threads;
boost::thread_group threadsTwo;
for (std::size_t i = 0; i < 2; ++i)
threads.create_thread(boost::bind(&boost::asio::io_service::run, &io_service));
for (std::size_t i = 0; i < 2; ++i)
threadsTwo.create_thread(boost::bind(&boost::asio::io_service::run, &io_service2));
io_service.post(boost::bind(printStuff,1));
io_service.post(boost::bind(pstwo,1));
io_service2.post(boost::bind(printStuff,2));
io_service2.post(boost::bind(pstwo,2));
boost::this_thread::sleep( boost::posix_time::milliseconds(10000));
io_service.stop();
std::cout<<"------------------"<<std::endl;
boost::this_thread::sleep( boost::posix_time::milliseconds(10000));
io_service.run();
io_service2.stop();
std::cout<<"-----------------"<<std::endl;
boost::this_thread::sleep( boost::posix_time::milliseconds(10000));
io_service.stop();
threads.join_all();
threadsTwo.join_all();
return 0;
}
从
开始Def: A B C
A: D E
B: F | G
C: [H] I
然后用D E替换A:
A
\
B
\
C
使用B(替换为F | G)和C(替换为[H] I)执行相同的操作,然后得到:
D
\
E
\
B
\
C
现在,如果您对该树执行递归深度优先遍历,则会获得有效字符串:
D
\
E
/ \
F G
/ \ / \
I H I H
\ \
I I
当您输出字符串时,您可以用&#34; b&#34;等替换D.
我一步一步地展示了它,但你可以一次性完成所有这些。