數據結構28:廣義表及M元多項式


廣義表,又稱為列表。記作:

LS = (a 1,a 2,…,a n) ;( LS 為廣義表的名稱, a n 表示廣義表中的數據)。

廣義表可以看作是線性表的推廣。兩者區別是:線性表中的數據元素只能表示單個數據元素;廣義表中的單個數據元素 a,既可以是單個元素,也可以是廣義表。

原子和子表

在廣義表中,單個元素被稱為 “原子”;包含的廣義表被稱為 “子表”。

例如:

  1. A = ()  :A 表示一個廣義表,只不過表是空的,廣義表 A 的長度為 0。
  2. B = (e)  :廣義表 B 中只有一個原子 e ,長度為 1。
  3. C = (a,(b,c,d)) :廣義表 C 中有兩個元素,原子 a 和子表 (b,c,d) ,廣義表C的長度為 2。 
  4. D = (A,B,C) :廣義表 D 中有三個元素:子表 A、B、C,長度為 3 ,這種表示方式等同於: D = ((),(e),(b,c,d)) 。
  5. E = (a,E)  :廣義表 E 中有兩個元素,原子 a 和它本身,長度為 2 。這是一個遞歸的表,等同於:E = (a,(a,(a,…)))。
A = () 和 A = (()) 是不一樣的:前者是空表,長度為 0 ;后者表的長度為 1 ,包含的元素是一個子表,只不過這個子表是空表。

表頭和表尾

當廣義表不為空時,稱表中的第一個元素為表的 “表頭” ;剩余所有元素組成的表為 “表尾” 。

任何一個非空廣義表,表尾肯定是廣義表。

例如:上邊例子中的 D = (A,B,C) ,子表 A 為廣義表 D 的表頭;而 (B,C) 組成的表為 D 的表尾。

非空廣義表是由表頭和表尾構成,反過來說也對:給定一個表頭和表尾,可以唯一確定一個廣義表。

廣義表中結點結構

由於廣義表中的數據元素類型分為原子和子表,難以使用順序存儲結構表示,所以通常采用鏈式存儲結構。

根據原子和子表的不同,鏈式存儲中的結點需要用兩種不同的結構表示。對於原子來說,需要由兩部分組成:標志位 + 值域(如圖1(A));子表需要由三部分組成:標志位 + 指向表頭的指針域 + 指向表尾的指針域(如圖1(B))。

兩者都有一個相同的標志位,作用是為了能夠區分出原子和字表,一般標志位為1,表示子表;標志位為0,表示原子。


圖1 廣義表的鏈表結點結構

代碼表示:

typedef struct GLNode
{   
int tag;  //標志域   union
  {     
char atom;  //原子結點的值域     struct
    {       struct GLNode *hp, *tp;     }ptr;  //子表結點的指針域,hp指向表頭;tp指向表尾   }; }*Glist;

 

例如,使用圖1的鏈表結構表示廣義表 C = (a,(b,c,d)),效果圖為:


圖2 廣義表C的結構示意圖

實現代碼為:

Glist creatGlist(Glist C)
{   
// 廣義表C   C = (Glist)malloc(sizeof(Glist));   C->tag = 1;   // 表頭原子‘a’   C->ptr.hp = (Glist)malloc(sizeof(Glist));   C->ptr.hp->tag = 0;   C->ptr.hp->atom = 'a';   // 表尾子表(b,c,d),是一個整體   C->ptr.tp = (Glist)malloc(sizeof(Glist));   C->ptr.tp->tag = 1;   C->ptr.tp->ptr.hp = (Glist)malloc(sizeof(Glist));   C->ptr.tp->ptr.tp = NULL;   // 開始存放下一個數據元素(b,c,d), 表頭為‘b’,表尾為(c,d)   C->ptr.tp->ptr.hp->tag = 1;   C->ptr.tp->ptr.hp->ptr.hp = (Glist)malloc(sizeof(Glist));   C->ptr.tp->ptr.hp->ptr.hp->tag = 0;   C->ptr.tp->ptr.hp->ptr.hp->atom = 'b';   C->ptr.tp->ptr.hp->ptr.tp = (Glist)malloc(sizeof(Glist));   // 存放子表(c,d),表頭為c,表尾為d   C->ptr.tp->ptr.hp->ptr.tp->tag = 1;   C->ptr.tp->ptr.hp->ptr.tp->ptr.hp = (Glist)malloc(sizeof(Glist));   C->ptr.tp->ptr.hp->ptr.tp->ptr.hp->tag = 0;   C->ptr.tp->ptr.hp->ptr.tp->ptr.hp->atom = 'c';   C->ptr.tp->ptr.hp->ptr.tp->ptr.tp = (Glist)malloc(sizeof(Glist));   // 存放表尾d   C->ptr.tp->ptr.hp->ptr.tp->ptr.tp->tag = 1;   C->ptr.tp->ptr.hp->ptr.tp->ptr.tp->ptr.hp = (Glist)malloc(sizeof(Glist));   C->ptr.tp->ptr.hp->ptr.tp->ptr.tp->ptr.hp->tag = 0;   C->ptr.tp->ptr.hp->ptr.tp->ptr.tp->ptr.hp->atom = 'd';   C->ptr.tp->ptr.hp->ptr.tp->ptr.tp->ptr.tp = NULL;
  
return C; }

結點結構的另一種表示方式

除了上邊的那種表示結點的方式,還可以采用另外一種表示形式,不同在於:表結點和原子結點都添加了一個指向下一個數據元素的指針;而子表結點中只保留了指向表頭結點的指針,刪除了指向表尾的指針。


圖3 廣義表的另一種結點結構

代碼表示為:

typedef struct GLNode
{   
int tag;  //標志域   union
  {     
int atom;  //原子結點的值域     struct GLNode *hp;  //子表結點的指針域,hp指向表頭   };   struct GLNode *tp;  //這里的tp相當於鏈表的next指針,用於指向下一個數據元素 }*Glist;

 

例如,用這種結構結構表示C = (a,(b,c,d)),效果圖為:


圖4 廣義表C的結構示意圖

實現代碼:

Glist creatGlist(Glist C)
{   C
= (Glist)malloc(sizeof(Glist));   C->tag = 1;   C->hp = (Glist)malloc(sizeof(Glist));   C->tp = NULL;   // 表頭原子a   C->hp->tag = 0;   C->atom = 'a';   C->hp->tp = (Glist)malloc(sizeof(Glist));   C->hp->tp->tag = 1;   C->hp->tp->hp = (Glist)malloc(sizeof(Glist));   C->hp->tp->tp = NULL;   // 原子b   C->hp->tp->hp->tag = 0;   C->hp->tp->hp->atom = 'b';   C->hp->tp->hp->tp = (Glist)malloc(sizeof(Glist));   // 原子c   C->hp->tp->hp->tp->tag = 0;   C->hp->tp->hp->tp->atom = 'c';   C->hp->tp->hp->tp->tp = (Glist)malloc(sizeof(Glist));   // 原子d   C->hp->tp->hp->tp->tp->tag = 0;   C->hp->tp->hp->tp->tp->atom = 'd';   C->hp->tp->hp->tp->tp->tp = NULL;
  
return C; }

 

總結

在編寫代碼時,一定要注意不要破壞廣義表中數據元素之間的關系,例如:C1 = (a,b,c,d)和 C2 = (a,(b,c),d),兩個廣義表中數據元素是一樣的,但是數據元素之間的關系不同,在 C1 中,各原子之間是並列的,而 C2 中,原子 a 和子表 (b,c) 和 d 是並列的。

補:M元多項式的表示

例如:

P(x,y,z) = x 10y 3z 2 + 2x 6y 3z 2 + 3x 5y 2z 2 + x 4y 4z + 6x 3y 4z + 2yz + 15

這是一個3元多項式(有3個變量:x,y,z),使用廣義表表示M元多項式,首先需要對多項式做一下變形:

P(x,y,z)=((x 10+2x 6)y 3+3x 5y 2)z 2+((x 4+6x 3)y 4+2y)z+15

經過變形后,P(x,y,z)可以這樣表示:

P(x,y,z)=Az 2+Bz+15,其中:A=Cy 3+Dy 2,B=Ey 4+Fy,C=x 10+2x 6,D=3x 5,E=x 4+6x 3,F=2


經過兩輪轉化后,P這個 3 元多項式分解成了由 A 多項式和 B 多項式組成的一元多項式(只有一個變元 z ),而 A 也變成了由 C 多項式和 D 多項式組成的一元多項式,…。

當全部轉化成能用一元多項式表示時,每一個一元多項式只需要存儲各項的指數和系數就可以了。

廣義表中每個結點的構成如圖5所示:


圖5 多項式結點構成

代碼表示:

typedef struct MPNode
{   
int tag;  //區分原子結點和子表結點(0代表原子;1代表子表)   int exp;  //存放指數域   union
  {     
int coef;  //存放多項式的系數     struct MPNode *hp;  //當多項式系數為子表時,用它   };   struct MPNode *tp;  //相當於線性鏈表的next,指向下一個數據元素 }*MPList;

 

注意:在表示多項式的時候,每一個一元多項式,都要額外添加一個表頭結點,用於記錄此一元多項式中的變元(是x,y還是z),而所有的變元可以預先存儲在數組中,這樣就可以利用每一個表頭結點中的 exp 變量表示變元所在數組中的位置下標。


實現代碼:

MPList initP(MPList P)
{   
char a[] = "xyz";   MPList F = (MPList)malloc(sizeof(MPList));   F->tag = 1;   F->exp = 0;  // 表示F這個一員多項式中的變元位a[0],也就是x   F->hp = NULL;   F->tp = (MPList)malloc(sizeof(MPList));   F->tp->tag = 0;   F->tp->exp = 0;   // x的指數為0   F->tp->coef = 2;   // 系數為2   F->tp->tp = NULL;  // tp截止,說明F=2;   MPList E = (MPList)malloc(sizeof(MPList));   E->tag = 1;   E->exp = 0;  // E中變元位a[0],即x   E->hp = NULL;   E->tp = (MPList)malloc(sizeof(MPList));   E->tp->tag = 0;   E->tp->exp = 4;   E->tp->coef = 1;   E->tp->tp = (MPList)malloc(sizeof(MPList));   E->tp->tp->tag = 0;   E->tp->tp->exp = 3;   E->tp->tp->coef = 6;   E->tp->tp->tp = NULL;// 截止,E=1*x4+6*x3(x后為它的指數)   MPList D = (MPList)malloc(sizeof(MPList));   D->tag = 1;   D->exp = 0;// D中變元為a[0],即x   D->hp = NULL;   D->tp = (MPList)malloc(sizeof(MPList));   D->tp->tag = 0;   D->tp->exp = 5;   D->tp->coef = 3;   D->tp->tp = NULL;  // 截止,D=3*x5(5是x的指數);   MPList C = (MPList)malloc(sizeof(MPList));   C->tag = 1;   C->exp = 0;  // C中變元為a[0]=x;   C->hp = NULL;   C->tp = (MPList)malloc(sizeof(MPList));   C->tp->tag = 0;   C->tp->exp = 10;   C->tp->coef = 1;   C->tp->tp = (MPList)malloc(sizeof(MPList));   C->tp->tp->tag = 0;   C->tp->tp->exp = 6;   C->tp->tp->coef = 2;   C->tp->tp->tp = NULL;  // C=1*x10+2*x6   MPList B = (MPList)malloc(sizeof(MPList));   B->tag = 1;   B->exp = 1;  // B中變元為a[1]=y   B->hp = NULL;   B->tp = (MPList)malloc(sizeof(MPList));   B->tp->tag = 1;   B->tp->exp = 4;   B->tp->hp = E;   B->tp->tp = (MPList)malloc(sizeof(MPList));   B->tp->tp->tag = 1;   B->tp->tp->exp = 1;   B->tp->tp->hp = F;   B->tp->tp->tp = NULL;  // B=E*y4+F*x1;   MPList A = (MPList)malloc(sizeof(MPList));   A->tag = 1;   A->exp = 1;  // A中變元為a[1]=y;   A->hp = NULL;   A->tp = (MPList)malloc(sizeof(MPList));   A->tp->tag = 1;   A->tp->exp = 3;   A->tp->hp = C;   A->tp->tp = (MPList)malloc(sizeof(MPList));   A->tp->tp->tag = 1;   A->tp->tp->exp = 2;   A->tp->tp->hp = D;   A->tp->tp->tp = NULL;  // A=C*y3+D*y2;   P = (MPList)malloc(sizeof(MPList));   P->tag = 1;   P->exp = 3;  // 表示表元的數量   P->hp = (MPList)malloc(sizeof(MPList));   P->tp = NULL;   P->hp->tag = 1;   P->hp->exp = 2;  // P中變元為a[2]=z;   P->hp->hp = NULL;   P->hp->tp = (MPList)malloc(sizeof(MPList));   P->hp->tp->tag = 1;   P->hp->tp->exp = 2;   P->hp->tp->hp = A;   P->hp->tp->tp = (MPList)malloc(sizeof(MPList));   P->hp->tp->tp->tag = 1;   P->hp->tp->tp->exp = 1;   P->hp->tp->tp->hp = B;   P->hp->tp->tp->tp = (MPList)malloc(sizeof(MPList));   P->hp->tp->tp->tp->tag = 0;   P->hp->tp->tp->tp->exp = 0;   P->hp->tp->tp->tp->coef = 15;   P->hp->tp->tp->tp->tp = NULL;  // P=A*z2+B*z1+15
  return P; }

 


免責聲明!

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



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