除了向量,是否有更合适的解决方案?
[6, 5, 3]
2x^3 - 4x + 7
会被表示为:[2, 0, -4, 7]
多项式的次数由列表长度减一确定。这种表示法有一个严重的缺点:对于稀疏多项式,列表将包含大量零。
更合理的稀疏多项式项列表表示方法是作为非零项的列表,其中每个项都是一个包含该项次数和系数的列表;多项式的次数由第一项的次数确定。例如,多项式x^100+2x^2+1
将被表示为以下列表:
[[100, 1], [2, 2], [0, 1]]
[3, 5, 6]
,这样 for (i=0; i<n; i++) sum += array[i]*x^i
。 - user列表并不是唯一的选择。
你可以使用一个映射(字典)将指数映射到相应的系数。
使用映射,你的示例代码将会是:
{2: 6, 1: 5, 0: 3}
(系数,指数) 对列表是非常标准的。如果您知道您的多项式是密集的,也就是说,所有的指数位置都是小整数,范围在0到一些小的最大指数之间,您可以使用数组,就像我看到Óscar Lopez刚刚发布的那样。
Expression<Func<double,double>> polynomial = x => (x * x + 2 * x - 1);
double result = polynomial.Compile()(23.0);
y(x) = x^1000 + 1
将数据结构与多项式顺序绑定的方法对于这种病态情况来说是非常浪费的。
只需将系数存储在数组或向量中。例如,在 C++ 中,如果您仅使用整数系数,则可以使用 std::vector<int>
,或者对于实数,可以使用 std::vector<double>
。然后,您只需按顺序推送系数,并通过变量指数号访问它们。
例如(再次在 C++ 中),要存储 5*x^3 + 9*x - 2,您可以执行以下操作:
std::vector<int> poly;
poly.push_back(-2); // x^0, acceesed with poly[0]
poly.push_back(9); // x^1, accessed with poly[1]
poly.push_back(0); // x^2, etc
poly.push_back(5); // x^3, etc
向量/数组是显而易见的选择。根据表达式的类型,您可以考虑某种稀疏向量类型(自定义制作,即基于字典或甚至是链表,如果您的表达式有2-3个非零系数,则为5x^100+x)。
在任一情况下,通过自定义类/接口公开将是有益的,因为您稍后可以替换实现。如果您计划编写大量表达式操作代码,您可能希望提供标准操作(+,-,*,equals)。
你需要存储两个东西:
在标准C++中,“std::vector<>”和“std::list<>”都可以实现。
你还可以将它转化为逆波兰表示法:
6x^2 + 5x + 3 -> x 2 ^ 6 * x 5 * + 3 +
在这里,x
和数字被“推送”到堆栈中,操作(^、*、+)获取堆栈中最顶端的两个值并用操作的结果替换它们。最终,您将在堆栈上获得结果值。
以这种形式计算任意复杂表达式非常容易。
这种表示法也接近于表达式的树形表示法,其中非叶子树节点表示操作和函数,而叶子节点则表示常量和变量。
树的好处在于您可以轻松评估表达式,还可以执行象征性微分等操作。两者都具有递归性质。