您的位置:首页 > 编程语言 > C语言/C++

用C++实现了一个广义表类

2006-05-12 18:48 633 查看
//---------------------------------------------------------------
/*注:由清华大学出版社出版出版,殷人昆等人编著的《数据结构 C++描述》
* 一书中,对广义表的定义是比较详细的。但是,该书对广义表的进行的抽象分析
* 以及实现有点差强人意,经过分析,该书对广义表的C++实现有下面几个缺点:
*
* 1:整个类型的定义非常松散,完全没有把数据封装以及对数据的隐藏当一回事
*
* 2:对于GenListNode 几个公开的接口的定义让人根本不能分清楚它们到底是不是成员函数
*
* 3: 广义表GenList的一部分public成员函数返回的是 GenListNode* 类型,
* 而这个函数返回的是函数内部通过申请堆内存获得的指针,这很容易引起memory leak
* 这种作法根本不能在公用接口中出现,看到这样的做法让我半天无语中……
*
* 4:对于链表这类指针元素比较多的类型结构,如果不想提供拷贝构造和赋值函数,
* 最好把它们声明为私有的……,这会省去很多麻烦
*
* 5:貌似还有一些无伤大雅的错误……………… 原书setNext() 和 setTail() 两个函数一定有问题
*
* 6:撇开上面的第3点不谈,书上提供的GenList的ADT以及实现对广义表结构以及算法的理解
* 还是有用的,但是这样做似乎对不起“用C++描述”这几个字。如果这样,我还不如去买
* 一本比较好的《数据结构,精辟地用C描述》一本书来看
*
*
* 实现该类的目的不是为了完美的解释一个广义表结构,相反,利用数据隐藏等潜规则
* GenList的实现会稍微复杂一些,如果想了解广义表的Data structure,最好去看
* 下用C实现的GenList,那样会更容易理解
*
* OK,试试能不能自己实现一个完全用C++实现的的GenList
*
* Author: Jacky Wu
* 2006-5-8
*/

/*
* **************************************************************
* Copyright (c) 2006
* Jacky Wu
* You can use these source code for any purpose.
* And It is provided "as is" without express or implied warranty.
*
* 你可以任意使用该代码,但是本人不对代码的安全性做任何担保!!!
*
* 由于大部分代码是出于学习目的实现的,只是让它“可以使用",
* 并没有经过安全性,高负荷运行强度等测试,我必须对这些代码做一个声明:
* !!!!
* 免责声明:
* 对于使用在本blog上提供的任意“形式”(包括测试,类的实现,
* 系统的分析 等等只要是代码片断)的代码造成系统不稳定或者
* 由于此造成的经济、声誉上的损失,或者是人身伤害等任何损失,本人不负任何法律责任
* **************************************************************
*/

////////////////////////////////////////////////////
//文件 GenList.h
///////////////////////////////////////////////////
#ifndef GENLIST_H_
#define GENLIST_H_

#include <string>
#include <iostream>

///////////////////////////////////////////////////////////
//广义表 General List
//
//广义表结点中元素类型还是根据书上定义的几种类型
//0:HEAD 1:INT 2:CH 3:LIST

enum EleCate { HEAD=0, INT, CH, LIST }; //ElementCategory 元素类型种类

class GenList;
class GenListNode;

/*********************************************************
* class NodeElement
*节点中元素的类型,是用union来保存的,这里提供了一系列SET,GET操作函数
*这样可以减少程序中因误取union类型出现错误
**********************************************************/
class NodeElement {
public: //针对不同联合存储类型进行构造
NodeElement();
NodeElement( int iinfo);
NodeElement( char chinfo);
NodeElement( GenListNode* link);

public: //提供一些能够正确存取节点中 m_unValue 元素的接口
//每次只能正确的使用一个接口获取信息

EleCate GetTypeID() const; //获得元素类型信息

void SetRef(int rf);
int GetRef() const;

void SetIntInfo(int iinfo);
int GetIntInfo() const;

void SetCharInfo(char chinfo);
char GetCharInfo() const;

void SetList(GenListNode* link);
GenListNode* GetList() const;

void SetElement( const NodeElement& node); //根据node值设定
public:
NodeElement& operator=( const NodeElement& ne);
bool operator==(const NodeElement& ne);
protected:
void SetTypeID(EleCate ID); //设定元素ID,只能提供protected访问

private:
union EleValue
{
int ref; //m_iType == HEAD,存放表头的引用计数
int intinfo; //m_iType == INT, 存放整数值
char charinfo; //m_iType == CH, 存放字符
GenListNode* hlink; //m_iType == LIST, 存放下层子表的头的指针
};

private:
EleCate m_iType; //标记存放的元素种类
EleValue m_unValue; //元素值
};

/************************************************************************
* class GenListNode
*由于结点保存的数据类型比较复杂,在这里必须将结点类单独定义
*这种定义方式是以破坏广义表的结构封装性为代价的,
*但是获得了良好的代码复杂度,综合考虑是可以使用的
*************************************************************************/
class GenListNode {
friend class GenList;
public:
GenListNode();
GenListNode( int iinfo);
GenListNode( char chinfo);
GenListNode( GenListNode* link);

public: //提供操作该节点的接口
const NodeElement& GetInfo() const; //获得该结点的信息
void SetInfo(const NodeElement& node); //设置结点内容,这里可以发生隐式类型转换

private:
NodeElement m_NodeEle; //节点中的元素
GenListNode* m_pLink; //指向同层下一个结点的指针

}; //GenListNode over

class GenList {
public:
GenList();
GenList( const GenListNode* glnode); //用glnode节点作为第一个节点索引的表生成新表
~GenList();

//如果考虑到类的完整性,最好为下面几个函数同时提供 () const函数,
//实现代码是相似的,只是函数声明不同,这里就简略了

NodeElement& Head(); //返回广义表表头元素的引用(非节点)
GenList Tail(); //返回该广义表的尾表
NodeElement& First(); //返回广义表第一个元素的引用
NodeElement& Next(const GenListNode* node); //返回node节点直接后继元素的引用(不推荐进行这样的操作) //

GenList& Push( const NodeElement& x); //将x值作为第一个节点的元素值插入到广义表中
GenList& SetHead( const NodeElement& x); //将第一个元素值设置为x
GenList& SetNext( const GenListNode* node, const NodeElement& x); //将node节点后一个节点的元素值设置为x
GenList& SetTail( GenList& list); //将list作为新表的表尾,list 被删除
GenList& SetTail( const GenList& list); //将list元素复制为表尾,list不发生变化

GenList& Copy( const GenList& list); //复制一个广义表
int Depth() const ; //计算一个广义表深度
bool operator==(const GenList& list) const; //判断两个表是否相等
GenList& Delete(const NodeElement& x); //删除表中含所有值为X的原子节点

GenList& CreateList(const std::string& exp); //由exp描述的表达式来生成一个表
void CreatList(); //由输入流新建一个表格

friend std::ostream& operator<<(std::ostream& out, const GenList& list);
private:
GenListNode* copy(const GenListNode* nd); //全模式递归复制广义表(包括对递归,共享表的识别复制)
//递归复制子表,这个函数返回堆上指针,
int depth(const GenListNode* list) const; //递归计算表的深度 //注意,此函数只能作为该类私有使用,不得剥离作为它用
GenListNode* scopy(const GenListNode* nd); //单一模式广义表的拷贝 ,表中无递归或者共享结构
void remove(GenListNode* nd); //删除nd节点后所有的表节点
bool IsEqual(const GenListNode* p, const GenListNode* q) const;
void delvalue(GenListNode* list, const NodeElement& x); //删除表中含所有值为X的原子节点的递归函数

GenListNode* creatlist(std::istream& in);

void output(std::ostream& out, const GenListNode* node) const;//用于输出流的广义表递归提取函数

private:
GenListNode* m_phead; //表头指针
};

#endif /*GENLIST_H_*/

////////////////////////////////////////////////////
//文件 GenList.cpp
///////////////////////////////////////////////////

#include "GenList.h"

#include <cassert>
#include <stdexcept>
#include <iostream>
using namespace std;

//NodeElement constructs
NodeElement::NodeElement() : m_iType(HEAD) //default is a head node
{
m_unValue.ref = 1;
}

NodeElement::NodeElement( int iinfo) : m_iType(INT)
{
m_unValue.intinfo = iinfo;
}

NodeElement::NodeElement( char chinfo) : m_iType(CH)
{
m_unValue.charinfo = chinfo;
}

NodeElement::NodeElement( GenListNode* link) : m_iType(LIST)
{
m_unValue.hlink = link;
}

//*********************************************************
void NodeElement::SetTypeID(EleCate ID) //this is protected function
{
m_iType = ID;
}

EleCate NodeElement::GetTypeID() const
{
return m_iType;
}

void NodeElement::SetRef(int rf)
{
SetTypeID(HEAD);
m_unValue.ref = rf;
}

int NodeElement::GetRef() const
{
assert( m_iType == HEAD);
return m_unValue.ref;
}

void NodeElement::SetIntInfo(int iinfo)
{
SetTypeID(INT);
m_unValue.intinfo = iinfo;
}

int NodeElement::GetIntInfo() const
{
assert( m_iType == INT);
return m_unValue.intinfo;
}

void NodeElement::SetCharInfo(char chinfo)
{
SetTypeID(CH);
m_unValue.charinfo = chinfo;
}

char NodeElement::GetCharInfo() const
{
assert( m_iType == CH);
return m_unValue.charinfo;
}

void NodeElement::SetList(GenListNode* link)
{
SetTypeID(LIST);
m_unValue.hlink = link;
}

GenListNode* NodeElement::GetList() const
{
assert( m_iType == LIST);
return m_unValue.hlink;
}

void NodeElement::SetElement( const NodeElement& node)
{
switch(node.m_iType)
{
case HEAD :
this->SetRef(node.m_unValue.ref);
break;
case INT :
this->SetIntInfo(node.m_unValue.intinfo);
break;
case CH :
this->SetCharInfo(node.m_unValue.charinfo);
break;
case LIST :
this->SetList(node.m_unValue.hlink);
break;
}
}

NodeElement& NodeElement::operator=( const NodeElement& ne)
{
m_iType = ne.m_iType;
m_unValue = ne.m_unValue;
return *this;
}

bool NodeElement::operator==(const NodeElement& ne)
{
//针对不同的数据类型进行比较
switch(ne.m_iType)
{
case HEAD :
if(m_iType == HEAD && m_unValue.ref == ne.GetRef())
{
return true;
}
else return false;
break;

case INT :
if(m_iType == INT && m_unValue.intinfo == ne.GetIntInfo())
{
return true;
}
else return false;
break;

case CH :
if(m_iType == CH && m_unValue.charinfo == ne.GetCharInfo())
{
return true;
}
else return false;
break;

case LIST :
if(m_iType == LIST && m_unValue.hlink == ne.GetList())
{
return true;
}
else return false;
break;
default:
return false;
break;
}
}

//*********************************************************
//

//*********************************************************
//GenListNode:
//

//constructors!!
GenListNode::GenListNode() : m_pLink(0) {} //默认构造定义了一个表头节点

GenListNode::GenListNode( int iinfo) : m_NodeEle(iinfo), m_pLink(0) {}

GenListNode::GenListNode( char chinfo) : m_NodeEle(chinfo), m_pLink(0) {}

GenListNode::GenListNode( GenListNode* link) : m_NodeEle(link), m_pLink(0) {}

const NodeElement& GenListNode::GetInfo() const
{
return this->m_NodeEle;
}

void GenListNode::SetInfo(const NodeElement& node)
{
m_NodeEle.SetElement(node);
}

//*********************************************************
//

//*********************************************************
//GenList
//

GenList::GenList()
{
m_phead = new GenListNode; //定义了一个表头节点
assert( m_phead );
}

GenList::~GenList()
{
remove(m_phead);
}

NodeElement& GenList::Head() //表头元素的引用,可以修改元素内部值
{
return m_phead->m_NodeEle;
}

/*这里返回的是一个表尾的拷贝
由于广仪表结构的特殊性(包含指针域),必须为这样的函数提供
GenList(const GenList&) 和 operator=(const GenList& )
这两个非常重要的函数,此类没有具体定义,但是只要在这两个函数中调用
GenList& GenList::Copy(const GenList& list) 就可以很容易实现
*/

GenList GenList::Tail()
{

GenList glist;
if(m_phead->m_pLink)
{
glist.m_phead->m_pLink = this->copy(m_phead->m_pLink->m_pLink); //拷贝尾表中所有的节点
}

return glist; //此句将引发两个过程
//1:对于外部过程,可能会调用 GenList(const GenList&) 或者operator=(const GenList& )
//2:对于内部过程,一定会调用 glist.~GenList();
//这样做不会引起memory leak,且有良好的封装但是
//性能就值得担忧了,如果由于这个函数引起系统性能低下,
//可以考虑是不是要舍弃类的数据隐藏。
}

NodeElement& GenList::First() //表中第一个元素的引用,可以修改元素内部值
{
if(!m_phead->m_pLink)
{
throw out_of_range("FirstElementNotExist");
}
return m_phead->m_pLink->m_NodeEle;
}

NodeElement& GenList::Next(const GenListNode* node)
{
if(!node->m_pLink)
{
throw out_of_range("NextElementNotExist");
}
return node->m_pLink->m_NodeEle;

}

GenList& GenList::Push( const NodeElement& x)
{
GenListNode* pnode = new GenListNode;
assert(pnode);
pnode->SetInfo(x);
pnode->m_pLink = m_phead->m_pLink;
m_phead->m_pLink = pnode;
return *this;
}

GenList& GenList::SetHead( const NodeElement& x)
{
GenListNode* pnode = m_phead->m_pLink;
if(!pnode) //无元素表,主动生成第一个元素
{
pnode = new GenListNode;
assert(pnode);
m_phead->m_pLink = pnode;
pnode->m_pLink = 0;
}
pnode->SetInfo(x);
return *this;
}

GenList& GenList::SetNext( const GenListNode* node, const NodeElement& x)
{
if(node && node->m_pLink)
{
node->m_pLink->m_NodeEle.SetElement(x); //设定节点元素值为x
}
return *this;
}

GenList& GenList::SetTail( GenList& list)
{
GenListNode* tmp;
tmp = m_phead->m_pLink->m_pLink;
m_phead->m_pLink->m_pLink = list.m_phead->m_pLink;
delete list.m_phead; list.m_phead = 0; //使list失去对原来表的控制,阻止其进行正常的析构操作
this->remove(tmp); //删除原表的表尾
return *this;
}

GenList& GenList::SetTail(const GenList& list)
{
GenListNode* tmp;
tmp = m_phead->m_pLink->m_pLink;
m_phead->m_pLink->m_pLink = this->copy(list.m_phead->m_pLink); //递归复制
this->remove(tmp); //删除原表的表尾
return *this;
}

GenList& GenList::Copy(const GenList& list)
{
remove(m_phead->m_pLink);
m_phead->m_pLink = copy(list.m_phead->m_pLink);
return *this;
}

GenListNode* GenList::copy(const GenListNode* nd)
{
GenListNode* pnode = 0;
if(nd)
{
pnode = new GenListNode;
if(nd->GetInfo().GetTypeID() == LIST) //节点中存储的是子表
{
pnode->m_NodeEle.SetList( copy(nd->m_NodeEle.GetList()));
}
else
{
pnode->m_NodeEle.SetElement(nd->m_NodeEle);
}
pnode->m_pLink = copy(nd->m_pLink);
}
return pnode;
}

//
int GenList::Depth() const
{
return depth(m_phead);
}

int GenList::depth(const GenListNode* list ) const
{
if(!list->m_pLink) return 1; //空表深度为1
GenListNode *tmp = list->m_pLink;
int m = 0;
while(tmp)
{
if(tmp->m_NodeEle.GetTypeID() == LIST)
{
int n = depth(tmp->m_NodeEle.GetList());
if(m<n) m = n;
}
tmp = tmp->m_pLink;
}
return m+1;
}

//
bool GenList::operator==(const GenList& list) const
{
return IsEqual(m_phead, list.m_phead);
}

bool GenList::IsEqual(const GenListNode* p, const GenListNode* q) const
{
if(!p->m_pLink && !q->m_pLink)
{
//p,q都索引的是空表
return true;
}

bool btest = false;
if(p->m_pLink != 0 && q->m_pLink !=0
&& p->m_pLink->m_NodeEle.GetTypeID()
== q->m_pLink->m_NodeEle.GetTypeID())
{
if( p->m_pLink->m_NodeEle.GetTypeID() == INT)
{
if(p->m_pLink->m_NodeEle.GetIntInfo() == q->m_pLink->m_NodeEle.GetIntInfo())
{
btest = true;
}
else btest = false;
}
else if(p->m_pLink->m_NodeEle.GetTypeID() == CH)
{
if(p->m_pLink->m_NodeEle.GetCharInfo() == q->m_pLink->m_NodeEle.GetCharInfo())
{
btest = true;
}
else btest = false;
}
//扫描到的是一个表头索引,进入子表进行索引
else btest = IsEqual(p->m_pLink->m_NodeEle.GetList(), q->m_pLink->m_NodeEle.GetList());

//节点中的元素是相等的,比较下面一个节点
if(btest) return IsEqual(p->m_pLink, q->m_pLink);
}
return false;
}

//广义表删除操作,等同于析构
void GenList::remove(GenListNode* nd) //nd must be a head node
{
if(nd) //delete nd if it is using
{
assert(nd->m_NodeEle.GetTypeID() == HEAD);
nd->m_NodeEle.SetRef(nd->m_NodeEle.GetRef()-1); //detach reference count
if(!nd->m_NodeEle.GetRef())
{
//表头已经不再作为任何子表
GenListNode* ptmp = nd;

while(ptmp != 0)
{
nd = nd->m_pLink;
if( nd && nd->m_NodeEle.GetTypeID() == LIST )
{
//该节点为子表索引,则递归删除子表
remove(nd->m_NodeEle.GetList());
}
delete ptmp;
ptmp = nd;
}
}
}
}

//删除广义表中的所有的指定的元素
GenList& GenList::Delete(const NodeElement& x)
{
delvalue(m_phead, x);
return *this;
}

//删除元素的递归函数
void GenList::delvalue( GenListNode* list, const NodeElement& x)
{
//list must be a headnode
//x必须是原子节点表示的类型
assert(x.GetTypeID() == INT || x.GetTypeID() == CH);
if(list->m_pLink != 0)
{
GenListNode* ptmp = list->m_pLink;
GenListNode* q = list;
while(ptmp)
{
if(ptmp->m_NodeEle == x) //直接调用 NodeElement::operator==()
{
//如果是原子节点,则进行比较,相等则删除
q->m_pLink = ptmp->m_pLink;
delete ptmp;
}
else if(ptmp->m_NodeEle.GetTypeID()==LIST)
{
//发现子表,对子表进行递归删除操作
delvalue(ptmp->m_NodeEle.GetList(), x);
}
q = ptmp;
ptmp = ptmp->m_pLink;
}
}
}

void GenList::CreatList()
{

cout << " Please Input a List expression/n As this form: /n 21,5,(2,3,(42,p,x,61,n,(x,f,s,6),25,x)),p,x# " << endl;
//由输入流来建立一个新表的公用接口
//必须先删除原表
remove(m_phead->m_pLink);

//输入格式为:
//21,5,(2,3,(42,p,x,61,n,(x,f,s,6),25,x)),p,x#
//其中字符可以相连,数字为整型数,#为输入流终结控制符,
//最外层表的括号得省
m_phead->m_pLink = creatlist(cin); //参数是输入流
}

GenListNode* GenList::creatlist(istream& in)
{
//对输入流进行处理,生成广仪表
char ch;
while(in.get(ch), ch !='#')
{
if(ch != ',')
{
if(ch == '(') //ch为左括号,动作:生成一个原子节点,生成一个表头索引,递归扫描流
{
GenListNode* nd = new GenListNode;
GenListNode* lhead = new GenListNode;

nd->m_NodeEle.SetList(lhead); //
lhead->m_NodeEle.SetRef(1);
lhead->m_pLink = creatlist(in); //递归生成子表

nd->m_pLink = creatlist(in); //在生成子表完成后继续递归生成主干表

return nd;
}
else if(ch == ')')
{
//ch为右括号,表递归结束,
return 0;
}
else //ch表示字符或者是一个数字
{
if(isdigit(ch)) //ch为数字,则生成一个存储数字的原子节点
{
in.putback(ch); //ch回推给流
GenListNode* nd = new GenListNode;
int x;
in >> x; //从流中获取x值
nd->m_NodeEle.SetIntInfo(x);
nd->m_pLink = creatlist(in); //递归流

return nd;
}
else
{
//ch就表示一个字符
GenListNode* nd = new GenListNode;
nd->m_NodeEle.SetCharInfo(ch);
nd->m_pLink = creatlist(in); //递归流

return nd;
}
}
}
} // end while
//运行到此表示 ch == '#',输入流结束
return 0; //终结指针
}

void GenList::output(std::ostream& out,const GenListNode* node) const
{
if(!node)
{
return ;
}
switch(node->m_NodeEle.GetTypeID())
{
case HEAD: //当前节点为头节点
output(out,node->m_pLink);
break;

case INT:
out << node->m_NodeEle.GetIntInfo();
if(node->m_pLink)
{
out << ",";
}
output(out, node->m_pLink);

break;
case CH:
out << node->m_NodeEle.GetCharInfo();
if(node->m_pLink)
{
out << ",";
}
output(out, node->m_pLink);
break;

case LIST:
out << "(";
output(out, node->m_NodeEle.GetList());
out <<")";
if(node->m_pLink)
{
out << ",";
}
output(out, node->m_pLink);
break;
}
}

std::ostream& operator<<(std::ostream& out, const GenList& list)
{
out << "The GenList is: /n";
list.output(out,list.m_phead);
return out;
}

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: