23. 霍納法則(多項式求值快速算法)


一. 概念引入

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 來保存系數,在輸入時,按照表達式的系數順序輸入即可,不用從后往前輸入。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM