數據結構編程筆記七:第二章 線性表 一元多項式程序的實現

一元多項式是鏈表的一個應用。

還是老規矩:

程序在碼雲上可以下載。
地址:https://git.oschina.net/601345138/DataStructureCLanguage.git

簡單看看程序的實現:

//------------------------------------引入的頭文件-------------------------------------- 
#include <stdio.h>          //使用了標準庫函數 printf(),scanf()
#include <stdlib.h>         //使用了動態內存分配函數 malloc(),free()

//------------------------------------自定義符號常量------------------------------------ 
#define OVERFLOW -2         //內存溢出錯誤常量
#define OK 1                //表示操作正確的常量 
#define ERROR 0             //表示操作錯誤的常量
#define TRUE 1                 
#define FALSE 0             

//-----------------------------------自定義數據類型------------------------------------- 
typedef int Status;         //用typedef給int起個別名,也便於程序的維護 
typedef float ElemType;     //用typedef給float起個別名,也便於程序的維護

//一元多項式的C語言表示
typedef struct{   //項的表示,多項式的項作爲LinkList的數據元素 
    float coef;   //係數 
    int   expn;   //指數 
}PElemType;       //數據類型名PElemType

typedef struct LNode{
    PElemType data;       //上面被typedef定義的結構體類型作爲一元多項式的元素類型 
    struct LNode *next;   //單鏈表的指針域 
}* Link,* Position; 

typedef struct{  //鏈表類型 
    Link head,tail;  //頭指針head和尾指針tail分別指向線性鏈表中的頭結點和尾結點 
    int len;   //指示線性鏈表中數據元素的個數 
}LinkList;

typedef LinkList Polynomial;  //用帶表頭結點的有序鏈表表示一元多項式 

//******************************** 一元多項式的基本操作 ************************************ 

//------------------------------ 1.線性表的基本算法 ---------------------------------------- 
Status MakeNode(Link &p, PElemType e){  //生成結點 
    //分配由p指向值爲e的結點
    if(!(p = (Link)malloc(sizeof(LNode)))){
        printf("內存分配失敗!\n");
        exit(OVERFLOW);
    }//if
    p->data = e;
    return TRUE; 
}//MakeNode

void FreeNode(Link &p){  //釋放結點 
    //釋放p所指向的結點
    free(p);
    p = NULL; 
}//FreeNode

void InitList(LinkList &L){   //初始化表 
    //構造一個空的線性鏈表L
    Link p = NULL;
    if(!(p = (Link)malloc(sizeof(LNode)))){
        printf("內存分配失敗!\n");
        exit(OVERFLOW);
    }//if
    else{
        p->next = NULL;
        L.head = L.tail = p;
        L.len = 0;
    }//if     
}//InitList

void ClearList(LinkList &L){  //清空鏈表 
    //將線性鏈表L置成空表,並釋放原鏈表的結點空間
    Link p = NULL,q = NULL;
    if(L.head != L.tail){  //不是空表 
        p = q = L.head->next;
        L.head->next = NULL;
        while(p != L.tail){
            p = q->next;
            free(q);
            q = p;
        }//while
        free(q);
        L.tail = L.head;
        L.len = 0;
    }//if
}//ClearList

void DestoryList(LinkList &L){  //銷燬鏈表 
    //銷燬線性鏈表L,L不再存在
    ClearList(L);  //清空鏈表
    FreeNode(L.head);
    L.tail = NULL;
    L.len = 0; 
}//DestoryList

void InsFirst(LinkList &L, Link h, Link s){  //插入結點 (形參增加L,因爲需要修改L)
    //已知h爲線性表的頭結點,將s所指結點插在第一個結點之前 
    s->next = h->next;
    h->next = s;
    if(h == L.tail) { //h指向尾結點
       L.tail = h->next;  //修改尾指針 
    }//if
    L.len++; 
}//InsFirst

Status DelFirst(LinkList &L, Link h, Link &q){ //刪除結點 (形參增加L,因爲需要修改L)
    //h指向L的一個結點,把h當做頭結點,刪除鏈表中第一個結點並以q返回
    //若鏈表爲空(h指向尾結點),q=NULL,返回FALSE
    q = h->next;
    if(q){  //鏈表非空 
        h->next = q->next;
        if(!h->next) { //刪除尾結點
           L.tail = h; //修改尾指針
        }//if
        L.len--;
        return OK;    
    }//if 
    else {
        return ERROR;
    }//else 
}//DelFirst 

void Append(LinkList &L, Link s){  //追加 
    //將指針s(s->data爲第一個數據元素)所指(彼此以指針相鏈,以NULL結尾)的
    //一串結點鏈接在線性鏈表L的最後一個結點之後,並改變鏈表L的尾指針指向新的尾結點
    int i = 1;
    L.tail->next = s;
    while(s->next){
        s = s->next;
        i++;
    }//while
    L.tail = s;
    L.len += i;
}//Append 

Position PriorPos(LinkList L, Link p){  //獲取前驅位置 
    //已知p指向線性鏈表中的一個結點,返回p所指結點的直接前驅位置,若無直接前驅,則返回NULL
    Link q = NULL;
    q = L.head->next;
    if(q == p) {  //無前驅
        return NULL;
    }//if
    else{
        while(q->next != p) {  //q不是p的直接前驅 
            q = q->next;
        }//while
        return q;
    }//else 
}//PriorPos 

void SetCurElem(Link p,PElemType e){   //設置(更新)元素的值 
    //已知p指向線性鏈表中的一個結點,用e更新p所指結點中的數據元素的值
    p->data=e; 
}//SetCurElem

PElemType GetCurElem(Link p){   //獲取元素的值 
    //已知p指向線性鏈表中的一個結點,返回p所指結點數據元素的值
    return p->data;
}//GetCurElem

Position GetHead(LinkList L){  //獲得頭結點位置 
    //返回線性鏈表L中頭結點的位置
    return L.head; 
}//GetHead

Position NextPos(Link p){  //獲得後繼位置 
    //已知p指向線性鏈表中的一個結點,返回p所指結點直接後繼的位置
    return p->next; 
}//NextPos

Status ListEmpty(LinkList L){  //判空 
    //若線性鏈表L爲空表,則返回TRUE,否則返回FALSE
    if(L.len) {
       return FALSE;
    }//if
    else {
       return TRUE;
    }//else
}//ListEmpty

//--------------------------------2.一元多項式的算法------------------------------------------

//-----------------------------有序比較函數------------------------------

int compare(PElemType a, PElemType b){  //比較a,b指數值大小 

    //依a的指數值<(或=)(或>) b的指數值,分別返回-1,0和+1
    if(a.expn < b.expn) {
        return -1;
    }//if  
    else if(a.expn == b.expn) {
        return 0;
    }//else if
    else{
        return 1; 
    }//else       
}//compare

//-------------------------------定位函數-------------------------------- 

Status LocateElem(Polynomial P, PElemType e, Position &q, 
              int (*compare)(PElemType ,PElemType)){  //定位函數 
     /*若有序鏈表L中存在與e滿足判定函數compare()取值爲0的元素,
        則q指示L中第一個值爲e的結點的位置,並返回TRUE;
       否則q指示第一個與e滿足判定函數compare()取值>0的元素的前驅的位置,並返回FALSE                           */
    Link p = P.head, p1 = NULL;
    do{
        p1 = p;
        p = p->next;
    }while(p && (compare(p->data, e) < 0));  //沒到表尾且p->data.expn < e.expn

    if(!p || compare(p->data, e) > 0){  //到表尾或compare(p->data,e)>0 
        q = p1;
        return FALSE;
    }//if
    else{  //找到 
        q = p;
        return TRUE;
    }//else
}//LocateElem

//----------------------------------------按序插入-------------------------------------- 

void OrderInsertMerge(Polynomial &P, PElemType e,
          int (*compare)(PElemType ,PElemType)){  //按序插入 

    //按有序判定函數compare()的約定,將值爲e的結點插入或合併到升序鏈表L的適當位置
    Position q = NULL, s = NULL;
    if(LocateElem(P, e, q, compare)){  //L中存在該指數項 
        q->data.coef += e.coef;  //改變當前結點係數的值 
        if(!q->data.coef){  //係數爲0 
            //刪除多項式L中的當前結點
            if(!(s = PriorPos(P, q))){  //s爲當前結點的前驅且q無前驅 
                s = P.head; 
            }//if
            DelFirst(P, s, q);
            FreeNode(q);
        }//if 
    }//if 
    else{ //生成指數項並鏈入鏈表 
        MakeNode(s, e);   //生成結點 
        InsFirst(P, q, s); 
    }//else
}//OrderInsertMerge

//-----------------------------一元多項式的創建與銷燬---------------------------------------

void createPolyn(Polynomial &P, int m){    //一元多項式的創建 
    //輸入m項的係數和指數,建立表示一元多項式的有序鏈表P
    PElemType e;
    Position h = NULL, q = NULL, s = NULL;
    InitList(P);
    h = GetHead(P); //得到頭結點的位置,頭結點的位置爲函數的返回值 
    e.coef = 0.0;
    e.expn = -1;
    SetCurElem(h, e);  //設置頭結點的數據元素
    for(int i = 1; i <= m; ++i){  //依次輸入m個非零項
        printf("請輸入多項式%d的係數:",i); 
        scanf("%f", &e.coef);
        printf("請輸入多項式%d的指數:",i);
        scanf("%d", &e.expn);
        if(!LocateElem(P, e, q, compare)){  //當前鏈表中不存在該指數項 
            if(MakeNode(s, e))     //生成結點並插入鏈表 
                InsFirst(P, q, s);
        }//if
    }//for    
}//createPolyn 

void DestoryPolyn(Polynomial &P){   //一元多項式的銷燬 
    //銷燬一元多項式P 
    DestoryList(P);
} //AddPolyn

//-------------------------------計算一元多項式項數--------------------------------- 

int PolynLength(Polynomial P){
    //返回一元多項式的項數 
    return P.len;
}//AddPolyn

//--------------------------------打印一元多項式----------------------------------- 
void Print(PElemType e){
    printf("%.2fx^%d", e.coef, e.expn);
}//Print

void PrintPolyn(Polynomial P, void (*Print)(PElemType)){
    //打印輸出一元多項式P
    Link q = NULL;
    q = P.head->next;  //q指向第一個結點
    printf("  f(x)=");
    while(q){
        Print(q->data);
        if(q->next && q->next->data.coef > 0){
            printf("+");
        }//if
        q = q->next;
    }//while 
    printf("\n");
}//PrintPolyn

//-----------------------------一元多項式的運算(+ - *)-------------------------------- 

void AddPolyn(Polynomial &Pa, Polynomial &Pb){
    //多項式加法:Pa=Pa+Pb ,利用兩個多項式的結點構成“和多項式”
    Position ha = NULL, hb = NULL, qa = NULL, qb = NULL;
    float sum = 0;
    PElemType a, b;
    ha = GetHead(Pa);
    hb = GetHead(Pb);
    qa = NextPos(ha);
    qb = NextPos(hb); 
    while(qa && qb){
        a = GetCurElem(qa);
        b = GetCurElem(qb);
        switch(compare(a, b)){
            case -1: { //多項式PA中當前結點指數值最小 
                ha = qa;  
                qa = NextPos(ha); 
                break;
            }//case 
            case 0:  { //兩者指數值相等 
                sum = a.coef + b.coef;
                if(sum != 0.0){  //修改多項式PA當前的係數值
                    PElemType e;
                    e.coef = sum;
                    e.expn = a.expn; 
                    SetCurElem(qa, e);
                    ha=qa;
                }//if 
                else{     //刪除多項式PA的當前結點 
                    DelFirst(Pa, ha, qa);
                    FreeNode(qa); 
                }//else
                DelFirst(Pb, hb, qb);
                FreeNode(qb);
                qb = NextPos(hb); 
                qa = NextPos(ha);
                break;
            }//case
            case 1:{   //多項式PB中當前結點的指數值小 
                DelFirst(Pb, hb, qb);
                InsFirst(Pa, ha, qb);
                qb = NextPos(hb);
                ha = NextPos(ha); 
                break;
            }//case     
        }//switch 
    }//while
    if(!ListEmpty(Pb)){
        Pb.tail = hb;
        Append(Pa, qb);  //鏈接Pb中剩餘結點 
    }//if 
    DestoryPolyn(Pb);  //銷燬Pb 
} //AddPolyn

void Opposite(Polynomial &Pa){  //係數取反 
    //多項式Pa係數取反
    Position p;
    p = Pa.head;
    while(p->next){
        p = p->next;
        p->data.coef *= -1;
    }//while 
}//Opposite

void SubtractPolyn(Polynomial &Pa, Polynomial &Pb){
    //多項式減法:Pa=Pa-Pb,並銷燬一元多項式Pb 
    Opposite(Pb);      //多項式Pb係數取反 
    AddPolyn(Pa, Pb);   //兩多項式相加,操作完之後銷燬Pb 
} //SubtractPolyn

void MultiplePolyn(Polynomial &Pa, Polynomial &Pb){
    //多項式乘法:Pa=Pa*Pb,並銷燬一元多項式Pb 
    Polynomial Pc;
    Position qa = NULL, qb = NULL;
    PElemType a, b, c;
    InitList(Pc);
    qa = GetHead(Pa);
    qa = qa->next;
    while(qa){
        a = GetCurElem(qa);
        qb = GetHead(Pb);
        qb = qb->next;
        while(qb){
            b = GetCurElem(qb);
            c.coef = a.coef * b.coef;
            c.expn = a.expn + b.expn;
            OrderInsertMerge(Pc, c, compare);
            qb = qb->next;
        }//while
        qa = qa->next;
    }//while
    DestoryPolyn(Pb);  //銷燬Pb
    ClearList(Pa);     //將Pa重置爲空表
    Pa.head = Pc.head; 
    Pa.tail = Pc.tail;
    Pa.len = Pc.len;
} //MultiplePolyn

//-------------------------------------------主函數--------------------------------------------------- 
int main(int argc,char *argv[]){
    Polynomial P, Q;  //兩個多項式
    int m = 0; 
    printf("\n------------------------------- 一元多項式 -------------------------------------\n"); 
    printf("->請輸入一元多項式1的非零項個數:");   scanf("%d", &m);
    createPolyn(P, m); 
    printf("->請輸入一元多項式2的非零項個數:");   scanf("%d", &m);
    createPolyn(Q, m);
    printf("\n->執行操作前,P、Q 兩多項式:\n");
    printf("P : "); PrintPolyn(P, Print);
    printf("Q : "); PrintPolyn(Q, Print);
    AddPolyn(P,Q);       //多項式加法,P+Q 
    printf("\n->兩個多項式相加結果P+Q:");     PrintPolyn(P, Print);
    printf("\n->請輸入一元多項式3的非零項個數:");  scanf("%d", &m);
    createPolyn(Q, m);
    printf("\n->執行操作前,P、Q 兩多項式:\n");
    printf("P : "); PrintPolyn(P, Print);
    printf("Q : "); PrintPolyn(Q, Print);
    SubtractPolyn(P,Q);  //多項式減法,P-Q
    printf("\n->兩個多項式相減結果P-Q:");     PrintPolyn(P, Print);
    printf("\n->請輸入一元多項式4的非零項個數:");  scanf("%d", &m);
    createPolyn(Q, m);
    printf("\n->執行操作前,P、Q 兩多項式:\n");
    printf("P : "); PrintPolyn(P, Print);
    printf("Q : "); PrintPolyn(Q, Print);
    MultiplePolyn(P,Q);  //多項式乘法,P*Q
    printf("\n->兩個多項式相乘結果P*Q:\n");   PrintPolyn(P, Print);
    DestoryPolyn(P);   //所有操作完成都會銷燬Q,此時只剩下P沒被銷燬         
    return 0;
}

程序的運行結果和輸入的數據:

------------------------------- 一元多項式 -------------------------------------

->請輸入一元多項式1的非零項個數:3
請輸入多項式1的係數:1
請輸入多項式1的指數:2
請輸入多項式2的係數:5
請輸入多項式2的指數:4
請輸入多項式3的係數:3
請輸入多項式3的指數:3
->請輸入一元多項式2的非零項個數:3
請輸入多項式1的係數:-3
請輸入多項式1的指數:3
請輸入多項式2的係數:4
請輸入多項式2的指數:2
請輸入多項式3的係數:7
請輸入多項式3的指數:1

->執行操作前,P、Q 兩多項式:
P :   f(x)=1.00x^2+3.00x^3+5.00x^4
Q :   f(x)=7.00x^1+4.00x^2-3.00x^3

->兩個多項式相加結果P+Q:  f(x)=7.00x^1+5.00x^2+5.00x^4

->請輸入一元多項式3的非零項個數:3
請輸入多項式1的係數:4
請輸入多項式1的指數:1
請輸入多項式2的係數:2
請輸入多項式2的指數:3
請輸入多項式3的係數:6
請輸入多項式3的指數:6

->執行操作前,P、Q 兩多項式:
P :   f(x)=7.00x^1+5.00x^2+5.00x^4
Q :   f(x)=4.00x^1+2.00x^3+6.00x^6

->兩個多項式相減結果P-Q:  f(x)=3.00x^1+5.00x^2-2.00x^3+5.00x^4-6.00x^6

->請輸入一元多項式4的非零項個數:2
請輸入多項式1的係數:1
請輸入多項式1的指數:1
請輸入多項式2的係數:2
請輸入多項式2的指數:2

->執行操作前,P、Q 兩多項式:
P :   f(x)=3.00x^1+5.00x^2-2.00x^3+5.00x^4-6.00x^6
Q :   f(x)=1.00x^1+2.00x^2

->兩個多項式相乘結果P*Q:
  f(x)=3.00x^2+11.00x^3+8.00x^4+1.00x^5+10.00x^6-6.00x^7-12.00x^8

--------------------------------
Process exited with return value 0
Press any key to continue . . .

下次的文章將會介紹順序棧的實現,希望大家繼續關注,不見不散!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章