1. 廣義表的定義
每個元素可以為Atom,原子,也可以為線性表。
線性表的推廣。線性表元素有唯一的前驅和后繼,為線性表,而廣義表是多層次的線性表
表頭:第一個元素,可能是原子,可能是廣義表
表尾:除了第一個元素,剩余的元素,所構成的廣義表
舉例:
A = (a,b,(c,d),e)
head(A) = a
tail(A) = (b,(c,d),e)
遍歷操作:
取表頭,取表尾 ,取表頭..
長度:最外層的元素數,即最外層的','+1
深度:括號層數
2. 廣義表的兩種存儲結構(子表法)
2.1鏈式存儲結構 - 每個數據元素可以用一個節點表示
元素可以為原子或列表
原子節點:標志域、值域
列表節點:標志域、指示表頭的指針域、指示表尾的指針域
空表:A = NULL
除了空表,表頭指針指向一個表節點,表節點再分表頭、表尾...
最高層表節點(可能原子、子表)的個數就是表長度? A = (a,b,(c,d),e) 最高層表頭是先a,表尾是(b,(c,d),e),表頭是b,表尾((c,d),e)..就是第一層的表尾直到為空之前,有過的表尾指針+1
判斷是否在同一層次?
是這樣的: 最高層處於同一層,后繼的tail指針指向的是同一層,否則,head指針,或者表頭是Atom,都是下一層。
2.2擴展線性表存儲結構
不是用表頭表尾指針了,而是,每一個節點,不管是子表還是原子,都有一個指向本子表下一個元素的next指針
A = (a,b,(c,d))
A -> |1,HP,TP|
| |
a -> b -> (c,d)
|
c -> d下面,實現了廣義表的兩種定義,以及基於遞歸的一些操作。
1 #include<bits/stdc++.h> 2 #define AtomType int 3 typedef enum{ATOM,LIST}ElemTag; //ATOM = 0:原子;LIST = 1:子表 4 /*線性表存儲之鏈式*/ 5 typedef struct GLNode{ 6 ElemTag tag; //枚舉類型的標志域,只能取定義了的枚舉值 7 union{ //union聯合體,下面兩部分只能取其一;要么取AtomType;要么取結構體ptr,ptr包括兩個指針hp,tp 8 AtomType atom; 9 struct{ 10 struct GLNode *hp,*tp; 11 }ptr; 12 }; 13 }*GList; //定義廣義表類型,GList為指針 14 15 /*線性表存儲之擴展線性表 = 子表法*/ 16 typedef struct GLNode2{ 17 ElemTag tag; 18 union{ 19 AtomType atom; 20 struct GLNode2 *hp; //對於原子,tp就是指向其相同層次的下一個元素 21 //對於列表,hp指向本列表內部第一個元素,而tp是指向本層次上的下一個元素 22 }; 23 struct GLNode2 *tp; 24 } *GList2; 25 /* 26 * 討論廣義表的遞歸算法 : 分治法進行遞歸算法設計 27 * 1. 問題可拆解成子問題,與原問題性質相同,規模變小 28 * 2. 有遞歸終止條件 29 */ 30 31 /*求廣義表的深度 - 采用鏈式存儲結構時 32 * 廣義表的深度:()的重數 空表() 深度為1.原子深度為0 33 * 34 */ 35 int GListDepth(GList L) { 36 if(!L) return 1; //空表1 37 if(L->tag ==ATOM ) return 0; 38 GList pp; 39 //遍歷同一層,遞歸下一層,取表尾,取表頭,第一步先去一個表頭 40 int max; 41 for(max = 0, pp =L;pp!=NULL;pp = pp->ptr.tp){ 42 int dep = GListDepth(pp->ptr.hp) ; 43 if(dep > max) max = dep; //這一步比較,是比較同一層的depth 44 } 45 return max+1; 46 } 47 //練習 48 int depth_my(GList L) { 49 if(L == NULL){ 50 return 1; 51 } 52 if(L->tag == ATOM){ 53 return 0; 54 } 55 int max = 0; 56 GList pp; 57 for(max = 0,pp=L;pp!=NULL;pp = pp->ptr.tp){ 58 int dep = depth_my(pp->ptr.hp); 59 if(dep >max) max = dep; 60 } 61 return max+1; 62 } 63 64 /* 65 求Depth2 == 子表法求dep 66 */ 67 int GListDepth_2(GList2 L){ 68 if(L == NULL) return 1; 69 if(L->tag == ATOM) return 0; 70 int max = 0; 71 GList2 pp; 72 for(max = 0,pp=L->hp;pp!=NULL;pp = pp->tp){ 73 int dep = GListDepth_2(pp); 74 if(dep >max) max = dep; 75 } 76 return max+1; 77 } 78 /*********************分界*****************************/ 79 /* 80 * 復制廣義表:copy深復制 -- 鏈式存儲 81 * 分別復制表頭、表尾,然后合成即可==遞歸 82 */ 83 void CopyGList(GList &T,GList L) { 84 //頭尾鏈表存儲,將L賦值給T 85 if(!L) T = NULL; //空 86 else{ 87 //創建一個節點 ,這個節點要么是ATOM,要么是廣義表 88 T = (GList)malloc(sizeof(GLNode)); 89 if(!T) exit(0); 90 T->tag = L->tag; 91 if(L->tag == ATOM) //是原子的話,復制原子 92 T->atom = L->atom; 93 //復制廣義表 94 else{ 95 //分別復制表頭和表尾 96 CopyGList(T -> ptr.hp,L->ptr.hp); 97 CopyGList(T->ptr.tp,L->ptr.tp); 98 } 99 } 100 } 101 //練習 102 void copy_my(GList&T,GList L) { 103 if(L == NULL) T = NULL; 104 else{ 105 T = (GList)malloc(sizeof(GLNode)); 106 if(!T) exit(0); 107 T -> tag = L -> tag; 108 if(L->tag == ATOM){ 109 T->atom = L->atom; 110 }else{ 111 copy_my(T -> ptr.hp,L->ptr.hp); 112 copy_my(T ->ptr.tp,L->ptr.tp); 113 } 114 } 115 } 116 /**********************分割線*************************/ 117 /* 118 * 創建一個廣義表:必考內容 119 * 廣義表的書寫,看成一個字符串S 120 * 下面頭尾鏈表法創建一個廣義表 121 */ 122 using namespace std; 123 string emp = "()" ; 124 125 void sever(string &str,string &hstr){ 126 //將非空串str分割成兩部分,hstr是表頭 127 int n = str.size(); 128 int i = -1; 129 int k = 0; //k記錄尚未配對的“(” 數 130 char ch; 131 do{ //搜索最外層第一個( 132 ++i; 133 ch = str[i]; 134 if(ch == '(') ++k; 135 else if(ch == ')') --k; 136 }while(i<n&&(ch != ','||k!=0)); 137 if(i<n){ 138 hstr =str.substr(0,i); 139 //printf("in\n"); 140 str = str.substr(i+1,n-i-1); 141 //printf("out\n"); 142 }else{ 143 hstr = str.substr(0,str.size()); 144 str.clear(); 145 } 146 } 147 148 void CreateGList(GList &L,string s){ 149 //采用頭尾鏈表存儲結構,創建L 150 if(s.compare(emp) == 0) L = NULL; 151 else{ 152 L = (GList)malloc(sizeof(GLNode)); 153 if(!L) exit(0); 154 if(s.size() == 1){ //單個元素,建立原子節點 155 L->tag = ATOM; 156 L->atom = s[0]; 157 }else{ //表節點 ,表尾 158 L->tag = LIST; 159 GList p,q; 160 p = L; //p是指向當前子表(表尾節點)的指針 161 string sub; 162 sub = s.substr(1,s.size()-2); //去掉外層括號 163 string hsub; 164 do{ //重復建立n個子表 165 sever(sub,hsub); //sub中分理出表頭串hsub ,同時,sub去除了hsub 166 CreateGList(p->ptr.hp,hsub); 167 q = p; //記錄p,下面sub不為空,要再建立一個表尾節點,q記錄上一層的p,用以連接q->ptr.tp = q 168 if(!sub.empty()) { 169 p = (GList)malloc(sizeof(GLNode)); 170 if(!p)exit(0); 171 p -> tag = LIST; 172 q -> ptr.tp = p; 173 }//if 174 }while(!sub.empty()); 175 q -> ptr.tp = NULL; 176 // printf("has complete\n"); 177 } 178 } 179 } 180 181 182 int main(){ 183 // string s = "1232342342"; 184 // if(s.compare("123") == 0){ 185 // printf("13"); 186 // } 187 // printf("\n"); 188 // s = s.substr(1,s.size()-2); 189 // for(int i = 0;i<s.size();i++){ 190 // printf("%c",s[i]); 191 // } 192 193 string ss = "(2,3,4,(1,2))"; 194 GList L; 195 CreateGList(L,ss); 196 printf("深度:"); 197 printf("%d",GListDepth(L)); 198 return 0; 199 }