[转]广义表

(C版)

#include <stdio.h>
#include <malloc.h>
#define OK 1
#define ERROR -1
#define status int
typedef struct gnode
{
 int tag;
 union
 {
  char atom;
  struct gnode *sublist;
 } val;
 struct gnode *link;
} *Gnode;
Gnode creatglist(char *s)
{//创建广义表
 Gnode h;
 char ch;
 ch=*s;
 s++;
 if(ch!=‘\0‘)          //串未结束判断
 {
  h=(Gnode)malloc(sizeof(Gnode));
  if(!h) printf("存储空间分配失败\n");
  if(ch==‘(‘)
  {
   h->tag=1;
   h->val.sublist=creatglist(s);   //递归创建广义表
  }
  else if(ch==‘)‘)  h=NULL;
  else
  {
   h->tag=0;
   h->val.atom=ch;
  }
 }
 else h=NULL;
 ch=*s;
 s++;
 if(h!=NULL)
 {
  if(ch==‘,‘)
   h->link=creatglist(s);
  else
   h->link=NULL;
 }
 return h;
}
void output(Gnode h)
{
 if(h!=NULL)
 {
  if(h->tag==1)
  {
   printf("(");
   if(h->val.sublist==NULL)
    printf(" ");
   else
    output(h->val.sublist);
  }
  else
   printf("%c",h->val.atom);
  if(h->tag==1)
   printf(")");
  if(h->link!=NULL)
  {
   printf(",");
   output(h->link);
  }
 }
}
void empty(Gnode h)
{
 if(h->val.sublist==NULL)
  printf("广义表为空\n");
 else
  printf("广义表非空\n");
}
int length(Gnode h)
{
 Gnode p=h;
 int len=0;
 if(p==NULL)
  return len;
 else
  return length(h->link)+1;
}
Gnode copy(Gnode h)
{
 Gnode b;
 if(h==NULL) return NULL;
 b=(Gnode)malloc(sizeof(Gnode));
 b->tag=h->tag;
 if(h->tag==1)
  b->val.sublist=copy(h->val.sublist);
 else
  b->val.atom=h->val.atom;
 b->link=copy(h->link);
 return b;
}
void insert(Gnode &h,char e)
{//把元素e插入广义表h,为其第一个元素
 Gnode p;
 p=(Gnode)malloc(sizeof(Gnode));
 p->tag=0;
 p->val.atom=e;
 p->link=h->val.sublist;
 h->val.sublist=p;
}
int depth(Gnode h)
{//求广义表的深度
 int max=0,dep;
 while(h!=NULL)
 {
  if(h->tag==1)
  {
   dep=depth(h->val.sublist);
   if(dep>max)
    max=dep;
  }
  h=h->link;
 }
 return max+1;
}
void delfirstnode(Gnode &h)
{//删除第一元素并输出其值
 Gnode p,q;
 p=(Gnode)malloc(sizeof(Gnode));
 p=copy(h);
 p->val.sublist->link=NULL;
 printf("广义表的第一元素为:   ");
 output(p->val.sublist);printf("\n");
 q=h->val.sublist;
 h->val.sublist=q->link;
 printf("删除第一元素后,广义表h为:\n");
 output(h);
}
void main()
{
 int len,dep;
 char s[50],elem;
 Gnode h,b;
 scanf("%s",s);

h=creatglist(s);

empty(h);

printf("广义表h为\n");
 output(h);printf("\n");
 
 printf("广义表的长度为:  ");
 len=length(h->val.sublist);
 printf("%d\n",len);

b=copy(h);
 printf("广义表b为:  ");
 output(b);printf("\n");
 insert(b,‘e‘);
 printf("广义表b为:  ");
 output(b);printf("\n");

printf("广义表h的深度为:\n");
 dep=depth(h->val.sublist);
 printf("%d\n",dep);

delfirstnode(b);
}

(C之二)

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#define AtomType char
#define MAXSIZE  1024
#define ElemTag int
#define OK       1
#define ERROR    0

typedef struct GLNode
{
 ElemTag tag;
 union
 {
  AtomType  atom;
  struct GLNode *hp;
 }atom_hp;
    struct GLNode *tp;
}GLNode,*GList;

//功能:分离出广义表中表头部分
//返回:分离后剩下的字符串,不包括逗号
void Disastr(char *s,char *hstr)
{
 int i,j,k,r;
 char rstr[MAXSIZE];
 
 i=j=k=0;
 while(s[i] && (s[i] != ‘,‘ || k))
 {
  if (s[i] == ‘(‘)  {  k++ ; }        // k 作为括号计数器        
  else if (s[i] == ‘)‘) {k--;}
  if (s[i] != ‘,‘ || s[i] == ‘,‘ && k)
  {
   hstr[j] = s[i];
   i++;
   j++;
  }
 }

hstr[j] = ‘/0‘;
 if (s[i] == ‘,‘) {i++;}

r=0;
 while(s[i])                 // 处理剩余的表尾部分
 {
  rstr[r] = s[i];
  r++;
  i++;
 }
 rstr[r] = ‘/0‘;
 strcpy(s,rstr);
}

//功能:根据输入的字符串,建立广义表
//返回:成功则返回建立的广义表的表头,否则,返回NULL
GLNode * GLCreate(char *s)
{
 GLNode *p,*q,*r,*head;
    char substr[MAXSIZE],hstr[MAXSIZE];//rstr[MAXSIZE];
    int len;

len = strlen(s);
    if ( !strcmp(s,"()") || !len)  { head = NULL;}     // (1) 空表情况
 else if (len == 1)                                      // (2) 原子情况
 {
  head = (GLNode *)malloc(sizeof(GLNode));       // 建立一个新结点
  if (!head)  return NULL;     
  head->tag = 0;                                 // 构造原子结点
  head->atom_hp.atom = *s;
  head->tp = NULL;
 }
    else                                                // (3) 子表情况
 {
  head = (GLNode *)malloc(sizeof(GLNode));
  if (!head) return NULL;
  head->tag = 1;
  p = head;
  s++;
  strncpy(substr,s,len-2);                         // 剥去外层的()
  substr[len-2] = ‘/0‘;
  do 
  {
   Disastr(substr,hstr);                        // 分离出表头
   r = GLCreate(hstr);
   p->atom_hp.hp = r;                           // 尾插法建表
   q=p;
   len = strlen(substr);
   if (len > 0)
   {
    p = (GLNode*)malloc(sizeof(GLNode));
    if (!p) return NULL;
    p->tag = 1;
    q->tp=p;
   }
  } while (len > 0);
  q->tp=NULL;
 }
 return head;
}

void DisplayList(GList head)
{
 GLNode *p,*q;
    
 if (!head)  return;
 if (head->tag==0)
 {
  printf("%c",head->atom_hp.atom);
  return;
 }
 printf("(");
 if (head)
 {
  do 
  {
   p = head->atom_hp.hp;
   q = head->tp;
   while (q && p && p->tag == 0)                //  同一层的原子结点
   {
    printf("%c,",p->atom_hp.atom);
    p = q->atom_hp.hp;
    q = q->tp;
   }
   if (p && !p->tag)                           // 最后一个原子结点
   {
    printf("%c",p->atom_hp.atom);
    break;
   }
   else                                        // 子表情况
   {
    if (!p) printf("()");
    else DisplayList(p);
    if (q)  printf(",");
    head = q;
   }
  } while (head);
  printf(")");
 }
}

//功能:取出广义表的表头部分
//返回:成功则返回广义表的表头,否则,返回空或退出
GList GetHead(GList L)
{
 if (!L)  return (NULL);                    // 空表无表头
 if (L->tag == 0)  exit(0);                 // 原子结点不是表
 else return (L->atom_hp.hp);
}

//功能:取出广义表的表尾部分
//返回:成功返回广义表的表尾部分,否则,返回空或者退出
GList GetTail(GList L)
{
 if (!L) return (NULL);
 if (L->tag == 0) exit(0);
 else return (L->tp);
}

//功能:求出广义表的长度
//返回值:广义表的长度
int Length(GList L)
{
 int k=0;
 GLNode *s;

if (!L) return 0;                    // 空表的长度为零
 if (L->tag == 0) exit(0);            // 原子不是表
 s=L;
 while(s)                             // 统计表的最上层的长度
 {
  k++;
  s=s->tp;
 }

return k;
}

//功能:求得广义表的深度
//输入:需求深度的广义表的指针
int Depth(GList L)
{
 int d,max;
 GLNode *s;

if (!L)  return (1);            // 空表的深度为 1
 if (L->tag==0)  return 0;       // 原子的深度为 0
 s=L;
 max=0;
 while (s)                        // 递归求每个子表深度的最大值
 {
  d = Depth(s->atom_hp.hp);
  if (d > max) max = d;
  s = s->tp;
 }
 return (max+1);                  // 表的深度为子表深度加一
}

//功能:统计原子结点的个数
//输入:需统计的广义表指针
int CountAtom(GList L)
{
 int n1,n2;

if (!L) return 0;                   // 空表无原子结点
 if (L->tag==0) return 1;            // 原子结点
 n1 = CountAtom(L->atom_hp.hp);      
 n2 = CountAtom(L->tp);
 return (n1+n2);
}

//功能:完成广义表的复制,将res复制到dest中
//返回:成功返回1,否则,返回0
bool CopyList(GList *dest,GList res)
{
 if (!res) {*dest = NULL;return (OK);}

*dest = (GLNode *)malloc(sizeof(GLNode));
 if (!*dest)  return (ERROR);

(*dest)->tag = res->tag;
 if (res->tag==0)  (*dest)->atom_hp.atom = res->atom_hp.atom;
    else
    {
  CopyList(&(*dest)->atom_hp.hp,res->atom_hp.hp);
  CopyList(&(*dest)->tp,res->tp);
 }
 return (OK);
}

//功能:合并广义表,如果p为空,则申请空间,将q复制到p中
//例如:((a,b),c) 和(a,b)合并之后为:((a,b),c,a,b)
//算法描述:先找到第一个广义表的最后一个结点,将其链到第二个广义表的首元素即可
void Merge(GList *p,GLNode *q)
{
 GLNode *r;

if (!q) return;       //  如果复制的是个空表,返回
 if (!p)               // p为空,申请空间
 {
  *p = (GLNode*)malloc(sizeof(GLNode));
  if (!(*p)) return ;
  (*p)->tag = 1;
 }
 else
 {
  if ((*p)->tag)         
  {
   r=*p;
   while(r->tp) r=r->tp;             // 找到最后一个子表的表尾指针
   if (q->tag) r->tp = q;        // 修改表尾指针
  }
 }
}

//功能:类似二叉树的先序遍历遍历广义表L
//eg:例如(a,(b,(c),d))结果为:a,b,c,d
//算法描述:
//L若为原子结点,显示该数据,递归调用遍历后续元素,也即:write(L->atom_hp.atom);PreOrder(L->tp);
//L是子表结点,递归调用遍历该子表,遍历后续元素,也即:PreOrder(L->atom_hp.tp);PreOrder(L->tp);
void PreOrder(GList L)
{
 if (L)
 {
  if (L->tag==0) printf("%c ",L->atom_hp.atom);   // 打印原子结点
  else  PreOrder(L->atom_hp.hp);                  // 往下遍历,类似二叉树中的左子树

if (L->tp) PreOrder(L->tp);                     // 往右遍历,类似二叉树中的右子树
 }
}

// 判断两个广义表是否相等,相等,返回1,否则,返回0
// 相等的定义:两个广义表具有相同的存储结构,对应的原子结点的数据域也相等
//算法描述:
// 形式:条件
//Equal(p,q) = Equal(p->tp,q->tp) ; p->tag = 0 && q->tag = 0 && p->atom_hp.atom = q->atom_hp.atom
//Equal(p,q) = Equal(p->atom_hp.hp,q->atom_hp.hp) && Equal(p->tp,q->tp) ; p->tag = 1 && q->tag = 1
//Equal(p,q) = false     ; p->tag = 0 && q->tag = 0 p->atom_hp.atom != q->atom_hp.atom 或者 p->tag *p->tag + q->tag*q->tag =1
//Equal(p,q) = false      ; p q 其中之一为NULL
bool Equal(GList p,GList q)
{
 bool flags = true;

if (!p && q) flags = false;
 if (p && !q) flags = false;
    if (p && q)
 {
  if (p->tag == 0 && q->tag == 0 )
  {
   if (p->atom_hp.atom != q->atom_hp.atom) 
    flags = false;
  }
  else if (p->tag == 1 && q->tag == 1)
  {
   flags = Equal(p->atom_hp.hp,q->atom_hp.hp);
  }
  else flags = false;
  if (flags) flags = Equal(p->tp,q->tp);
 }
 return flags;
}

int main()
{
 char s[MAXSIZE],a[MAXSIZE];
 GList head;
    GList L;

printf("please input a string:");
 scanf("%s",s);
 head = GLCreate(s);
 DisplayList(head);
 printf("/n");

printf("The Head is:");
    DisplayList(GetHead(head));
    printf("/n");

printf("The Tail is: ");
 DisplayList(GetTail(head));
 printf("/n");

printf("The Length is %d/n",Length(head));
 printf("The Depth is %d/n",Depth(head));
 printf("The Atom number is %d/n",CountAtom(head));

printf("Copy the List:/n");
    CopyList(&L,head);
 DisplayList(L);
 printf("/n");

printf("Merge the List/n");
 Merge(&L,head);
 DisplayList(L);
 printf("/n");

printf("PreOrder:");
 PreOrder(head);
 printf("/n");

printf("input a string:");
 scanf("%s",a);
 L = GLCreate(a);
 DisplayList(L);
 printf(" Eqaul ");
 DisplayList(head);
 printf(":");
 if (Equal(L,head)) printf("yes!/n");
 else printf("no!/n");
 return 0;
}

(C++)

//---------------------------------------------------------------

/*注:由清华大学出版社出版出版,殷人昆等人编著的《数据结构 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;

}

时间: 2024-11-07 04:23:32

[转]广义表的相关文章

c++数据结构之广义表

最近学习了广义表,我们知道广义表也是一种线性表,而顾名思义广义表就是不止一个表,下面来举个栗子: A=( ) B=(1 , 2,3) C=(1 ,2 ,3, ( a , b ,c) ) D=(1, 2, 3, (a,( b,c),d),4) 以上A,B,C,D都是广义表,只不过深度不一样,也就是括号的对数不一样,A是个特殊的广义表,即空表.B里面有三个元素,C里面有6个元素,包括一个子表(a,b,c),C也同理,只不过多了一层子表.由此可总结为一句话:表里有表 这样看可能不太直观,下面以广义表C

数据结构实践项目——数组和广义表

本文针对 [数据结构基础系列网络课程(5):数组和广义表] 1. 数组的基本概念与存储结构 2. 特殊矩阵的压缩存储 3. 稀疏矩阵的三元组表示 4. 稀疏矩阵的十字链表表示 5. 广义表 6. 广义表的存储结构及基本运算的实现 [项目1 - 猴子选大王(数组版)] 一群猴子,编号是1,2,3 -m,这群猴子(m个)按照1-m的顺序围坐一圈.从第1只开始数,每数到第n个,该猴子就要离开此圈,这样依次下来,最后一只出圈的猴子为大王.输入m和n,输出猴子离开圈子的顺序,从中也可以看出最后为大王是几号

数据结构与算法系列研究四——数组和广义表

稀疏矩阵的十字链表实现和转置 一.数组和广义表的定义 数组的定义1:一个 N 维数组是受 N 组线性关系约束的线性表.           二维数组的逻辑结构可形式地描述为:           2_ARRAY(D,R)              其中 D={aij} | i=0,1,...,b1-1; j=0,1,...,b2-1;aij∈D0}              R={Row,Col}              Row={<aij,ai,j+1>|0<=i<=b1-1;

广义表的实现

/*--------------------------------------------------------------------- 广义表的存储结构 ---------------------------------------------------------------------*/ #include<stdio.h> #include<stdlib.h> typedef char ElemType;//元素类型是字符型 //广义表的存储结构 struct GN

广义表的实现(法二)

#include<iostream> #include<string> using namespace std; enum elemTag {ATOM,LIST}; class GList; class GLnode { private: elemTag Tag; //标志是原子还是子表 0:原子 1:子表 union { char data; //原子结点值域 struct //表结点指针域 { GLnode *hp; GLnode *tp; }ptr; }; friend cl

广义表

其中包括广义表的创建.输出.拷贝构造.赋值运算符重载.析构.有效数据个数以及广义表深度 #pragma once #include<iostream> #include<assert.h> #include<ctype.h> using namespace std; enum Type {  HEAD, VALUE, SUB };//头结点.值.子表 struct GeneralizedNode {  Type _type;  //广义表结点类型  Generalize

数据结构之广义表

#include<stdio.h> //广义表的头尾链表存储结构 typedef int AtomType; typedef enum NodeType{ATOM,LIST}ElemTag;//ATOM表示原子结点,LIST表示表节点 typedef struct GLNode{ ElemTag tag; union{ AtomType atom; struct List{ struct GLNode* hp,*tp; } htp; }atom_htp; }GLNode,*GList; //求

数据结构——广义表

定义 Python中的list就是一种广义表,使用起来非常方便.广义表的特点就是能够存储不同类型的元素,也支持嵌套使用,即表中还有表.关于广义表的定义还有几本操作归纳如下: ADT Linear List: 元素组成: 能存储不同元素类型的表结构叫做广义表,支持嵌套操作. 基本操作: InitGList() 创建一个空表 DestoryGList() 销毁一个表 GListLength()  获取表的长度 GListDepth()  获取表的深度 PrintList() 遍历一次表 Insert

33. 蛤蟆的数据结构笔记之三十三广义表实现二

33. 蛤蟆的数据结构笔记之三十三广义表实现二 本篇名言:" 希望是附丽于存在的,有存在,便有希望,有希望,便是光明.--鲁迅" 我们继续来看下广义表的其他代码实现.代码均来自网络,解释来自蛤蟆,均亲测可行. 欢迎转载,转载请标明出处: 1.  广义表实现二 1.1         main 创建两个链表的指针head和L. 输入一个字符串,调用GLCreate函数创建广义表.显示,获取头表,尾表,输出长度,深度,原子个数,复制列表,Merge列表,遍历,比较广义表操作. 如下图1:

数据结构之---C语言实现广义表头尾链表存储表示

//广义表的头尾链表存储表示 //杨鑫 #include <stdio.h> #include <malloc.h> #include <stdlib.h> #include <string.h> #define MAXSTRLEN 40 ) typedef char SString[MAXSTRLEN+1]; typedef char AtomType; // 定义原子类型为字符型 typedef enum{ ATOM, LIST // ATOM==0:原