一. 概念引入
1.定义
(1)x 的 n 次多项式: P(x) = anxn + an-1xn-1 + ... + a1x + a0。(其中 x 是底数, n 是指数, ai 是每一项前面的系数, 0 ≤ i ≤ n ,并且最高次项前面的系数不为 0 )
2. 实例分析
(1)求 xn 的方法:
xn = x · x · … · x (共 n 个 x ),显然,式子中执行了 n - 1 次乘法。
取 x = 2, n = 3 时,该项为 23 = 2 × 2 × 2,可以看出,执行了 2 次乘法。
(2)求 x 的 n 次多项式的方法:
假设有多项式 P(x) = anxn + an-1xn-1 + ... + a1x + a0。先看第一项 anxn ,其中 xn 执行了 n - 1 次乘法,再与 an 相乘,共执行 n 次乘法。其余各项同理。
取 x = 2, n = 4, 系数为 1 时, P(2) = 24 + 23 + 22 + 21 + 1
二. 多项式求值常规算法
继续以上例来说明问题:取 x = 2, n = 4, 系数为 1 时, P(2) =24 + 23 + 22 + 21 + 1。
当我们用正常思路去计算,即先算第一项,再算第二项,直到算出每项结果,最后将各项结果相加。先算第一项: 2 × 2 × 2 × 2 ,再算第二项: 2 × 2 × 2, 再算第三项: 2 × 2。该算法的时间复杂度是 O(n2)。我们可以发现,其中有很多重复步骤。第一项已经做完了大部分工作,其余项为什么要把第一项的劳动成果弃之不用呢?
三. 霍纳法则
霍纳将多项式进行变形:P(x) = a3x3 + a3x2 + a1x + a0 → P(x) = x ( x ( x ( a3 ) + a2 ) + a1 ) + a0 ,这样执行多项式求值,每一次的结果都能得到充分的利用,不难看出,霍纳算法的时间复杂度是 O( n )
四. 代码实现
1. 常规算法
这里我手动实现了一个函数 cal_power,用于计算 x 的 n 次方。
1 int cal_power(int x, int n) { 2 int product = x; 3 for (int i = 0; i < n - 1; ++i) { 4 product *= x; 5 } 6 7 return product; 8 } 9 10 int cal_ploy (vector<int> &coefficient, int x, int n) { 11 int sum = coefficient[ n ]; 12 for (int i = 0; i < n; ++i) { 13 int item = coefficient[ i ] * cal_power(x, n - i); 14 sum += item; 15 } 16 17 return sum; 18 }
2.霍纳法则
1 int honour_rule(vector<int> &coefficient, int x, int n) { 2 int sum = coefficient[0]; 3 for (int i = 1; i <= n; ++i) { 4 sum = x * sum + coefficient[i]; 5 } 6 7 return sum; 8 }
3.测试
1 int main() { 2 int x, n, result; 3 cout << "Enter x, n : "; 4 cin >> x >> n; 5 vector<int> coefficients; 6 7 for (int i = 0; i <= n; ++i) { 8 int current_num; 9 cout << "coefficient " << (i + 1) << " : "; 10 cin >> current_num; 11 coefficients.push_back(current_num); 12 } 13 14 result = cal_ploy(coefficients, x, n); 15 cout << "regular sum = " << result << endl; 16 17 result = honour_rule(coefficients, x, n); 18 cout << "honour rule sum = " << result << endl; 19 20 cout << "Done." << endl; 21 22 return 0; 23 }
其中需要说明几点:
第一,代码中没有错误处理,边界检查,默认输入没有问题,这样做只是为了清楚地说明算法思路,略去了算法无关的内容,但是实际操作中,这些代码必不可少。
第二,用 vector 来保存系数,在输入时,按照表达式的系数顺序输入即可,不用从后往前输入。