多項(xiàng)式加減法 (一)

實(shí)驗(yàn)內(nèi)容

需要設(shè)計(jì)一個(gè)簡(jiǎn)單的一元稀疏多項(xiàng)式加減法計(jì)算器

實(shí)驗(yàn)要求

  • 輸入并建立多項(xiàng)式

例如:
![][1]
[1]: http://latex.codecogs.com/gif.latex?A(x)=7+3x+9x{8}+5x{17}
或:
![][2]
[2]: http://latex.codecogs.com/gif.latex?B(x)=8x+22x{7}-9x{8}

  • 輸出多項(xiàng)式
  • 多項(xiàng)式A和B相加,建立多項(xiàng)式 C = A + B,并輸出相加的結(jié)果多項(xiàng)式 C
  • 多項(xiàng)式A和B相減,建立多項(xiàng)式 C = A - B,并輸出相減的結(jié)果多項(xiàng)式C (選作)

如何做?

首先根據(jù)實(shí)驗(yàn)要求,多項(xiàng)式為稀疏一元多項(xiàng)式,因此采用鏈?zhǔn)骄€性存儲(chǔ)結(jié)構(gòu)表示,鏈?zhǔn)骄€性存儲(chǔ)結(jié)構(gòu)在理論課中介紹了:

  • 單鏈表
  • 雙向鏈表
  • 循環(huán)鏈表

在此,為簡(jiǎn)便起見(jiàn),我們采用單鏈表結(jié)構(gòu)。如果使用單鏈表存儲(chǔ)一元多項(xiàng)式,則單鏈表中的每一個(gè)節(jié)點(diǎn)用于存儲(chǔ)該一元多項(xiàng)式中的某一項(xiàng)。

第一步 定義數(shù)據(jù)結(jié)構(gòu)類(lèi)型

由實(shí)驗(yàn)要求可知,一元多項(xiàng)式中每一項(xiàng)由系數(shù)和指數(shù)構(gòu)成,因此我們定義單鏈表中節(jié)點(diǎn)結(jié)構(gòu)為:

struct tagNode
{
    float chef;
    int exp;
    struct tagNode *next;
};

typedef struct tagNode Node;
typedef struct tageNode * pNode;

typedef struct tagNode * LinkList;
typedef struct tagNode * Poly;

單鏈表可以采用帶頭結(jié)點(diǎn)的單鏈表或頭指針單鏈表,為簡(jiǎn)便起見(jiàn),我們采用帶頭結(jié)點(diǎn)的單鏈表。

如上代碼所示,我們通過(guò) typedef struct tagNode *Poly 定義了多項(xiàng)式類(lèi)型。

第二步 定義操作接口

實(shí)驗(yàn)要求必須實(shí)現(xiàn)如下功能:

  • 輸入并建立多項(xiàng)式
  • 輸出多項(xiàng)式
  • 多項(xiàng)式A和B相加,建立多項(xiàng)式 C = A + B,并輸出相加的結(jié)果多項(xiàng)式 C
  • 多項(xiàng)式A和B相減,建立多項(xiàng)式 C = A - B,并輸出相減的結(jié)果多項(xiàng)式C

上述4個(gè)功能,可以映射為 對(duì) Poly 類(lèi)型的四個(gè)不同操作接口。

此外, 對(duì)于單鏈表而言,由于是動(dòng)態(tài)分配節(jié)點(diǎn)存儲(chǔ)空間,因此還需要考慮單鏈表的建立、銷(xiāo)毀操作;

對(duì)于多項(xiàng)式如何建立,可以再創(chuàng)建時(shí)既確定多項(xiàng)式中每一項(xiàng)的系數(shù)及指數(shù);也可以在多項(xiàng)式數(shù)據(jù)結(jié)構(gòu)實(shí)例創(chuàng)建完成后通過(guò)其他操作接口添加新的項(xiàng)。

根據(jù)上述要求,我們可以給出多項(xiàng)式操作接口的聲明:

struct tagNode
{
    float chef;
    int exp;
    struct tagNode *next;
};

typedef struct tagNode Node;
typedef struct tageNode * pNode;

typedef struct tagNode * LinkList;
typedef struct tagNode * Poly;

Poly CreatePoly(); // 創(chuàng)建多項(xiàng)式數(shù)據(jù)結(jié)構(gòu)實(shí)例
bool DestroyPoly(Poly poly); // 銷(xiāo)毀多項(xiàng)式實(shí)例
void PrintPoly(Poly poly); // 輸出多項(xiàng)式
Poly Add(Poly polya, Poly polyb); // 多項(xiàng)式相加
Poly Substract(Poly ploya, Poly polyb); // 多項(xiàng)式相減

bool AddNode(Poly poly, float coef, int exp); // 為poly多項(xiàng)式添加新項(xiàng)(coef, exp)

第三步 建立項(xiàng)目文件

首先,建立一個(gè)C或C++項(xiàng)目工程。關(guān)于C或C++項(xiàng)目工程,由于使用開(kāi)發(fā)環(huán)境的不同,操作步驟不盡相同。這里,我們不使用IDE,直接使用gcc編譯器對(duì)源文件進(jìn)行編譯。

我們需要建立3個(gè)文件,他們分別是:

  • Poly.h : 用于定義多項(xiàng)式數(shù)據(jù)結(jié)構(gòu)及操作接口聲明
  • Poly.cpp : 用于多項(xiàng)式操作接口實(shí)現(xiàn)
  • main.cpp : 用于整個(gè)實(shí)驗(yàn)項(xiàng)目的測(cè)試

Poly.h文件

通常而言,我們將數(shù)據(jù)結(jié)構(gòu)的 定義、操作接口 的聲明與 實(shí)現(xiàn) 分開(kāi),以便于項(xiàng)目的組織及代碼復(fù)用。
以下給出Poly.h文件的代碼:

#ifndef _POLY_H_
#define _POLY_H_

#include <stdio.h>

struct tagNode
{
    float chef;
    int exp;
    struct tagNode *next;
};

typedef struct tagNode Node;
typedef struct tageNode * pNode;

typedef struct tagNode * LinkList;
typedef struct tagNode * Poly;

Poly CreatePoly(); // 創(chuàng)建多項(xiàng)式數(shù)據(jù)結(jié)構(gòu)實(shí)例
bool DestroyPoly(Poly poly); // 銷(xiāo)毀多項(xiàng)式實(shí)例
void PrintPoly(Poly poly); // 輸出多項(xiàng)式
Poly Add(Poly polya, Poly polyb); // 多項(xiàng)式相加
Poly Substract(Poly ploya, Poly polyb); // 多項(xiàng)式相減

bool AddNode(Poly poly, float coef, int exp); // 為poly多項(xiàng)式添加新項(xiàng)(coef, exp)

#endif _POLY_H_

Poly.h 文件中,文件頭2行和最后1行使用了 #ifndef#define 宏,主要作用是為防止 Poly.h 頭文件被重復(fù)引用的問(wèn)題。

Poly.cpp文件

在定義好 Poly.h 文件后,我們開(kāi)始實(shí)現(xiàn)多項(xiàng)式相關(guān)的操作接口。與多項(xiàng)式相關(guān)的操作接口都在 Poly.cpp 文件中實(shí)現(xiàn)。首先來(lái)看看 Poly.cpp 文件:

#include "Poly.h"
#include <stdio.h>

Poly CreatePoly()
{
    ...
}
bool DestroyPoly(Poly poly)
{
    ...
}

...

Poly.cpp 文件中,首先通過(guò)頭文件包含命令將 Poly.h 引用進(jìn)來(lái)。如此一來(lái),在 Poly.cpp 文件中便可使用 Poly.h 文件所定義的數(shù)據(jù)類(lèi)型及相關(guān)接口聲明。

CreatePoly接口

我們首先來(lái)實(shí)現(xiàn)創(chuàng)建多項(xiàng)式數(shù)據(jù)類(lèi)型實(shí)例的方法。由于采用頭結(jié)點(diǎn)單鏈表形式,因此我們需要在 CreatePoly 接口中完成如下幾步操作:

  1. 通過(guò) malloc(sizeof(Node)) 分配頭結(jié)點(diǎn);
  2. 完成 Poly 數(shù)據(jù)類(lèi)型實(shí)例初始化工作;
  3. 成功則返回 Poly 實(shí)例,否則返回錯(cuò)誤提示;

CreatePoly 接口實(shí)現(xiàn)代碼如下所示:

...

Poly CreatePoly()
{
    Poly poly = NULL;
    PNode head = NULL; 
    
    head = (PNode) malloc(sizeof(Node));
    if (head != NULL)
    {
        // 不需要對(duì)頭結(jié)點(diǎn)的coef和exp數(shù)據(jù)域進(jìn)行設(shè)置
        head->next = NULL; // 設(shè)置頭結(jié)點(diǎn)的next指針域?yàn)镹ULL
        poly = head;
    }

    return poly;  // 如果分配頭結(jié)點(diǎn)空間成功,則返回poly非空表示創(chuàng)建多項(xiàng)式實(shí)例操作成功,
                  // 否則返回值為NULL,表示創(chuàng)建多項(xiàng)式實(shí)例操作失敗
}

...

DestroyPoly接口

在完成 CreatePoly 接口后,我們來(lái)實(shí)現(xiàn) DestroyPoly 接口。 該接口需要完成的操作是將參數(shù) poly表示的多項(xiàng)式實(shí)例進(jìn)行銷(xiāo)毀。因?yàn)?C/C++ 中內(nèi)存的分配和釋放操作需由程序員自行完成。

實(shí)現(xiàn) CreatePoly 接口,需要完成如下幾步操作:

  1. 從頭節(jié)點(diǎn)開(kāi)始逐一釋放 poly 實(shí)例中每個(gè)節(jié)點(diǎn)的內(nèi)存空間;
  2. 返回操作成功與否的結(jié)果;

DestroyPoly 接口實(shí)現(xiàn)代碼如下所示:

...

bool DestroyPoly(Poly poly)
{
    PNode p = NULL;
    
    p = poly; // p指向頭結(jié)點(diǎn)

    while (p != NULL)
    {
        poly = poly->next;
        free (p);
        p = poly;
    }
    
    return true;
}

...

PrintPoly接口

完成 CreatePolyDestroyPoly 兩個(gè)接口后,我們來(lái)實(shí)現(xiàn) PrintPoly 接口。

PrintPoly 接口主要用于輸出多項(xiàng)式。此外,我們可以利用該接口測(cè)試其他接口實(shí)現(xiàn)是否正確。

例如,要測(cè)試多項(xiàng)式相加接口 Add 實(shí)現(xiàn)是否正確,可在調(diào)用 Add 接口之前及之后調(diào)用Print接口,通過(guò)Print接口的輸出結(jié)果可以較方便、快捷的判斷 Add 接口實(shí)現(xiàn)是否存在邏輯問(wèn)題 。

當(dāng)遇到程序邏輯問(wèn)題時(shí),通過(guò)調(diào)試方式檢測(cè)邏輯問(wèn)題是一件耗費(fèi)時(shí)間和精力的事情,在可以通過(guò)輸出中間結(jié)果進(jìn)行判斷檢測(cè)時(shí),盡量避免過(guò)早陷入調(diào)試程序的陷阱中。

...
Poly polyA, polyB, polyC;
...

PrintPoly(polyA);
polyC Add(polyA, polyB);
PrintPoly(polyC);

...

以下給出 PrintPoly 接口的實(shí)現(xiàn):

void PrintPoly(Poly poly)
{
    PNode p = NULL;

    if (poly == NULL)
        return ;
    
    p = poly->next; // 忽略頭結(jié)點(diǎn)
    while (p != NULL)
    {
        if (p->exp != 0)
        {
            printf("%+.1fX^%d ", p->coef, p->exp);
        }
        else
        {
            printf("%+.1f ", p->coef);
        }
    }

    printf("\n");
}

第四步 讓我們的代碼跑起來(lái)

完成CreatePoly、DestroyPoly、PrintPoly 三個(gè)接口后。對(duì)于剩余的Add、SubtractAddNode接口,我們暫且放一邊。

接下來(lái)我們的目標(biāo)是將項(xiàng)目盡快跑起來(lái),以便對(duì)已實(shí)現(xiàn)的接口進(jìn)行測(cè)試(包括語(yǔ)法、邏輯錯(cuò)誤)。

實(shí)際項(xiàng)目開(kāi)發(fā)過(guò)程中,我們總是通過(guò)不斷的迭代開(kāi)發(fā)來(lái)完善我們的項(xiàng)目。因此,在開(kāi)發(fā)過(guò)程中盡快讓項(xiàng)目運(yùn)行起來(lái),能夠有一個(gè)可運(yùn)行版本(最小功能版本最小系統(tǒng)版本)至關(guān)重要。

main.cpp

讓我們來(lái)編寫(xiě)測(cè)試代碼。我們把測(cè)試代碼放在main.cpp文件中。測(cè)試代碼主要對(duì)已編寫(xiě)的接口進(jìn)行測(cè)試,按照本文PrintPoly接口中所寫(xiě)的類(lèi)似,可以先調(diào)用CreatePoly、再調(diào)用PrintPoly接口對(duì)其他接口進(jìn)行測(cè)試。

#include "Poly.h"
#include <stdio.h>

int main ()
{
    Poly ploya = NULL;
    
    polya = CreatePoly();
    PrintPoly(polya);
    DestroyPoly(polya);

    return 0;
}

完成 main.cpp 中測(cè)試代碼的編寫(xiě)后,我們來(lái)對(duì)整個(gè)項(xiàng)目進(jìn)行編譯。在此,我們使用gcc編譯套件進(jìn)行編譯工作。

Step 1

進(jìn)入 lab01 目錄,使用 ls 命令查看當(dāng)前目錄信息:

[localhost:lab01 xgqin]$ ls
Poly.cpp Poly.h   main.cpp

Step 2

運(yùn)行 g++ 命令,對(duì) main.cpp 、 Poly.cpp 進(jìn)行編譯。編譯后,無(wú)語(yǔ)法錯(cuò)誤,默認(rèn)生成 a.out 執(zhí)行文件。

[localhost:lab01 xgqin]$ g++ main.cpp Poly.cpp 
[localhost:lab01 xgqin]$ ls
Poly.cpp Poly.h   a.out    main.cpp
[localhost:lab01 xgqin]$ 

Step 3

通過(guò) ./a.out 運(yùn)行編譯后的執(zhí)行文件。從運(yùn)行結(jié)果看, a.out 文件執(zhí)行后,無(wú)任何輸出。因?yàn)?main.cpp 文件中調(diào)用了 CreatePolyPrintPoly 兩個(gè)方法,但由于 CreatePoly 方法僅僅創(chuàng)建了一個(gè)帶頭結(jié)點(diǎn)的空鏈表,因此 PrintPoly 方法無(wú)任何輸出。

[localhost:lab01 xgqin]$ ls
Poly.cpp Poly.h   a.out    main.cpp
[localhost:lab01 xgqin]$ ./a.out 
[localhost:lab01 xgqin]$ 

通過(guò)上述運(yùn)行結(jié)果,我們并不知道在 Poly.cpp 中所寫(xiě)的 CreatePoly 、 PrintPoly 等接口是否無(wú)問(wèn)題。那接下來(lái)我們?cè)撊绾巫觯靠梢钥紤]以下幾個(gè)方案:

  1. 實(shí)現(xiàn) AddNode 接口,從而可以構(gòu)造出非空的多項(xiàng)式,然后通過(guò) PrintPoly 接口進(jìn)行測(cè)試;
  2. CreatePoly 接口中新增添加節(jié)點(diǎn)的測(cè)試代碼,再通過(guò)PrintPoly接口進(jìn)行測(cè)試;

在此,我們選擇方案2,因?yàn)榭杀苊庠谖赐瓿傻谝淮蔚_(kāi)發(fā)前再加入新的接口,盡可能避免讓項(xiàng)目代碼在開(kāi)發(fā)早期過(guò)于復(fù)雜。

CreatePoly接口增加測(cè)試代碼

新加的測(cè)試代碼目的是便于我們進(jìn)行測(cè)試,如下代碼所示:

Poly CreatePoly()
{
    Poly poly = NULL;
    PNode head = NULL; 
    PNode cur = NULL; // 始終指向存儲(chǔ)多項(xiàng)式的單鏈表最后一個(gè)節(jié)點(diǎn)的指針
    int num; // 存儲(chǔ)所需輸入多項(xiàng)式項(xiàng)數(shù)
    float coef;
    int exp;

    head = (PNode) malloc(sizeof(Node));
    if (head != NULL)
    {
        // 不需要對(duì)頭結(jié)點(diǎn)的coef和exp數(shù)據(jù)域進(jìn)行設(shè)置
        head->next = NULL; // 設(shè)置頭結(jié)點(diǎn)的next指針域?yàn)镹ULL
        poly = head;
    }
    
    cur = poly; // 初始化cur指針,cur當(dāng)前指向頭結(jié)點(diǎn)
    
    printf("請(qǐng)輸入節(jié)點(diǎn)個(gè)數(shù):");
    scanf("%d", &num);
    
    for (int i = 0; i < num; i++)
    {
        scanf("%f%d", &coef, &exp);
        cur->next = (PNode) malloc(sizeof(Node));
        if (cur->next != NULL)  // 分配節(jié)點(diǎn)成功
        {
            cur = cur->next;  // 確保cur指向最后一個(gè)新節(jié)點(diǎn)
            cur->coef = coef;
            cur->exp = exp;
            cur->next = NULL;
        }
    }

    return poly;  // 如果分配頭結(jié)點(diǎn)空間成功,則返回poly非空表示創(chuàng)建多項(xiàng)式實(shí)例操作成功,
                  // 否則返回值為NULL,表示創(chuàng)建多項(xiàng)式實(shí)例操作失敗
}

完成 CreatePoly 接口修改后,我們?cè)俅伟凑?strong>Step 1 至 Step 2的步驟對(duì)當(dāng)前項(xiàng)目進(jìn)行編譯:

[localhost:lab01 xgqin]$ ls
Poly.cpp Poly.h   a.out    main.cpp
[localhost:lab01 xgqin]$ g++ main.cpp Poly.cpp 
[localhost:lab01 xgqin]$ ls
Poly.cpp Poly.h   a.out    main.cpp
[localhost:lab01 xgqin]$ ./a.out
請(qǐng)輸入節(jié)點(diǎn)個(gè)數(shù):4
4 -1
7 0
3 1
9 8
+4.0X^-1 +7.0X +3.0X^1 +9.0X^8
[localhost:lab01 xgqin]$

再次使用 g++ 命令可以對(duì) main.cpp、Poly.cpp 進(jìn)行編譯,如無(wú)語(yǔ)法錯(cuò)誤,編譯器會(huì)生成新的 a.out 文件覆蓋舊版本 a.out 文件。

從程序再一次的運(yùn)行結(jié)果看,我們創(chuàng)建了一個(gè)包含4個(gè)項(xiàng)的一元多項(xiàng)式,且輸入每個(gè)項(xiàng)的系數(shù)與指數(shù)時(shí),按照指數(shù)升序的形式進(jìn)行輸入、存儲(chǔ)。

![][3]
[3]: http://latex.codecogs.com/gif.latex?A=4x{-1}+7+3x+9x{8}

輸入所表示的多項(xiàng)式如上圖所示,輸出結(jié)果如下所示。

+4.0X^-1 +7.0X +3.0X^1 +9.0X^8

從程序運(yùn)行輸出結(jié)果看,目前 CreatPoly 、 PrintPoly 兩個(gè)接口未發(fā)現(xiàn)邏輯錯(cuò)誤(未發(fā)現(xiàn)邏輯錯(cuò)誤 不等價(jià)于 沒(méi)有邏輯錯(cuò)誤)。

你可以多次運(yùn)行 a.out 文件輸入不同數(shù)據(jù)對(duì)程序進(jìn)行測(cè)試或修改main.cpp中的測(cè)試代碼(例如:聲明新的Poly指針,新增PrintPoly接口調(diào)用代碼等)。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 在多項(xiàng)式加法 (一)中,我們介紹了多項(xiàng)式對(duì)應(yīng)的單鏈表的幾個(gè)接口,現(xiàn)在我們來(lái)完成本次實(shí)驗(yàn)剩余的其他幾個(gè)接口。 第五步...
    我叫卡卡算了閱讀 1,320評(píng)論 4 3
  • 發(fā)現(xiàn) 關(guān)注 消息 iOS 第三方庫(kù)、插件、知名博客總結(jié) 作者大灰狼的小綿羊哥哥關(guān)注 2017.06.26 09:4...
    肇東周閱讀 15,327評(píng)論 4 61
  • *面試心聲:其實(shí)這些題本人都沒(méi)怎么背,但是在上海 兩周半 面了大約10家 收到差不多3個(gè)offer,總結(jié)起來(lái)就是把...
    Dove_iOS閱讀 27,622評(píng)論 30 472
  • 第二次支教,卻意外遇到了第一次支教過(guò)的一位小朋友 一見(jiàn)面就給了我一個(gè)緊緊的擁抱,臨走時(shí)還悄悄塞給了我一封信。當(dāng)時(shí)沒(méi)...
    Infinity999閱讀 380評(píng)論 0 0
  • 你像風(fēng),捉摸不住,對(duì)付風(fēng)最好的辦法就是化作空氣。在你飄忽不定時(shí),我又能無(wú)孔不入。 可是我這空氣是稀薄的,不想讓你窒...
    卜蟬明閱讀 208評(píng)論 0 2

友情鏈接更多精彩內(nèi)容