广义表

原链接 https://www.cnblogs.com/lihuidashen/p/4852484.html

广义表的基本概念

广义表(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 Glist

{

   数据对象: D={ei | i=1,2,..,n;n>=0 ;  eiÎAtomSet 或ei ÎGlist,

                                     AtomSet为某个数据对象}

   数据关系:R1={< ei-1, ei > | ei-1 , ei ÎD,2<=i<=n}

   基本操作:

       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、仅有表结点由三个域组成:

    标志域、指示表头的指针域和指示表尾的指针域;而原子域只需两个域:标志域和值域。

 

头尾链表存储表示

  1. typedef enum {ATOM,LIST } ElemTag;  //ATOM==0:表示原子,LIST==1:表示子表  
  2. typedef struct GLNode {  
  3.     ElemTag  tag;  //公共部分,用以区分原子部分和表结点  
  4.     union {       //原子部分和表结点的联合部分  
  5.       AtomType  atom; //atom是原子结点的值域,AtomType由用户定义  
  6.       struct { struct GLNode *hp, *tp;} ptr;  
  7.              // ptr是表结点的指针域,ptr.hp 和ptr.tp分别指向表头和表尾  
  8.     };  
  9. } *Glist;  //广义表类型  


示例如图:

 

这种存储结构的三个特点:

1。除空表的表头指针为空外,对任何非空列表,其表头指针均指向一个表结点,且该结点中的hp域指示列表表头,tp域指向列表表尾(除非表尾为空,则指针为空,否则必为表结点);

2。容易分清列表中原子和子表所在层次。如在列表D中,原子e和a在同一层次上,而b、c和d在同一层次且比e和a低一层,B和C是同一层的子表;

3。最高层的表结点个数即为列表的长度。

 

2、表结点和原子结点均由三个域组成:标志域、指示表头的指针域和指示表尾的指针域;原子结点的三个域为:标志域、值域和指示表尾的指针域。

 

其类型定义如下:

扩展线性链表存储表示

  1. Typedef enum { ATOM,LIST} ElemTag;                                
  2.     //ATOM==0:表示原子,LIST==1:表示子表  
  3. Typedef struct GLNode {  
  4.     ElemTag    tag;  //公共部分,用以区分原子部分和表结点  
  5.     union {  //原子部分和表结点的联合部分  
  6.         AtomType    atom;  //原子结点的值域  
  7.         struct GLNode  *hp;  //表结点的表头指针  
  8.         };  
  9.         struct GLNode    *tp;    
  10.                 //相当于线性链表的next,指向下一个元素结点  
  11. } *Glist;  //广义表类型Glist 是一种扩展的线性链表  


示例如图:

 

 

广义表基本操作的实现

我们以头尾表示法存储广义表,讨论广义表的有关操作的实现。由于广义表的定义是递归的,因此相应的算法一般也都是递归的。

⒈广义表的取头、取尾

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

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

⒉建立广义表的存储结构

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

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);

}

}

⒊以表头、表尾建立广义表

1

2

3

4

5

6

7

8

9

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

4.求广义表的深度

 

1

2

3

4

5

6

7

8

9

10

11

12

13

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

 

⒌复制广义表

1

2

3

4

5

6

7

8

9

10

11

12

13

14

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中

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

128

129

130

131

132

133

134

135

136

137

138

139

140

141

142

143

144

145

146

147

148

149

150

151

152

153

154

155

156

157

158

159

160

161

162

163

164

165

166

167

168

169

170

171

172

173

174

175

176

177

178

179

180

181

182

183

184

185

186

187

188

189

190

191

192

193

194

195

196

197

198

199

200

201

202

203

204

205

206

207

208

209

210

211

212

213

214

215

216

217

218

219

220

221

222

223

224

225

226

227

228

229

230

231

232

233

234

235

236

237

238

239

240

241

242

243

244

245

246

247

248

249

250

251

252

253

254

255

256

257

258

259

260

261

262

263

264

265

266

267

268

269

270

271

272

273

274

275

276

277

278

279

280

281

282

283

284

#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");

  

  

}

  编译运行之后:

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值