将前缀表达式树向量转换为ORF/Karva表示法表达式树向量
Convert a prefix expression tree vector to a ORF/Karva notation expression tree vector
好吧,这有点棘手。
我有一堆采用表达式树的代码,比如:
((a + b)/(c + d) + sqrt(e))
以前缀形式存储在向量中(我使用C++,但我只需要算法):
+(/(+(a,b),+(c,d)),sqrt(e))
//括号只是为了帮助你阅读。每个运算符和终端都是向量中的一个元素。
现在有另一种表示表达式树的方法,称为ORF形式的
(论文第三页:http://arxiv.org/ftp/cs/papers/0102/0102027.pdf)
在这种形式中,你表示树就像从左到右、从上到下阅读树一样。
((a + b)/(c + d) + sqrt(e))
现在变成:
+/sqrt++eabcd
我一直没能做的是创建一个可以转换的算法:
+/sqrt++eabcd
/ORF进入:+(/(+(a,b),+(c,d)),sqrt(e))
//前缀
到目前为止,我所拥有的只是一些代码,可以在不同级别上获得树的宽度:
bool ConvertPrefixToORF(const std::vector<Node> & individual,
std::vector<Node> & ETindividual){
bool all_terminal = false;
int breadth;
int breadthOfDepth[individual.size()];
int depthCounter = 0;
breadthOfDepth[0] = 1;
//Resize only once.
ETindividual.reserve(individual.size());
while (all_terminal == false) {
//Reset breadth
breadth = 0;
//Iterate over next level and calculate depth of level after that.
for (int i = 0; i < breadthOfDepth[depthCounter]; i++) {
all_terminal = true;
//If the individual is a function...
if (individual[current+i].isFunction()) {
//Get individual from i'th item at this depth
function f = individual[current + i];
//Increment breadth of next level with arity
breadth += f->getArity();
//if a single function is found
all_terminal = false;
}
}
//Go down a level in the tree.
depthCounter++;
//Set the breadth of that tree depth:
breadthOfDepth[depthCounter] = breadth;
}
}
提前感谢您的帮助!这让我头疼。哦,这对性能至关重要:(
我的策略是构建解析树,然后先深入它以生成前缀表示法。
您可以使用队列从ORF构建解析树。当您遇到每个运算符(或术语)时,请将其作为队列头的运算符的子项。当队列顶端的节点有足够的子节点时,将其从队列中弹出。
在你的例子中。。。从+
开始,并将其推送到队列中(初始元素的特殊情况)。
接下来处理/
。由于队列头部的+
没有子级(但需要两个),因此将/
附加到+
作为其第一个子级,并将/
推送到队列中。所以现在队列看起来像:
+/
树看起来像
+
/ .
. .
其中"."是等待填写的元素。
接下来是sqrt
。由于+
位于队列的头部,并且还没有两个子级,因此将sqrt
附加到+
,并将sqrt
推送到队列上。所以现在队列看起来像:
+/sqrt
树看起来像
+
/ sqrt
. . .
接下来是第二个CCD_ 18。队列的头是第一个+
,但现在它已经有了所有的子级。所以把它从队列中弹出。队列的下一个元素是/
,它还没有子元素,所以这个+
成为它的子元素并进入队列的后面。队列现在读取:
/sqrt+
树现在是:
+
/ sqrt
+ . .
. .
接下来,第三个CCD_ 22成为CCD_。因此,队列将是:
/sqrt++
树将是(对不起,我的ASCII艺术很弱):
+
/ sqrt
+ + .
. . . .
现在满足了/
,所以当您点击e
时,您将从队列中弹出/
。现在sqrt
是队列的开始,所以e
被附加到它。队列现在是:
sqrt++
树是:
+
/ sqrt
+ + e
. . . .
接下来的四次迭代显然将a、b、c、d分配给剩余的叶子,从而得到解析树。
顺便说一句,std::dequeue
是用于队列的完美数据结构。
只需构建一个树T。每个节点都是一个元组(terminal,)
、(unary_operator, operand)
或(binary_operator, first_operand, second_operand)
。操作数本身为树中节点的索引。
例如,表达式a + (b / c)
将具有树T[0] = (+, 1, 2), T[1] = (a,), T[2] = (/, 3, 4), T[3] = (b,), T[4] = (c,)
。一旦你有了这个,就做一个预购。以下是用于此操作的Python代码。
def preorder(T, i):
X = [T[i][0]]
if len(T[i]) > 1:
X.extend(preorder(T, T[i][1]))
if len(T[i]) > 2:
X.extend(preorder(T, T[i][2]))
return X
def convert(A):
binary_operators = ['+', '-', '/']
unary_operators = ['sqrt']
left = 0
right = 0
T = dict([(i, ()) for i in range(len(A))])
for a in A:
if a in binary_operators:
T[left] = (a, right + 1, right + 2)
right += 2
elif a in unary_operators:
T[left] = (a, right + 1)
right += 1
else:
T[left] = (a,)
left += 1
return preorder(T, 0)
def main(argv=None):
A = ['+', '/', 'sqrt', '+', '+', 'e', 'a', 'b', 'c', 'd']
print convert(A)
当您从ORF构建T时,保留一个左右指针,该指针告诉您必须在表达式树中填写的第一个节点,而right则告诉您最后一个节点。
- 如何将正则表达式向量与一个字符串匹配?
- 创建结构体向量,表达式:向量下标超出范围
- 将所有正则表达式匹配项保存在向量上
- 使用向量将给定表达式转换为波兰表示法时出现运行时错误
- 表达式必须具有指向对象的指针类型(指针向量)
- 错误:以增量方式填充向量时,表达式必须具有整数或无作用域枚举类型
- λ表达式(向量的总和)
- C 表达式:向量下标出范围错误线:1733
- 采用向量中包含的唯一指针的 Lambda 表达式
- 如何在一个表达式中将 char[] 转换为向量<char>(可移植)
- 在 lambda 表达式中自动推导出的类型是什么,用于修改 bool 类型的向量(特殊容器)
- 向量空Push_back在令牌之前调用'{'预期的主表达式
- 如果返回了向量的一个项,lambda表达式的返回类型是什么
- c++正则表达式:如何捕获子矩阵的向量
- 指向对象的指针向量,无法访问对象数据字段。(表达式必须具有指针类型)
- 表达式必须具有类类型.- 类对象的向量
- 我应该如何使用表达式模板来实现数学向量类的标量乘法
- 表达式必须具有整数或无作用域枚举类型,并带有字符串向量
- 表达式:VS2015单元测试框架中向量测试的范围外错误
- 什么是矩阵表达式和向量表达式类在Boost.uBLAS