我最近一直在试验遗传算法,现在我想用基因组构建数学表达式(简单来说,就是找到一个与特定结果匹配的表达式)。
我的基因组由字节表示的基因组成。一个基因组可能看起来像这样:{12, 127, 82, 35, 95, 223, 85, 4, 213, 228}。 长度是预定义的(虽然它必须落在一定的范围内),形式也是预定义的。 也就是说,任何条目都可以采用任何字节值。
现在的诀窍是将它翻译成数学表达式。确定基本表达式相当容易,例如:选取前 2 个值并将它们视为乘数,选取第 3 个值并将其选为运算符(+、-、*、/、^、mod),选取第 4 个值作为乘数,然后再次选取第 5 个值作为运算符,对前 2 个乘数的第 3 个运算符的结果进行运算。(或者只是将其作为后缀表达式处理)
当您开始允许优先级规则时,复杂性会上升。 现在,例如,索引 2 下的条目表示“(”,那么您肯定会在更远的地方找到一个“)”,但条目 3 除外,但条目 4 不一定。
当然,很多事情都是如此,你不能以运算符结尾,你不能以一个孤立的数字结尾等等。
现在我可以做一个巨大的 switch 语句(例如),接受所有可能的可能性,但这会使代码难以阅读。 我希望有人知道如何处理这个问题的好策略。
提前致谢!
** 编辑 **
根据要求:我试图实现的目标是制作一个可以为一组数字解析函数的应用程序。 至于我在下面的评论中给出的示例:{4, 11, 30},它可能会提出函数 (X ^ 3) + X
回答:
Belisarius 在评论中给出了一个相同主题的链接:运算符和操作数的排列算法
我的代码:
private static double ResolveExpression(byte[] genes, double valueForX) { // folowing: https://stackoverflow.com/questions/3947937/algorithm-for-permutations-of-operators-and-operands/3948113#3948113 Stack<double> operandStack = new Stack<double>(); for (int index = 0; index < genes.Length; index++) { int genesLeft = genes.Length - index; byte gene = genes[index]; bool createOperand; // only when there are enough possbile operators left, possibly add operands if (genesLeft > operandStack.Count) { // only when there are at least 2 operands on the stack if (operandStack.Count >= 2) { // randomly determine wether to create an operand by threating everything below 127 as an operand and the rest as an operator (better then / 2 due to 0 values) createOperand = gene < byte.MaxValue / 2; } else { // else we need an operand for sure since an operator is illigal createOperand = true; } } else { // false for sure since there are 2 many operands to complete otherwise createOperand = false; } if (createOperand) { operandStack.Push(GeneToOperand(gene, valueForX)); } else { double left = operandStack.Pop(); double right = operandStack.Pop(); double result = PerformOperator(gene, left, right); operandStack.Push(result); } } // should be 1 operand left on the stack which is the ending result return operandStack.Pop(); } private static double PerformOperator(byte gene, double left, double right) { // There are 5 options currently supported, namely: +, -, *, /, ^ and log (math) int code = gene % 6; switch (code) { case 0: return left + right; case 1: return left - right; case 2: return left * right; case 3: return left / right; case 4: return Math.Pow(left, right); case 5: return Math.Log(left, right); default: throw new InvalidOperationException("Impossible state"); } } private static double GeneToOperand(byte gene, double valueForX) { // We only support numbers 0 - 9 and X int code = gene % 11; // Get a value between 0 and 10 if (code == 10) { // 10 is a placeholder for x return valueForX; } else { return code; } } #endregion // Helpers}