广义表是一种允许表中有表的非线性结构,在实现广义表的基本操作时需注意以下几个问题:
1.就如下图来看,Head为表的头结点,它存储着指向广义表或其子表的地址;Value是广义表的一个值节点;那么Sub的作用是什么呢?又为什么不把子表的Head直接放入Sub里呢?原因在于,我们可以把Sub当成一个子表项,它和value是同一层次的(都可看成是第一层的),通过它的next找到下一个值节点或另一个表项,如果将子表的Head放在Sub位置,那么就无法进行找寻第一层的下一个节点了;
2.由于广义表中可能包含值也可能是子表,所以在创建广义表节点时用一个联合体将数据项和子表节点封装起来,联合体共用一块内存,在这里可以提高效率;
3.广义表的深度,它是这样理解的:例如E((a,(a,b),((a,b),c))),求其深度
深度是子表最大的嵌套次数,数据项算0,子表算1,从后看:((a,b),c)))到a或者b有四次嵌套,因此E的深度为4;
再或者看下图,D=(a,b,(c,d),(e,(f),h)),结构图画了三层,就代表其深度为3.
4.由于广义表的定义是递归的,所以在函数实现的时候肯定要用到递归,但是呢,类的成员函数一般是不能递归的,所以有得重新封装其他函数,辅助实现构造,拷贝构造,析构,赋值,求深度等等。
下面是一些常见广义表的存储结构:
generalist.h
#pragma once
#include<iostream>
#include<assert.h>
using namespace std;
enum Type
{
HEAD_TYPE, //头结点类型
VALUE_TYPE, //值类型
SUB_TYPE //子表类型
};
struct GeneralistNode
{
GeneralistNode(const char& value='0',const Type& type=HEAD_TYPE)
:_type(type)
,_next(NULL)
/*,_value(value)*/
,_pSub(NULL)
{}
Type _type;
GeneralistNode* _next; //指向下一个表项
union //子表中的值和指向子表的指针共用同一块空间
{
char _value;
GeneralistNode* _pSub; //指向子表的指针
};
};
class Generalist
{
public:
Generalist()
:_head(NULL)
{}
Generalist(char* str)
{
_head=_CreateList(str);
}
Generalist(const Generalist& g)
{
_head=_CopyList(g._head);
}
Generalist& operator=(Generalist g)
{
std::swap(_head,g._head);
return *this;
}
~Generalist()
{
_DelGeneralist(_head);
_head=NULL;
}
size_t Size()
{
return _Size(_head);
}
size_t Depth()
{
return _Depth(_head);
}
void Print()
{
return _Print(_head);
}
protected:
void _Print(GeneralistNode* head)
{
if(NULL==head)
{
return ;
}
GeneralistNode* cur=head;
while(cur)
{
if(cur->_type==VALUE_TYPE)
{
cout<<cur->_value;
if(cur->_next!=NULL)
{
cout<<',';
}
cur=cur->_next;
}
else if(cur->_type==SUB_TYPE)
{
_Print(cur->_pSub);
if(cur->_next!=NULL)
{
cout<<',';
}
cur=cur->_next;
}
else
{
cout<<'(';
cur=cur->_next;
}
}
cout<<')';
}
size_t _Depth(GeneralistNode* head) //计算广义表的深度
{
int maxdepth=1;
int curdepth=1;
GeneralistNode* cur=head;
while(cur)
{
if(cur->_type==SUB_TYPE)
{
curdepth+=_Depth(cur->_pSub);
if(curdepth>maxdepth)
{
maxdepth=curdepth;
}
curdepth=1;
}
cur=cur->_next;
}
return maxdepth;
}
size_t _Size(GeneralistNode* head)
{
size_t count=0;
GeneralistNode* cur=head;
while(cur)
{
if(cur->_type==VALUE_TYPE)
{
++count;
}
else if(cur->_type==SUB_TYPE)
{
count+=_Size(cur->_pSub);
}
cur=cur->_next;
}
return count;
}
void _DelGeneralist(GeneralistNode* head)
{
if(NULL==head)
{
return ;
}
GeneralistNode* cur=head;
GeneralistNode* del=head;
while(cur)
{
del=cur;
/*if(cur->_type==VALUE_TYPE)
{
delete del;
}*/
if(cur->_type==SUB_TYPE)
{
_DelGeneralist(cur->_pSub);
}
cur=cur->_next;
delete del;
}
}
GeneralistNode* _CopyList(GeneralistNode* head)
{
//pHead,pcur均为拷贝之后的结点
//head,cur为拷贝前已有对象的结点
GeneralistNode* pHead=new GeneralistNode(HEAD_TYPE);
GeneralistNode* cur=head;
GeneralistNode* pcur=pHead;
while(cur)
{
if(cur->_type==VALUE_TYPE)
{
pcur->_next=new GeneralistNode(cur->_value,VALUE_TYPE);
pcur=pcur->_next;
pcur->_value=cur->_value;
cur=cur->_next;
}
else if(cur->_type==SUB_TYPE)
{
pcur->_next=new GeneralistNode(SUB_TYPE);
pcur=pcur->_next;
pcur->_type=cur->_type;
pcur->_pSub=_CopyList(cur->_pSub); //递归拷贝子表项
cur=cur->_next;
}
else
{
cur=cur->_next;
}
}
return pHead;
}
GeneralistNode* _CreateList(char* &str)
{
assert(*str=='(');
++str;
GeneralistNode* head= new GeneralistNode(HEAD_TYPE);
GeneralistNode* cur=head;
while(*str)
{
if(IsLegalValue(*str)) //若合法,则创建一个值节点
{
cur->_next=new GeneralistNode(*str,VALUE_TYPE);
cur=cur->_next;
cur->_value=*str;
++str;
cur->_type=VALUE_TYPE;
}
else if(*str=='(') //有子表项
{
cur->_next=new GeneralistNode(SUB_TYPE);
cur=cur->_next;
cur->_pSub=_CreateList(str); //使用递归创建子表
++str;
cur->_type=SUB_TYPE;
}
else if(*str==')') //广义表或子表结束
{
++str;
return head;
}
else //逗号或空格等类型的直接跳过
{
++str;
}
}
return head;
}
bool IsLegalValue(char str)
{
if((str >= '0'&& str <= '9') ||(str>='a'&& str<='z')||(str>='A'&&str<='Z'))
{
return true;
}
else
{
return false;
}
}
private:
GeneralistNode* _head;
};
test.cpp
#include"generalist.h"
void test()
{
char str[]="((a,(a,b),((a,b),c)))";
Generalist g1(str);
g1.Print();
cout<<endl;
Generalist g2(g1);
g2.Print();
cout<<endl;
Generalist g3;
g3=g1;
g3.Print();
cout<<endl;
cout<<"大小:"<<g1.Size()<<endl; //6
cout<<"深度:"<<g1.Depth()<<endl; //4
}
int main()
{
test();
system("pause");
return 0;
}