廣義表的基本概念node
廣義表(Lists,又稱列表)是線性表的推廣。線性表定義爲n>=0個元素a1,a2,a3,…,an的有限序列。線性表的元素僅限於原子項,原子是做爲結構上不可分割的成分,它能夠是一個數或一個結構,若放鬆對錶元素的這種限制,允許它們具備其自身結構,這樣就產生了廣義表的概念。算法
廣義表是n (n>=0)個元素a1,a2,a3,…,an的有限序列,其中ai或者是原子項,或者是一個廣義表。一般記做LS=(a1,a2,a3,…,an)。LS是廣義表的名字,n爲它的長度。若ai是廣義表,則稱它爲LS的子表。數據結構
抽象數據類型廣義表的定義以下:函數
ADT Glistatom
{spa
數據對象: D={ei | i=1,2,..,n;n>=0 ; eiÎAtomSet 或ei ÎGlist,指針
AtomSet爲某個數據對象}對象
數據關係:R1={< ei-1, ei > | ei-1 , ei ÎD,2<=i<=n}blog
基本操做:遞歸
InitGList( &L);
操做結果:建立空的廣義表L。
CreateGList(&L,S);
初始條件:S是廣義表的書寫形式串。
操做結果:由S建立廣義表L。
DestroyGList(&L);
初始條件:廣義表L存在。
操做結果:銷燬廣義表L。
CopyGList( &T,L);
初始條件:廣義表L存在。
操做結果:由廣義表L複製獲得廣義表T。
GListLength(L);
初始條件:廣義表L存在。
操做結果:求廣義表L的長度,即元素個數。
GListDepth(L);
初始條件:廣義表L存在。
操做結果:求廣義表L的深度。
GListEmpty (L);
初始條件:廣義表L存在。
操做結果:斷定廣義表L是否爲空。
GetHead(L);
初始條件:廣義表L存在。
操做結果:取廣義表L的頭。
GetTail( &T,L);
初始條件:廣義表L存在。
操做結果:取廣義表L的尾。
InsertFirst_GL(&L,e);
初始條件:廣義表L存在。
操做結果:插入元素e做爲廣義表L的第一元素。
DeleteFirst_GL(&L,&e);
初始條件:廣義表L存在。
操做結果:刪除廣義表L的第一元素,並用e返回其值。
Traverse_GL (L,visit());
初始條件:廣義表L存在。
操做結果:遍歷廣義表L,用函數visit處理每一個元素。
}
一般用圓括號將廣義表括起來,用逗號分隔其中的元素。爲了區別原子和廣義表,書寫時用大寫字母表示廣義表,用小寫字母表示原子。若廣義表LS(n>=1)非空,則a1是LS的表頭,其他元素組成的表(a2,…an)稱爲LS的表尾。
顯然廣義表是遞歸定義的,這是由於在定義廣義表時又用到了廣義表的概念。廣義表的例子以下:
(1)A=()——A是一個空表,其長度爲零。
(2)B=(e)——表B只有一個原子e,B的長度爲1。
(3)C=(a,(b,c,d))——表C的長度爲2,兩個元素分別
爲原子a和子表(b,c,d)。
(4)D=(A,B,C)——表D的長度爲3,三個元素
都是廣義表。顯然,將子表的值代入後,
則有D=(( ),(e),(a,(b,c,d)))。
(5)E=(E)——這是一個遞歸的表,它的長度爲2,E至關於一個無限的廣義表E=(a,(a,(a,(a,…)))).
從上述定義和例子可推出廣義表的三個重要結論:
(1)廣義表的元素能夠是子表,而子表的元素還能夠是子表,。由此,廣義表是一個多層次的結構,能夠用圖形象地表示。P108
(2)廣義表可爲其它表所共享。例如在上述例(4)中,廣義表A,B,C爲D的子表,則在D中能夠沒必要列出子表的值,而是經過子表的名稱來引用。
(3)廣義表的遞歸性。
綜上所述,廣義表不只是線性表的推廣,也是樹的推廣。
由表頭、表尾的定義可知:任何一個非空廣義表其表頭多是原子,也多是列表,而其表尾一定是列表。
gethead(B)=e gettail(B)=( )
gethead(D)=A gettail(D)=(B,C)
因爲(B,C)爲非空廣義表,則可繼續分解獲得:
gethead(B,C)=B gettail(B,C)=(C)
注意廣義表( )和( ( ) )不一樣。前者是長度爲0的空表,
對其不能作求表頭的和表尾的運算;然後者是長度爲1的非空表(只不過該表中惟一的一個元素是空表)。對其可進行分解,獲得表頭和表尾均爲空表( )。
廣義表的存儲結構
因爲廣義表(a1,a2,a3,…an)中的數據元素能夠具備不一樣的結構,(或是原子,或是廣義表),所以,難以用順序存儲結構表示,一般採用鏈式存儲結構,每一個數據元素可用一個結點表示。
因爲廣義表中有兩種數據元素,原子或廣義表,所以,須要兩種結構的結點:一種是表結點,用以表示列表;一種是原子結點,用以表示原子。
若列表不空,則可分解成表頭和表尾;反之,一對肯定的表頭和表尾可惟一肯定列表。由此,一個表結點可由三個域組成:標誌域、指示表頭的指針域和指示表尾的指針域;而原子結點只需兩個域:標誌域和值域。
一、僅有表結點由三個域組成:
標誌域、指示表頭的指針域和指示表尾的指針域;而原子域只需兩個域:標誌域和值域。
頭尾鏈表存儲表示
示例如圖:
這種存儲結構的三個特色:
1。除空表的表頭指針爲空外,對任何非空列表,其表頭指針均指向一個表結點,且該結點中的hp域指示列表表頭,tp域指向列表表尾(除非表尾爲空,則指針爲空,不然必爲表結點);
2。容易分清列表中原子和子表所在層次。如在列表D中,原子e和a在同一層次上,而b、c和d在同一層次且比e和a低一層,B和C是同一層的子表;
3。最高層的表結點個數即爲列表的長度。
二、表結點和原子結點均由三個域組成:標誌域、指示表頭的指針域和指示表尾的指針域;原子結點的三個域爲:標誌域、值域和指示表尾的指針域。
其類型定義以下:
擴展線性鏈表存儲表示
示例如圖:
廣義表基本操做的實現
咱們以頭尾表示法存儲廣義表,討論廣義表的有關操做的實現。因爲廣義表的定義是遞歸的,所以相應的算法通常也都是遞歸的。
GList Head(GList ls) { if ls->tag = = 1 then p = ls->hp; return p; } 算法5.6 GList Tail(GList ls) { if ls->tag = = 1 then p = ls->tp; return p; } 算法5.7
int Create(GList *ls, char * S) { Glist p; char *sub; if StrEmpty(S) *ls = NULL; else { if (!(*ls = (GList)malloc(sizeof(GLNode)))) return 0; if (StrLength(S) = = 1) { (*ls)->tag = 0; (*ls)->data = S; } else { (*ls)->tag = 1; p = *ls; hsub =SubStr(S,2,StrLength(S)-2); do { sever(sub,hsub); Create(&(p->ptr.hp), sub); q = p; if (!StrEmpty(sub)){ if (!(p = (GList)malloc(sizeof(GLNode)))) return 0;; p->tag = 1; q->ptr.tp = p; } }while (!StrEmpty(sub)); q->ptr.tp = NULL; } } return 1; } 算法5.8 int sever(char *str, char *hstr) { int n = StrLength(str); i= 1; k = 0; for (i = 1, k = 0; i <= n || k != 0; ++i) { ch=SubStr(str,i,1); if (ch = = '(') ++k; else if (ch = = ')') --k; } if (i <= n) { hstr =SubStr(str,1,i-2); str= SubStr(str,i,n-i+1); } else { StrCopy(hstr,str); ClearStr(str); } }
int Merge(GList ls1,GList ls2, Glist *ls) { if (!(*ls = (GList)malloc(sizeof(GLNode)))) return 0; *ls->tag = 1; *ls->hp = ls1; *ls->tp = ls2; return 1; } 算法5.10
int Depth(GList ls) { if (!ls) return 1; /*空表深度爲1*/ if (ls->tag = = 0) return 0; /*單元素深度爲0*/ for (max = 0,p = ls; p; p = p->ptr.tp) { dep = Depth(p->ptr.hp); /*求以p->ptr.hp 尾頭指針的子表深度*/ if (dep > max) max = dep; } return max+1; /*非空表的深度是各元素的深度的最大值加1*/ } 算法5.11
int CopyGList(GList ls1, GList *ls2) { if (!ls1) *ls2 = NULL; /*複製空表*/ else { if (!(*ls2 = (Glist)malloc(sizeof(Glnode)))) return 0; /*建表結點*/ (*ls2)->tag = ls1->tag; if (ls1->tag = = 0) (*ls2)->data = ls1->data; /*複製單元素*/ else { CopyGList(&((*ls2)->ptr.hp), ls1->ptr.hp); /*複製廣義表ls1->ptr.hp 的一個副本*/ CopyGList(&((*ls2)->ptr.tp) , ls1->ptr.tp); /*複製廣義表ls1->ptr.tp 的一個副本*/ } } return 1; }
廣義表的二叉樹實現的形式
輸入二叉樹的廣義表形式,將其轉變爲二叉樹形式,至於怎樣輸入廣義表須要程序規定。
定義包含頭文件文件t11.h中
#include"stdio.h" #include"string.h" #include"ctype.h" #include"malloc.h" #include"stdlib.h" //atoi(),exit(); #include"io.h" //eof() #include"math.h" #define TRUE 1 #define FALSE 0 #define OK 1 #define ERROR 0 typedef int Status; typedef int Boolean; 定義數據結構頭文件gercs.h中 #define INIT_STACK 100 #define INIT_STACK_ADD 20 typedef struct node // 二叉樹的數據結構定義 { char data; struct node *lchild; struct node *rchild; }*Bitree,pBitree; typedef struct { char *bottom; char *top; int stacksize; }Sqstack; struct Binode { Bitree lp; }; struct Sqstack1 { Binode *bottom; Binode *top; int stacksize; }; typedef struct { Binode *front; Binode *rear; int queuesize; }*linkqueue,queue; Sqstack W; 定義包含實現函數功能模塊gercs.cpp中 void inittree(Bitree &T) { T=NULL; } void initqueue(queue &Q) { Q.front=(Binode*)malloc(INIT_STACK*sizeof(Binode)); Q.rear=Q.front; Q.queuesize=INIT_STACK; } void initstack(Sqstack &L) { L.bottom=(char*)malloc(INIT_STACK*sizeof(char)); if(!L.bottom) { printf("內存分配失敗!!"); exit(0); } L.top=L.bottom; L.stacksize=INIT_STACK; } void initstack1(Sqstack1 &L) { L.bottom=(Binode*)malloc(INIT_STACK*sizeof(Binode)); if(!L.bottom) { printf("內存分配失敗!!"); exit(0); } L.top=L.bottom; L.stacksize=INIT_STACK; } void enqueue(queue &Q,Bitree T) { if(Q.rear-Q.front > Q.queuesize) { Q.front=(Binode*)realloc(Q.front,(Q.queuesize,INIT_STACK_ADD)*sizeof(Binode)); Q.rear=Q.front+Q.queuesize; Q.queuesize+=INIT_STACK_ADD; } (Q.rear++)->lp=T; } void push(Sqstack &L,char ch) { if(L.top-L.bottom > L.stacksize) { L.bottom=(char*)realloc(L.bottom,(L.stacksize+INIT_STACK_ADD)*sizeof(char)); L.top=L.bottom+L.stacksize; L.stacksize+=INIT_STACK_ADD; } *(L.top++)=ch; } void push1(Sqstack1 &L,Bitree ch) { if(L.top-L.bottom > L.stacksize) { L.bottom=(Binode*)realloc(L.bottom,(L.stacksize+INIT_STACK_ADD)*sizeof(Binode)); L.top=L.bottom+L.stacksize; L.stacksize+=INIT_STACK_ADD; } (L.top++)->lp=ch; } Status pop(Sqstack &L,char &e) { if(L.bottom == L.top) return ERROR; else { e=*(--L.top); return OK; } } Status pop1(Sqstack1 &L,Bitree &e) { if(L.bottom == L.top) return ERROR; else { e=(--L.top)->lp; return OK; } } Status emptystack(Sqstack L) { if(L.bottom == L.top) return OK; else return ERROR; } Status emptystack1(Sqstack1 L) { if(L.bottom == L.top) return OK; else return ERROR; } Sqstack shuru(Sqstack &S) { Sqstack R; initstack(R); char ch,ch1; printf("輸入廣義表二叉樹形式:"); ch=getchar(); while(10 != ch) { if(ch >= 'a' && ch <= 'z')//|| ch >= 'A' && ch <='Z') { push(S,ch); ch1=getchar(); if(')' == ch1) { push(S,10); push(S,10); } ch=ch1; } else { ch1=getchar(); if(',' == ch && ',' == ch1) push(S,10); ch=ch1; } } while(!emptystack(S)) { pop(S,ch); //printf("%-3c",ch); push(R,ch); } return R; } void Createtree(Bitree &T) // 先序建立二叉樹 { // printf("進入了!"); char ch; pop(W,ch); // printf("ch=%c ",ch); if(ch == 10) // 若是是回車鍵置爲空 T=NULL; else { T=(Bitree)malloc(sizeof(pBitree)); if(!T) { printf("分配失敗!"); exit(0); } T->data=ch; Createtree(T->lchild); Createtree(T->rchild); } // getchar(); } // 建立二叉樹結束 void xianxu(Bitree T,Sqstack1 &S) // 先序非遞歸遍歷,採用的是保存右孩子的地址經過棧實現 { printf("先序非遞歸遍歷輸出:\n"); if(T) { if(T->rchild) push1(S,T->rchild); // 專門壓入右孩子指針地址 printf("%-3c",T->data); T=T->lchild; // 更新指針 }else exit(0); while(T || !emptystack1(S)) // 循環終止條件 { if(T!= NULL) // 始終做爲一個點存在加以判斷,一種狀況是一直指向左孩子,另外一種就是出棧彈出的右孩子 { printf("%-3c",T->data); // 輸出節點的數據域 if(T->rchild != NULL) // 該節點存在右孩子,將右孩子入棧 push1(S,T->rchild); T=T->lchild; // 更新指針,始終往左走 } else pop1(S,T); } } void cengci(Bitree T,queue &Q) { if(!T) { printf("樹爲空!"); exit(0); } Binode *P,*S; S=P=Q.front; enqueue(Q,T); while(P != Q.rear) { if(P->lp->lchild) enqueue(Q,P->lp->lchild); if(P->lp->rchild) enqueue(Q,P->lp->rchild); P++; } printf("層次遍歷爲:\n"); while(S < Q.rear) { printf("%-3c",S->lp->data); S++; } } 最後就是定義主函數函數調用了,包含於頭文件main_gercs.cpp中 #include"t11.h" #include"gercs.h" #include"gercs.cpp" void main() { // char ch; Bitree S; queue U; Sqstack1 Q; initstack(W); initstack1(Q); inittree(S); initqueue(U); W=shuru(W); /* while(!emptystack(W)) { pop(W,ch); printf("%-3c",ch); }*/ Createtree(S); xianxu(S,Q); printf("\n"); cengci(S,U); printf("\n"); }
編譯運行以後: