广义表是一种能嵌套自身的数据集合,即某个元素本身又可能是一个小的广义表。
实现广义表的过程中,我发现数据结构设计倒不难,难在如何表现、如何解析上。
最简单的表现形式就是带括号的字符串,比如(A,B,(C,D))这种。
那么(, B)这种合不合法呢?对于(A,B))这种明显不合法的输入,又如何检测出来呢?
为此还专门去看了下正则表达式这玩意。
最后我意识到,首先要给出合法的定义就是个很严谨的事,需要考虑非常周全。
于是,索性干脆不在字符串解析方面投入太多精力,毕竟原始目的不在此,主要意图还是掌握数据结构,顺便练习函数的嵌套调用。
这里假设输入的字符串都是常规“明显合法”类型,具体规则就不多精确描述了。
代码如下:
/*
2014.6.9
广义表的简单实现
*/
#include <iostream>
#include <string>
using std::cin;
using std::cout;
using std::endl;
using std::string;
enum TYPE{ATOM, LIST};
struct node; //嵌套定义时需提前申明
struct lists
{
node *hp;
node *tp;
};
struct node
{
TYPE flag;
union
{
char data;
lists list;
};
};
class glist
{
private:
node *head;
void Create(string src, node *&pnode);
void BraketsWipeOff(string &src);
void ShowOneNode(node *pnode);
void DeleteOneNode(node *pnode);
public:
glist(string src);
~glist();
void Show();
//int GetLength(); //略
//int GetDepth(); //略
};
glist::glist(string src)
{
//解析字符串并建立存储结构
Create(src, head);
}
void glist::Create(string src, node *&pnode)
{
pnode = new node;
if ("()" == src) //空表
{
pnode->flag = LIST;
pnode->list.hp = NULL;
pnode->list.tp = NULL;
}
else if (1 == src.size()) //单字符,原子元素
{
pnode->flag = ATOM;
pnode->data = src[0];
}
else //子表
{
//定义表头表尾,开辟节点空间由函数嵌套调用时处理
node *headnode = NULL;
node *tailnode = NULL;
//若有括号,脱掉外层括号
BraketsWipeOff(src);
//分离出表头、表尾字符串
string strhead;
string strtail;
string::size_type pos;
if (src[0] != '(')
{
pos = src.find(',');
strhead = src.substr(0, pos);
strtail = src.substr(pos + 1);
}
else //注意不能单纯根据第一个逗号分离头尾,比如(C,D),E时出错
{
int k = 1; //未配对的左括号数
for(pos=1; pos<src.size(); ++pos)
{
if ('(' == src[pos])
{
k++;
}
else if (')' == src[pos])
{
k--;
}
if (0 == k)
{
break;
}
}
strhead = src.substr(0, pos + 1);
strtail = src.substr(pos + 2);
}
//嵌套调用Init处理表头表尾
Create(strhead, headnode);
Create(strtail, tailnode);
//为当前节点赋值
pnode->flag = LIST;
pnode->list.hp = headnode; //注意此处要先创建节点再赋值,因为hp、tp均已变化
pnode->list.tp = tailnode;
}
}
//若有括号,脱掉外层括号
void glist::BraketsWipeOff(string &src)
{
//注意此处不能单纯判断第一个为括号则去除外层括号,比如遇(C,D),E时出错
if (('(' == src[0]) && (')' == src[src.size() - 1]))
{
src = src.substr(1, src.size() - 2);
}
else
{}
}
void glist::DeleteOneNode(node *pnode)
{
if (ATOM == pnode->flag)
{
//原子节点空间由父节点释放
}
else //flag = LIST; 子表
{
if (NULL != pnode->list.hp)
{
DeleteOneNode(pnode->list.hp);
}
else
{}
if (NULL != pnode->list.tp)
{
DeleteOneNode(pnode->list.tp);
}
else
{}
}
delete pnode;
pnode = NULL;
}
glist::~glist()
{
DeleteOneNode(head);
}
//将圆括号改为花括号显示
void glist::ShowOneNode(node *pnode)
{
if (ATOM == pnode->flag)
{
cout<<pnode->data;
}
else //flag = LIST; 子表
{
cout<<'{';
if (NULL != pnode->list.hp)
{
ShowOneNode(pnode->list.hp);
cout<<',';
}
else
{}
if (NULL != pnode->list.tp)
{
ShowOneNode(pnode->list.tp);
}
else
{}
cout<<'}';
}
}
void glist::Show()
{
ShowOneNode(head);
cout<<endl;
}
int main()
{
glist empty("()"); empty.Show();
glist A("A"); A.Show();
glist gen1("(A,B,(C,D),E)"); gen1.Show();
glist gen2("(A,(B,C))"); gen2.Show();
}
/*
运行结果:
{}
A
{A,{B,{{C,D},E}}}
{A,{B,C}}
坑点:
主要是练习函数的嵌套调用,字符串解析方面的工作需细心。
*/