【C/C++】實現數據結構廣義表


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 }

 

 


免責聲明!

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



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