NOJ-求广义表的深度
第一次写博客,希望能够记录下自己的心得体会,如有错误, 欢迎指正。
广义表的基本概念
- 广义表是线性表的推广,是典型的递归定义。
- 广义表由两部分组成——表头(Head),表尾(tail)。第一个元素称为表头,其余元素称为表尾。
- 广义表的特点:
1. 列表的元素可以是子表,而子表的元素还可以是子表。
2. 列表可为其他列表共享。
3. 列表可以是一个递归的表,即列表也可以是本身的一个子表。
广义表的存储结构
typedef enum{ATOM,LIST} ElemTag;//ATOM代表原子,LIST代表子表
typedef struct GLNode{
ElemTag tag;//公共部分,用于区分原子结点和表结点
union{
char atom;//原子结点的值
struct {
struct GLNode *hp, *tp;
} ptr;//ptr是表结点的指针域,*hp指向表头,*tp指向表尾
};
} * GList,GLNode;
结点的结构:
- 标志域 tag用于区分原子结点和表结点。
- 指针域 union部分。 如果是表结点则是指向表头和表尾的指针,如果是原子结点则是值域,代表该原子结点的值。
广义表的建立
void SubString(char sub[], char S[], int start, int len);//脱外层括号
void sever(char str[], char hstr[]);//将str,之前的部分给hstr,在str中删掉hstr和,
void CreateGList(GList *L, char *S);//创建广义表
主要函数如上
脱外层括号
void SubString(char sub[], char S[], int start, int len)
{
int i = 0;
for (i=0;i<len;i++)
sub[i] = S[i + start - 1];
sub[i] = '\0';
}
这一部分用于将一个字符数组的一部分复制到另一个字符数组中,这样做是为了分离出表头和表尾。在下一个函数中有解释。
分离表头和表尾
void sever(char *str,char *hstr)
{
int i,k;//k记录左括号数
for (i=0,k=0;i<strlen(str);i++)
{
if(str[i]=='(')
k++;
if(str[i]==')')
k--;
if(k==0&&str[i]==',')
break;
}//此时的i为表头和表尾的分界
if(i<strlen(str)){
SubString(hstr, str, 1, i);//表头字符串
SubString(str, str, i + 2, strlen(str) - i - 1);//表尾字符串
}//表尾不空
else{
SubString(hstr, str, 1, strlen(str));
str[0] = 0;
}//表尾空
}
在这一部分中,传入一个去掉左右括号的字符串。
表头和表尾的分界点是:
从左到右遍历这个字符串如果遇到的左括号等于遇到的右括号且i所指的字符是‘,’那么就说明到了表头表尾的分界点
- 如果遍历完了,说明表尾是空表,把这个字符数组直接赋给表头,所以表尾的字符数组直接给第一个元素赋予0。
- 但是如果没有遍历完,说明表尾不空,那么把逗号之前赋给表头,逗号之后赋给表尾。
创建广义表
我觉得这部分是最难的,比求广义表的深度更难,因为它也是一个递归建立。
void CreateGList(GList *L, char *S)
{
GList p=(GList)malloc(sizeof(GLNode));
GList q=(GList)malloc(sizeof(GLNode));
char hsub[100]={0};
if(S==NULL)
(*L) = NULL; //如果传入空字符,就创建空表
else{
(*L) = (GList)malloc(sizeof(GLNode));
if(strlen(S)==1){
(*L)->tag = ATOM;
(*L)->atom = *S;
}
else{
SubString(S, S, 2, strlen(S) - 2);//脱去外层括号
p = (*L);
p->tag = LIST;
do{//重复建n个子表
sever(S, hsub);//从sub中分离出表头串hsub
CreateGList(&(p->ptr.hp), hsub);
if((*S)!=0){
q = p;
p = (GList)malloc(sizeof(GLNode));
p->tag = LIST;
q->ptr.tp = p;
}
} while ((*S) != 0);
p->ptr.tp = NULL;
}
}
}
分三种情况
- 传入一个空指针,则建立空表。
- 若传入一个字符,则建立一个只有原子的结点的广义表。
- 否则,则进行如下操作:
脱去外层括号;
从S中分离出表头hsub然后递归调用CreateGList函数;
若表尾结点非空,则把表尾结点插入在表尾。
广义表深度的递归法
int GListDepth(GList L)
{
if(!L)
return 1;
if(L->tag==ATOM)
return 0;
int max = 0,dep;
GList p;
for (p = L; p; p = p->ptr.tp)
{
dep = GListDepth(p->ptr.hp);
if(dep>max)
max = dep;
}
return (max + 1);
}
递归定义为:
- 当L为空表时,深度为1;
- 当L为原子时,深度为0;
- 归纳:Depth=1+MAX{Depth(α)}
所以这部分递归是比较简单的,只用不断在指针非空的情况下遍历广义表,遇到更大的就更新MAX的值。
完整代码为:
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
typedef enum{ATOM,LIST} ElemTag;//ATOM代表原子,LIST代表子表
typedef struct GLNode{
ElemTag tag;//公共部分,用于区分原子结点和表结点
union{
char atom;//原子结点的值
struct {
struct GLNode *hp, *tp;
} ptr;//ptr是表结点的指针域,*hp指向表头,*tp指向表尾
};
} * GList,GLNode;
void SubString(char sub[], char S[], int start, int len);//脱外层括号
void sever(char str[], char hstr[]);//将str,之前的部分给hstr,在str中删掉hstr和,
void CreateGList(GList *L, char *S);//创建广义表
int GListDepth(GList L);//广义表深度递归求法
int main()
{
char S[100] = {0};
scanf("%s", S);
GList L = (GList)malloc(sizeof(GLNode));
CreateGList(&L, S);
int n = GListDepth(L);
printf("%d\n%d", n,n);
}
void SubString(char sub[], char S[], int start, int len)
{
int i = 0;
for (i=0;i<len;i++)
sub[i] = S[i + start - 1];
sub[i] = '\0';
}
void sever(char *str,char *hstr)
{
int i,k;//k记录左括号数
for (i=0,k=0;i<strlen(str);i++)
{
if(str[i]=='(')
k++;
if(str[i]==')')
k--;
if(k==0&&str[i]==',')
break;
}//此时的i为表头和表尾的分界
if(i<strlen(str)){
SubString(hstr, str, 1, i);//表头字符串
SubString(str, str, i + 2, strlen(str) - i - 1);//表尾字符串
}//表尾不空
else{
SubString(hstr, str, 1, strlen(str));
str[0] = 0;
}//表尾空
}
void CreateGList(GList *L, char *S)
{
GList p=(GList)malloc(sizeof(GLNode));
GList q=(GList)malloc(sizeof(GLNode));
char hsub[100]={0};
if(S==NULL)
(*L) = NULL; //如果传入空字符,就创建空表
else{
(*L) = (GList)malloc(sizeof(GLNode));
if(strlen(S)==1){
(*L)->tag = ATOM;
(*L)->atom = *S;
}
else{
SubString(S, S, 2, strlen(S) - 2);//脱去外层括号
p = (*L);
p->tag = LIST;
do{//重复建n个子表
sever(S, hsub);//从sub中分离出表头串hsub
CreateGList(&(p->ptr.hp), hsub);
if((*S)!=0){
q = p;
p = (GList)malloc(sizeof(GLNode));
p->tag = LIST;
q->ptr.tp = p;
}
} while ((*S) != 0);
p->ptr.tp = NULL;
}
}
}
int GListDepth(GList L)
{
if(!L)
return 1;
if(L->tag==ATOM)
return 0;
int max = 0,dep;
GList p;
for (p = L; p; p = p->ptr.tp)
{
dep = GListDepth(p->ptr.hp);
if(dep>max)
max = dep;
}
return (max + 1);
}