MFC版連結串列實現稀疏多項式相加減
題目
設計一個一元稀疏多項式簡單計算器。
基本要求
(1)輸入並建立兩個多項式;
(2)多項式a與b相加,建立和多項式c;
(3)多項式a與b相減,建立差多項式d;
(4)輸出多項式a, b, c, d。輸出格式:比如多項式a為:A(x)=c1xe1+ c2xe2+…+ cmxem,其中,ci和ei分別為第i項的係數和指數,且各項按指數的升冪排列,即0≤e1<e2<…<em。
實現提示
(1)用帶頭結點的單鏈表儲存多項式。
(2)每個多項式連結串列中都只儲存非零係數項。若多項式a與b中指數相等的兩項相加/減後,係數為零,則在和/差多項式中不儲存該指數項。
思路
其實說真的,看到連結串列就煩,沒辦法了,只能寫了,無奈自己太菜,大部分程式碼還是用的書上的,不過再運算子過載的時候自己改動了一下,因為要MFC視覺化的緣故,就把輸入輸出的過載刪掉了。
大致就和老師說的一樣,重點在於建立多項式類,難點在於MFC視覺化的計算器介面的資料輸入輸出,當然方法肯定很多,程式碼比較糙,將就著看吧,希望有對你有用的部分。
樣子差不多就是這樣:
輸入
輸出
1)輸入資料處理
輸入時,用CString變數存編輯框的內容,同時具備按鈕輸入和鍵盤輸入兩種方法,時間比較急,沒有檢測非法輸入,必須是合法輸入才能運算。不過這個寫起來也不難,完成作業就先這樣吧,到時候要是她還有要求再說。先把所有輸入存在串裡,然後用函式分割開,存進多項式物件裡,在分割時寫了一個函式,感覺蠻好用的,這裡還有一個操作可能比較多於,先用CString存,在取資料的時候又轉換為string,對string熟一點。
按鍵輸入程式碼:
void CCalculatorDlg::OnBnClickedButton1() { UpdateData(TRUE); m_Str += "1"; UpdateData(FALSE); // TODO: 在此新增控制元件通知處理程式程式碼 } void CCalculatorDlg::OnBnClickedButton0() { UpdateData(TRUE); m_Str += "0"; UpdateData(FALSE); // TODO: 在此新增控制元件通知處理程式程式碼 } void CCalculatorDlg::OnBnClickedButtonNod() { UpdateData(TRUE); m_Str += "."; UpdateData(FALSE); // TODO: 在此新增控制元件通知處理程式程式碼 } void CCalculatorDlg::OnBnClickedButton2() { m_Str += "2"; UpdateData(FALSE); // TODO: 在此新增控制元件通知處理程式程式碼 } void CCalculatorDlg::OnBnClickedButton3() { UpdateData(TRUE); m_Str += "3"; UpdateData(FALSE); // TODO: 在此新增控制元件通知處理程式程式碼 } void CCalculatorDlg::OnBnClickedButton4() { UpdateData(TRUE); m_Str += "4"; UpdateData(FALSE); // TODO: 在此新增控制元件通知處理程式程式碼 } void CCalculatorDlg::OnBnClickedButton5() { m_Str += "5"; UpdateData(FALSE); // TODO: 在此新增控制元件通知處理程式程式碼 } void CCalculatorDlg::OnBnClickedButton6() { UpdateData(TRUE); m_Str += "6"; UpdateData(FALSE); // TODO: 在此新增控制元件通知處理程式程式碼 } void CCalculatorDlg::OnBnClickedButton7() { UpdateData(TRUE); m_Str += "7"; UpdateData(FALSE); // TODO: 在此新增控制元件通知處理程式程式碼 } void CCalculatorDlg::OnBnClickedButton8() { UpdateData(TRUE); m_Str += "8"; UpdateData(FALSE); // TODO: 在此新增控制元件通知處理程式程式碼 } void CCalculatorDlg::OnBnClickedButton9() { m_Str += "9"; UpdateData(FALSE); // TODO: 在此新增控制元件通知處理程式程式碼 } void CCalculatorDlg::OnBnClickedButtonadd() { UpdateData(TRUE); m_Str += "+"; UpdateData(FALSE); // TODO: 在此新增控制元件通知處理程式程式碼 } void CCalculatorDlg::OnBnClickedButtonsub() { UpdateData(TRUE); m_Str += "-"; UpdateData(FALSE); // TODO: 在此新增控制元件通知處理程式程式碼 } void CCalculatorDlg::OnBnClickedButtonx() { m_Str += "X"; UpdateData(FALSE); // TODO: 在此新增控制元件通知處理程式程式碼 } void CCalculatorDlg::OnBnClickedButtonleft() { UpdateData(TRUE); m_Str += "("; UpdateData(FALSE); // TODO: 在此新增控制元件通知處理程式程式碼 } void CCalculatorDlg::OnBnClickedButtonright() { UpdateData(TRUE); m_Str += ")"; UpdateData(FALSE); // TODO: 在此新增控制元件通知處理程式程式碼 } void CCalculatorDlg::OnBnClickedButtonmul() { UpdateData(TRUE); m_Str += "^"; UpdateData(FALSE); // TODO: 在此新增控制元件通知處理程式程式碼 } void CCalculatorDlg::OnBnClickedButtonClear() { m_Str = ""; UpdateData(FALSE); // TODO: 在此新增控制元件通知處理程式程式碼 }
分割係數和指數函式:pos是開始時的串陣列下標,exp是指數,返回係數
float Search_Num(string a,int &pos,int&exp) {
float num = 0;
int cap = 0;
for (int i(pos); i < a.size(); i++) {
if (a[i] >= '0'&&a[i] <= '9') {
if (cap == 0)
num = num * 10 + a[i] - '0';
else num = num + (a[i] - '0')*pow(0.1, cap++);
}
else if (a[i] == '.') {
cap = 1;
}
else {
pos = i;
break;
}
}
exp = 0;
int tag = 1;
if (num == 0)
num = 1;
if (a[pos] == 'X') {
if (pos > a.size() -1||a[pos+1]=='-'||a[pos+1]=='+') {
exp = 1;
pos++;
return num;
}
if (a[pos + 2] == '-') {
tag = -1;
pos++;
}
for (int i(pos + 2); i < a.size(); i++) {
if (a[i] >= '0'&&a[i] <= '9') {
exp= exp* 10 + a[i] - '0';
}
else {
pos = i;
exp *= tag;
return num;
}
}
}
else {
exp = 0;
return num;
}
}
2)存進多項式物件中
類實現:
#include<iostream>
#include<string>
#include<cmath>
const double EXP = 1e-4;
using namespace std;
struct Term {
float coef;
int exp;
Term *link;
Term(float a, int b, Term* c = NULL) {
coef = a;
exp = b;
link = c;
}
Term *insertAfter(float a, int b);
};
Term *Term::insertAfter(float a, int b) {
link = new Term(a, b, link);
return link;
}
class Poly {
private:
Term *first;
public:
Poly() {
first = new Term(0, -1);
}
Poly(Poly&R);
int maxOrder();
Term *GetHead() {
return first;
}
string GetString();
Poly operator+(Poly&);
Poly operator-(Poly&);
};
Poly::Poly(Poly &R) {
first = new Term(0, -1);
Term *destptr = first, *srcptr = R.GetHead()->link;
while (srcptr != NULL) {
destptr->insertAfter(srcptr->coef, srcptr->exp);
srcptr = srcptr->link;
destptr = destptr->link;
}
}
int Poly::maxOrder() {
Term *current = first;
while (current->link != NULL) {
current = current->link;
}
return current->exp;
}
string Poly::GetString()
{
string s;
CString str;
Term *p = GetHead()->link;
bool flag = false;
while (p != NULL) {
str.Format(_T("%.5lf"), p->coef);
if (flag == true) {
if (p->coef >0) {
s += '+';
}
}
flag = true;
while (str[str.GetLength() - 1] == '0') {
str.Delete(str.GetLength() - 1, 1);
}
if (str[str.GetLength() - 1] == '.') {
str.Delete(str.GetLength() - 1, 1);
}
if(p->exp==0||(str!=_T("1")&&str!=(_T("-1"))))
s += (CT2A)str;
else if (str == _T("-1")) {
s += '-';
}
if (p->exp == 1) {
s += 'X';
}
else if(abs(p->exp)>1)
s += "X^";
str.Format(_T("%d"), p->exp);
if (abs(p->exp) > 1) {
s += (CT2A)str;
}
p = p->link;
}
return s;
}
Poly Poly::operator+(Poly&R) {
Term*pa, *pb, *pc, *p;
Poly C;
float temp;
pc = C.first;
pa = GetHead()->link;
pb = R.GetHead()->link;
while (pa != NULL && pb != NULL) {
if (pa->exp == pb->exp) {
temp = pa->coef + pb->coef;
if (abs(temp) > EXP) {
pc = pc->insertAfter(temp, pa->exp);
}
pa = pa->link;
pb = pb->link;
}
else if (pa->exp < pb->exp) {
pc = pc->insertAfter(pa->coef, pa->exp);
pa = pa->link;
}
else {
pc = pc->insertAfter(pb->coef, pb->exp);
pb = pb->link;
}
}
p = pa == NULL ? pb : pa;
while (p != NULL) {
pc = pc->insertAfter(p->coef, p->exp);
p = p->link;
}
return C;
}
Poly Poly::operator-(Poly&R) {
Term*pa, *pb, *pc, *p;
Poly C;
float temp;
pc = C.first;
pa = GetHead()->link;
pb = R.GetHead()->link;
while (pa != NULL && pb != NULL) {
if (pa->exp == pb->exp) {
temp = pa->coef - pb->coef;
if (abs(temp) > EXP) {
pc = pc->insertAfter(temp, pa->exp);
}
pa = pa->link;
pb = pb->link;
}
else if (pa->exp < pb->exp) {
pc = pc->insertAfter(pa->coef, pa->exp);
pa = pa->link;
}
else {
pc = pc->insertAfter(-pb->coef, pb->exp);
pb = pb->link;
}
}
p = pa == NULL ? pb : pa;
int flag = pa == NULL ? -1 : 1;
while (p != NULL) {
pc = pc->insertAfter(flag*p->coef, p->exp);
p = p->link;
}
return C;
}
按等於按鈕開始讀資料存進多項式A,B中:
void CCalculatorDlg::OnBnClickedButtonCal()
{
UpdateData(TRUE);
string s = (CT2A)m_Str;
if (s.empty()) {
AfxMessageBox(_T("請輸入表示式!"));
return;
}
Poly A, B,C;
bool flag = false;
float num = 0;
int cap = 0;
int v = 1;
int pos_B;
for (int i(0); i < s.size(); i++) {
if (s[i] == ')') {
pos_B = i;
break;
}
}
int p = 0;
if (s[0] == '(')p++;
bool real = true;
Term *rear = A.GetHead();
while (p < pos_B) {
real = true;
if (s[p] == '+') {
real = true;
p++;
}
else if (s[p] == '-'){
real = false;
p++;
}
int temp_e;
num=Search_Num(s, p,temp_e);
v = real == true ? 1 : -1;
rear = rear->insertAfter(v*num, temp_e);
}
p += 3;
rear = B.GetHead();
while (p < s.size()-1) {
real = true;
if (s[p] == '+') {
real = true;
p++;
}
else if (s[p] == '-') {
real = false;
p++;
}
int temp_e;
num = Search_Num(s, p, temp_e);
v = real == true ? 1 : -1;
rear = rear->insertAfter(v*num, temp_e);
}
if (s[pos_B + 1] == '+') {
C = A + B;
}
else {
C = A - B;
}
string temp = C.GetString();
m_Str = temp.c_str();
UpdateData(FALSE);
// TODO: 在此新增控制元件通知處理程式程式碼
}
3)結果轉換位字串更新到Edit框中
轉字串的函式就在類定義裡面,也費了不少功夫,因為樣例給的情況太全面了,剛開始沒考慮到負指數,不過不要緊,還是改好了。面向物件的特點體現以後更改程式碼也比較方便~
後記
程式碼沒有寫註釋,故意的。對,故意的。能理解的小夥伴應該能看懂,完全不懂的就有點困難了,相比不視覺化,視覺化對於輸入和輸出需要轉化一下,其他的和不普通的差不多,當然寫按鈕也比較煩,,,
介面很醜,之後可能會美化,再說吧,今天先睡了。
2018/11/13 23:42:48