廣義表3——廣義表的擴充套件線性連結串列表示
阿新 • • 發佈:2018-12-22
【結點結構】
用擴充套件線性連結串列表示時,廣義表也可以包含兩種結點:表結點和原子結點,這兩種結點都包含三個域。其中,表結點由標誌域tag、表頭指標域hp、表尾指標域tp構成:原子結點由指標域、原子的值域和表尾指標域構成。
標誌域tag用來區分當前結點是表結點還是原子結點,當tag=0時為原子結點,tag=1時為表結點;hp和tp分別指向廣義表的表頭和表尾;atom用來儲存原子結點的值。擴充套件線性連結串列的結點
如圖所示。
例如,A=(),B=(a),C=(a,(b,c)),D=(A,B,C),E=(a,E)
則廣義表A、B、C、D、E的擴充套件線性連結串列儲存結構如圖所示
【儲存結構】
typedef enum{ATOM,LIST}ElemTag; /*ATOM=0,表示原子,LIST=1,表示子表*/ typedef struct { ElemTag tag; /*標誌位tag用於區分元素是原子還是子表*/ union { AtomType atom; /*AtomType是原子結點的值域,使用者自己定義型別*/ struct { struct GLNode *hp,*tp; /*hp指向表頭,tp指向表尾*/ }ptr; }; }*GList,GLNode;
【問題】
編寫演算法,利用擴充套件線性連結串列表示法建立廣義表,要求在輸入廣義表的同時實現建立,設廣義表按形式:(a,b,(a,(a,b,c),d),e)輸入,並求廣義表的深度和長度。
【分析】
該題是北京工業大學考研試題。廣義表中的元素有原子和子表,在讀入輸入的字串時,遇到左括號"("時,就遞迴構造子表;若是原子,就建立原子結點;若讀入逗號“,”就遞迴構造後續子表;若n為0,則構造含空格字元的空表,直到遇見結束符“\n”為止。
main.cpp
#include<stdio.h> #include<stdlib.h> #include<iostream> using namespace std; typedef char AtomType;//元素型別為字元型 typedef enum { ATOM, LIST }ElemTag; /*ATOM=0,表示原子,LIST=1,表示子表*/ //廣義表的儲存結構 struct GNode { ElemTag tag; //標誌域 union { AtomType atom; //值域 struct GNode *hp;//子表的表頭指標 }; struct GNode *tp; //後繼結點的指標 }; int LengthGList(struct GNode *GL); //求廣義表的長度 int DepthGList(struct GNode *GL); //求廣義表的深度 void CreateGList(struct GNode **GL);//建立廣義表的儲存結構 void PrintGList(struct GNode *GL); //列印輸出廣義表 int SearchGList(struct GNode *GL, AtomType e);//查詢等於給定字元的單元素結點,查詢成功則返回1,否則返回0 void main() { int flag; AtomType e; struct GNode *GL; cout << "輸入一個廣義表(以回車結束)." << endl; CreateGList(&GL); cout << "輸出廣義表:" << endl; PrintGList(GL); cout << endl; cout << "廣義表的長度:"; cout << LengthGList(GL->hp) << endl; cout << "廣義表的深度:"; cout << DepthGList(GL->hp) << endl; cout << "請輸入要查詢的原子元素:" << endl; cin >> e; flag = SearchGList(GL, e); if (flag) cout << "廣義表中存在查詢的元素。" << endl; else cout << "要查詢的元素不存在。" << endl; system("pause"); } int LengthGList(struct GNode *GL) //求廣義表的長度 { if (GL != NULL) return(1 + LengthGList(GL->tp)); else return(0); } int DepthGList(struct GNode *GL) //求廣義表的深度 { int max = 0;//給max賦初值 int dep; //遍歷表中每一個結點,求出所有子表的最大深度 while (GL != NULL) { if (GL->tag == LIST) { dep = DepthGList(GL->hp);//遞迴呼叫求出一個子表的深度 if (dep > max) max = dep;//讓max始終為同一層所求過的子表中深度的最大值 } GL = GL->tp;//使GL指向同一層的下一個結點 } return max + 1;//返回表的深度 } void CreateGList(struct GNode **GL) //建立廣義表的儲存結構 { char ch; scanf("%c", &ch);//讀入一個字元,此處只可能讀入空格#、左括號或英文字母 if (ch == '#')//若輸入為空格,則置表頭指標為空 *GL = NULL; else if (ch == '(')//若輸入為左括號則建立由*GL所指向的子表結點並遞迴構造子表 { *GL = (struct GNode*)malloc(sizeof(struct GNode)); (*GL)->tag = LIST; CreateGList(&((*GL)->hp)); } else { //若輸入為字元則建立由*GL所指向的單元素結點 *GL = (struct GNode*)malloc(sizeof(struct GNode)); (*GL)->tag = ATOM; (*GL)->atom = ch; } scanf("%c", &ch);//此處讀入的字元必為逗號、右括號或分號 if (*GL == NULL)//若*GL為空,則什麼都不做 ; else if (ch == ',')//若輸入逗號則遞迴構造後繼表 CreateGList(&((*GL)->tp)); else if ((ch == ')') || (ch == '\n'))//若輸入為右括號或分號則置*GL的後繼指標域為空 (*GL)->tp = NULL; } void PrintGList(struct GNode *GL) //列印輸出廣義表 { if (GL->tag == LIST) //對於子表, { printf("(");//則輸出左括號,作為開始符號 if (GL->hp == NULL)//若子表為空則輸出‘#’字元 printf("#"); else//若子表非空,則遞迴輸出子表 PrintGList(GL->hp); printf(")");//當一個子表輸出結束後,應輸出一個右括號終止符 } else//對於原子元素結點,則輸出該結點的值 printf("%c", GL->atom); if (GL->tp != NULL)//輸出結點的後繼子表 { printf(",");//先輸出逗號分隔符 PrintGList(GL->tp);//再遞迴輸出後繼子表 } } int SearchGList(struct GNode *GL, AtomType e) //查詢等於原子元素結點,查詢成功則返回1,否則返回0 { while (GL != NULL) { if (GL->tag == LIST)//存在子表,則遞迴搜尋本層該子表 { if (SearchGList(GL->hp, e)) return 1; } else//存在原子元素結點,則查詢是否存在值e ,若存在則返回1 { if (GL->atom == e) return 1; } GL = GL->tp;//使GL指向同一層的下一個結點 } return 0;//搜尋不到值e ,則返回0 }
結果: