Skip to content

Commit 4e6c3d5

Browse files
committed
a
1 parent 5dbb5b9 commit 4e6c3d5

3 files changed

Lines changed: 625 additions & 0 deletions

File tree

homework3/report.md

Lines changed: 349 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,349 @@
1+
# 41143250
2+
# 問題一
3+
4+
## 解題說明
5+
6+
本題要求實作一個多項式(Polynomial)類別,該類別可以建立多項式物件,並支援以下操作:
7+
加法、減法、乘法與指定值的代入計算,多項式由若干非零項所組成,每項以 <coef, exp> 表示,其中 $coef$ 為係數(整數),$exp$ 為非負整數次方。
8+
9+
### 解題策略
10+
11+
1. **資料結構設計**
12+
使用 Term 結構儲存每一項的係數與指數。
13+
使用 Chain<Term> 節點類別與循環鏈結串列來儲存多項式項目,串列首節點為頭節點,其 next 指向自身表示空多項式。
14+
透過 Available<Term> 類別管理節點回收與重複利用,減少動態配置的成本。
15+
16+
2. **建構與清除**
17+
建構子建立空的循環鏈結串列。
18+
clear() 函式負責釋放所有節點並回收至 Available 物件中,以便重複使用。
19+
20+
3. **多項式輸入與輸出**
21+
輸入運算子 >>:讀入多項式項數與每項的 (coef, exp),依序插入鏈結串列。
22+
輸出運算子 <<:依次輸出多項式項,支援正負號與次方格式化。
23+
24+
4. **多項式運算**
25+
加法 (operator+):同時走訪兩個鏈結串列,按指數大小合併;若指數相同則加總係數,係數為 0 則略過該項。
26+
減法 (operator-):將另一多項式係數全部取負後呼叫加法運算。
27+
乘法 (operator*):雙重迴圈將每一項相乘後插入結果中,若存在相同次方則合併。
28+
29+
5. **代入運算 (Evaluate)**
30+
依序將每項計算 $coef \times x^{exp}$ 後加總得到多項式值。
31+
32+
33+
### 解題範例
34+
35+
假設
36+
多項式 $ pA(x) = 2x^2 + x + 3 $
37+
多項式 $ pA(x) = 2x^2 + x + 3 $
38+
39+
加法結果:$ 2x^2 + 2x + 7 $
40+
減法結果:$ 2x^2 + 0x - 1 $
41+
乘法結果:$ 2x^3 + 9x^2 + 7x + 12 $
42+
代入 $x = 2$ 至 $p_B(x)$:$ 1\times 2 + 4 = 6 $
43+
44+
## 程式實作
45+
46+
以下為主要程式碼:
47+
48+
```cpp
49+
#include <iostream>
50+
#include <cmath>
51+
using namespace std;
52+
53+
// ------------------ 資料結構 ------------------
54+
struct Term {
55+
int coef;
56+
int exp;
57+
Term(int c = 0, int e = 0) : coef(c), exp(e) {}
58+
};
59+
60+
template <class T>
61+
class Chain {
62+
friend class Polynomial;
63+
template <class U> friend class Available;
64+
65+
public:
66+
T term;
67+
Chain<T>* next;
68+
Chain() : term(T()), next(nullptr) {}
69+
Chain(const T& t) : term(t), next(nullptr) {}
70+
Chain(const T& t, Chain<T>* n) : term(t), next(n) {}
71+
Chain(int coef, int exp) : term(coef, exp), next(nullptr) {}
72+
};
73+
74+
template <class T>
75+
class Available {
76+
private:
77+
Chain<T>* avaList;
78+
public:
79+
Available() : avaList(nullptr) {}
80+
~Available() {
81+
while (avaList) {
82+
Chain<T>* temp = avaList;
83+
avaList = avaList->next;
84+
delete temp;
85+
}
86+
}
87+
void putBack(Chain<T>* node) {
88+
Chain<T>* current = node;
89+
while (current->next) current = current->next;
90+
current->next = avaList;
91+
avaList = node;
92+
}
93+
Chain<T>* getOneNode() {
94+
if (!avaList) return new Chain<T>();
95+
Chain<T>* node = avaList;
96+
avaList = avaList->next;
97+
node->next = nullptr;
98+
return node;
99+
}
100+
};
101+
102+
class Polynomial {
103+
private:
104+
Chain<Term>* head;
105+
Available<Term> recycler;
106+
107+
Chain<Term>* newTerm(int c, int e) {
108+
Chain<Term>* node = recycler.getOneNode();
109+
node->term.coef = c;
110+
node->term.exp = e;
111+
node->next = nullptr;
112+
return node;
113+
}
114+
void clear() {
115+
if (!head) return;
116+
Chain<Term>* cur = head->next;
117+
while (cur != head) {
118+
Chain<Term>* temp = cur;
119+
cur = cur->next;
120+
recycler.putBack(temp);
121+
}
122+
head->next = head;
123+
}
124+
public:
125+
Polynomial() {
126+
head = new Chain<Term>();
127+
head->next = head;
128+
}
129+
~Polynomial() {
130+
clear();
131+
delete head;
132+
}
133+
134+
// 輸入
135+
friend istream& operator>>(istream& is, Polynomial& p) {
136+
p.clear();
137+
int n;
138+
if (!(is >> n)) return is;
139+
Chain<Term>* tail = p.head;
140+
for (int i = 0; i < n; i++) {
141+
int c, e;
142+
is >> c >> e;
143+
Chain<Term>* node = p.newTerm(c, e);
144+
tail->next = node;
145+
tail = node;
146+
}
147+
tail->next = p.head;
148+
return is;
149+
}
150+
151+
// 輸出
152+
friend ostream& operator<<(ostream& os, const Polynomial& p) {
153+
Chain<Term>* cur = p.head->next;
154+
bool first = true;
155+
if (cur == p.head) {
156+
os << 0;
157+
return os;
158+
}
159+
while (cur != p.head) {
160+
int c = cur->term.coef;
161+
int e = cur->term.exp;
162+
if (!first && c > 0) os << " + ";
163+
if (c < 0) os << " - ";
164+
int absC = abs(c);
165+
if (absC != 1 || e == 0) os << absC;
166+
if (e > 0) os << "x";
167+
if (e > 1) os << "^" << e;
168+
first = false;
169+
cur = cur->next;
170+
}
171+
return os;
172+
}
173+
174+
// 複製建構
175+
Polynomial(const Polynomial& other) {
176+
head = new Chain<Term>();
177+
head->next = head;
178+
Chain<Term>* tail = head;
179+
Chain<Term>* cur = other.head->next;
180+
while (cur != other.head) {
181+
Chain<Term>* node = newTerm(cur->term.coef, cur->term.exp);
182+
tail->next = node;
183+
tail = node;
184+
cur = cur->next;
185+
}
186+
tail->next = head;
187+
}
188+
189+
// 指派運算子
190+
Polynomial& operator=(const Polynomial& other) {
191+
if (this != &other) {
192+
clear();
193+
Chain<Term>* tail = head;
194+
Chain<Term>* cur = other.head->next;
195+
while (cur != other.head) {
196+
Chain<Term>* node = newTerm(cur->term.coef, cur->term.exp);
197+
tail->next = node;
198+
tail = node;
199+
cur = cur->next;
200+
}
201+
tail->next = head;
202+
}
203+
return *this;
204+
}
205+
206+
// 加法
207+
Polynomial operator+(const Polynomial& b) const {
208+
Polynomial result;
209+
Chain<Term>* aPtr = head->next;
210+
Chain<Term>* bPtr = b.head->next;
211+
Chain<Term>* tail = result.head;
212+
while (aPtr != head || bPtr != b.head) {
213+
if (aPtr == head) {
214+
tail->next = result.newTerm(bPtr->term.coef, bPtr->term.exp);
215+
bPtr = bPtr->next;
216+
}
217+
else if (bPtr == b.head) {
218+
tail->next = result.newTerm(aPtr->term.coef, aPtr->term.exp);
219+
aPtr = aPtr->next;
220+
}
221+
else if (aPtr->term.exp > bPtr->term.exp) {
222+
tail->next = result.newTerm(aPtr->term.coef, aPtr->term.exp);
223+
aPtr = aPtr->next;
224+
}
225+
else if (aPtr->term.exp < bPtr->term.exp) {
226+
tail->next = result.newTerm(bPtr->term.coef, bPtr->term.exp);
227+
bPtr = bPtr->next;
228+
}
229+
else {
230+
int sum = aPtr->term.coef + bPtr->term.coef;
231+
if (sum != 0) {
232+
tail->next = result.newTerm(sum, aPtr->term.exp);
233+
}
234+
else {
235+
tail->next = result.head;
236+
break;
237+
}
238+
aPtr = aPtr->next;
239+
bPtr = bPtr->next;
240+
}
241+
tail = tail->next;
242+
}
243+
tail->next = result.head;
244+
return result;
245+
}
246+
247+
// 減法
248+
Polynomial operator-(const Polynomial& b) const {
249+
Polynomial negB = b;
250+
Chain<Term>* cur = negB.head->next;
251+
while (cur != negB.head) {
252+
cur->term.coef = -cur->term.coef;
253+
cur = cur->next;
254+
}
255+
return (*this) + negB;
256+
}
257+
258+
// 乘法
259+
Polynomial operator*(const Polynomial& b) const {
260+
Polynomial result;
261+
for (Chain<Term>* aPtr = head->next; aPtr != head; aPtr = aPtr->next) {
262+
for (Chain<Term>* bPtr = b.head->next; bPtr != b.head; bPtr = bPtr->next) {
263+
int c = aPtr->term.coef * bPtr->term.coef;
264+
int e = aPtr->term.exp + bPtr->term.exp;
265+
// 合併同類項
266+
Chain<Term>* cur = result.head->next;
267+
Chain<Term>* prev = result.head;
268+
bool found = false;
269+
while (cur != result.head) {
270+
if (cur->term.exp == e) {
271+
cur->term.coef += c;
272+
found = true;
273+
break;
274+
}
275+
prev = cur;
276+
cur = cur->next;
277+
}
278+
if (!found && c != 0) {
279+
Chain<Term>* node = result.newTerm(c, e);
280+
prev->next = node;
281+
node->next = result.head;
282+
}
283+
}
284+
}
285+
return result;
286+
}
287+
288+
// 代入計算
289+
float Evaluate(float x) const {
290+
float resultVal = 0;
291+
Chain<Term>* cur = head->next;
292+
while (cur != head) {
293+
resultVal += cur->term.coef * pow(x, cur->term.exp);
294+
cur = cur->next;
295+
}
296+
return resultVal;
297+
}
298+
};
299+
300+
301+
// ------------------ 主程式 ------------------
302+
int main() {
303+
Polynomial pA, pB;
304+
cout << "請輸入polyA" << endl;
305+
cin >> pA;
306+
cout << "請輸入polyB" << endl;
307+
cin >> pB;
308+
309+
cout << "polyA + polyB = " << pA + pB << endl;
310+
cout << "polyA - polyB = " << pA - pB << endl;
311+
cout << "polyA * polyB = " << pA * pB << endl;
312+
cout << "polyB(2.0) = " << pB.Evaluate(2.0) << endl;
313+
return 0;
314+
}
315+
```
316+
317+
## 效能分析
318+
319+
1. 時間複雜度:
320+
Evaluate: $O(n)$
321+
加法 / 減法:$O(n + m)$
322+
乘法:最差 $O(n \times m)$(需合併同類項)
323+
324+
2. 空間複雜度
325+
主要為儲存多項式節點的鏈結串列:$O(n)$
326+
乘法結果最多 $O(n \times m)$ 項,取決於次方分布。
327+
328+
## 測試與驗證
329+
330+
### 測試案例
331+
332+
| 測試案例 | polyA | polyB | polyA+polyB | polyA-polyB | polyA×polyB | polyB(2.0) |
333+
|----------|------------|--------|-------------|-------------|-------------------|------------|
334+
| 測試一 | $2x^2+x+3$ | $$x+4$ | $2x^2+2x+7$ | $2x^2-1$ | $2x^3+9x^2+7x+12$ | 6 |
335+
336+
## 申論及開發報告
337+
338+
### 類別設計的思路
339+
340+
在本程式中,使用遞迴來實現阿克曼函數的主要原因如下:
341+
342+
1. **封裝性高**
343+
使用 Polynomial 封裝多項式操作,Term 封裝單項,Available 封裝節點管理,結構清晰且易於維護。
344+
2. **功能模組化**
345+
輸入、輸出、加減乘、代入計算均獨立成員函式,便於測試與擴展。
346+
3. **鏈結串列實作**
347+
採循環鏈結串列,可快速判斷空多項式 (head->next == head),插入與清除效率高,不必預先分配容量。
348+
4. **可擴展設計**
349+
可進一步加入排序保證、簡化顯示、同次項自動合併等優化功能。

0 commit comments

Comments
 (0)