广义表(Generalized List)

1. 广义表的概念

1.1 广义表的定义
  • 广义表(Generalized List,又称列表,或表)是一种非线性的数据结构,是线性表的一种推广。
  • 广义表中放松对表元素的原子限制,容许它们具有其自身结构。即广义表的定义是递归的,因为在表的描述中又用到了表,允许表中有表,这种递归的定义能够很简洁地描述庞大而复杂的结构。
  • 一个广义表LS定义为n(n≥0)个元素a0,a1,a2,...an−1组成的有限序列,记作LS=(a0,a1,a2,...an−1),其中,LS为表名;ai(0≤i≤n-1)是表中元素,它或者是数据元素(称为原子),或者是子表;n是表的长度,即表中元素的个数;表的长度不包括作为分界符的左括号“(”和右括号“)”和表元素之间的分隔符“,”;长度为0的表为空表。
  • 一个广义表如果长度n≥1,则称其第一个表元素a0为广义表的表头(head),而由表中除a0外其他元素组成的表(a1,a2,...an−1)称为广义表的表尾(tail)。
  • 广义表的一些例子及其对应的示例图:
(1)A = (),A是一个空表,表的长度为0,没有表头和表尾。
(2)B = (a,b),B是一个只包括原子的表,称为线性表,表的长度为2,表头是a,表尾是(b)(表尾还是一个表,其表头是b,表尾是空表())。
(3)C = (c,(d,e,f)),C是一个包括一个原子和一个子表的表,表的长度为2,表头是c,表尾是((d,e,f))(表尾还是一个表,其表头是(d,e,f),表尾是空表())。
(4)D = (B,C,A) = ((a,b),(c,(d,e,f)),()),D是一个包括三个子表的表,表的长度为3,表头是B,表尾是(C,A)。
(5)E = (B,D) = ((a,b),(B,C,A)) = ((a,b),((a,b),(c,(d,e,f)),())),E是一个包括两个子表的表,表的长度为2,表头是B,表尾是(D)。
(6)F = (g,F) = (g,(g,(g,(…)))),F是一个包括一个原子和一个子表的表,表的长度为2,表头是g,表尾是(F)(表尾还是一个表,其表头是(F),表尾是空表()),对于表头来说出现了递归。

广义表定义的代码Java 广义表(())_广义表的结点结构

  • 注:广义表()和(())不同,前者是长度为0的空表,对其不能做求表头和表尾的运算;而后者是长度为1的非空表(只不过该表中惟一的一个元素是空表),对其可进行分解,得到的表头和表尾均是空表()。
1.2 广义表的特性
  • 有次序性:各表元素在表中以线性序列排列,每个表元素至多一个直接前驱,一个直接后继,这个次序不能交换(ps:这句话我也不是很懂,为什么不是可以有多个直接后继。)
  • 有长度:表元素个数一定,不能是无限的,可以是空表。
  • 有深度:表元素可以是原表的子表,子表的表元素还可以是子表,……,因此广义表是多层次结构。
  • 可递归:广义表本身可以是自己的子表,一般称具有这种性质的表为递归表。
  • 可共享:广义表可以为其他广义表共享,一般称具有这种性质的表为共享表或再入表。
1.3 广义表的存储表示及结点结构
  • 广义表的存储表示:用链表结构作为广义表的存储表示。
  • 广义表的的结点包括3个部分:标志域(utype),信息域(info),尾指针域(tlink)。
    (1)标志域(utype):用来标明该结点是什么类型的结点。
      当utype=0时,表示该结点是广义表专用的附加头结点;
      当utype=1时,表示该结点是原子节点;
      当utype=2时,表示该结点是子表结点。
    (2)信息域(info):不同类型的结点在这个域中存放的内容不同。
      当utype=0时,该信息域存放引用计数(ref);
      当utype=1时,该信息域存放数据值(value);
      当utype=2时,该信息域存放指向子表表头的指针(hlink)。
    (3)尾指针域(tlink):用于存放一个指针,该指针指向下一个结点的开始存储地址。
      当utype=0时,该指针域存放指向该表表头元素结点的指针;
      当utype≠0时,该指针域存放同一层下一个表结点的地址。
  • 广义表的结点结构示意图:

2. 广义表的实现

2.1 广义表的结点结构定义
  • 文件:GenListNode.h
#ifndef GEN_LIST_NODE_H_


#define GEN_LIST_NODE_H_



#include <iostream>


#include <string>


#include <strstream>


using namespace std;

template <class T>
struct GenListNode              //广义表结点类定义
{
    int utype;                  //标志域,utype={0,1,2}
    GenListNode<T> *tlink;      //尾指针域,tlink
    union                       //信息域,info
    {
        int ref;                //当utype=0时,该信息域存放引用计数(ref)
        T value;                //当utype=1时,该信息域存放数据值(value)
        GenListNode<T> *hlink;  //当utype=2时,该信息域存放指向子表表头的指针(hlink)
    }info;
    //构造函数
    GenListNode():utype(0),tlink(NULL),info.ref(0) { }
    //拷贝构造函数
    GenListNode(GenListNode<T>& RL) { utype = RL.utype; tlink = RL.tlink; info = RL.info; }
};

#endif /* GEN_LIST_NODE_H_ */
2.2 广义表的类定义及其操作的实现
  • 文件:GenList.h
#ifndef GEN_LIST_H_


#define GEN_LIST_H_



#include "GenListNode.h"


template<class T>
class GenList
{
public:
    GenList();      //构造函数
    ~GenList();        //析构函数

public:
    GenListNode<T>* Head();                         //返回表头元素
    GenListNode<T>* First();                        //返回第一个元素
    GenListNode<T>* Next(GenListNode<T>* elem);     //返回表元素elem的直接后继元素
    GenList<T>* Tail();                             //返回表尾元素
    void Copy(const GenList<T>& R);                 //广义表的复制
    int Length();                                   //计算广义表的长度
    int Depth();                                    //计算一个非递归广义表的深度

public:
    template<class T>
    friend istream& operator >> (istream& in, GenList<T>& L);   //输入广义表元素的重载操作>>

private:
    GenListNode<T>* Copy(GenListNode<T>* ls);           //复制一个ls指示的无共享非递归表
    int Length(GenListNode<T>* ls);                     //求由ls指示的广义表的长度
    int Depth(GenListNode<T>* ls);                      //计算由ls指示的非递归表的深度
    bool Equal(GenListNode<T>* s, GenListNode<T>* t);   //判以s和t为表头的两个表是否相等
    void Remove(GenListNode<T> *ls);                    //释放以ls为附加头结点的广义表
    void GreateList(istream& in, GenListNode<T> *& ls); //从输入流对象输入广义表的字符串描述,建立一个带附加头结点的广义表结构

private:
    GenListNode<T> *first;      //广义表头指针
};

//构造函数
template<class T>
GenList<T>::GenList()
: first(new GenListNode<T>)
{
    cout << "$ 执行构造函数" << endl;
}

//析构函数
template<class T>
GenList<T>::~GenList()
{
    cout << "$ 执行析构函数" << endl;
    Remove(first);
}

//返回表头元素
template<class T>
GenListNode<T>* GenList<T>::Head()
{
    return first;
}

//返回第一个元素
template<class T>
GenListNode<T>* GenList<T>::First()
{
    return first->tlink;
}

//返回表元素elem的直接后继元素
template<class T>
GenListNode<T>* GenList<T>::Next(GenListNode<T>* elem)
{
    return elem->tlink;
}

//返回表尾元素
template<class T>
GenList<T>* GenList<T>::Tail()
{
    if (first->tlink == NULL)
    {
        return NULL;
    }

    GenList<T>* lt;
    lt->first->tlink = Copy(first->tlink->tlink);
    return lt;
}

//广义表的复制
template<class T>
void GenList<T>::Copy(const GenList<T>& R)
{
    first = Copy(R.first);
}

//计算广义表的长度
template<class T>
int GenList<T>::Length()
{
    return Length(first);
}

//计算一个非递归广义表的深度
template<class T>
int GenList<T>::Depth()
{
    return Depth(first);
}

//输入广义表元素的重载操作>>
template<class T>
istream& operator >> (istream& in, GenList<T>& L)
{
    return in;
}

//复制一个ls指示的无共享非递归表
template<class T>
GenListNode<T>* GenList<T>::Copy(GenListNode<T>* ls)
{
    GenListNode<T> *q = NULL;
    if (ls != NULL)
    {
        q = new GenListNode<T>;     //处理当前的结点q
        q->utype = ls->utype;       //复制结点类型
        switch (ls->utype)          //根据utype传送信息
        {
            case 0:
            {
                q->info.ref = ls->info.ref;             //附加头结点
                break;
            }
            case 1:
            {
                q->info.value = ls->info.value;         //原子结点
                break;
            }
            case 2:
            {
                q->info.hlink = Copy(ls->info.hlink);   //表结点
                break;
            }
            default:
            {
                break;
            }
        }
        q->tlink = Copy(ls->tlink); //处理同一层下一结点为头的表
    }
    return q;
}

//求由ls指示的广义表的长度
template<class T>
int GenList<T>::Length(GenListNode<T>* ls)
{
    if (ls != NULL)
    {
        return 1 + Length(ls->tlink);
    }
    else
    {
        return 0;
    }
}

//计算由ls指示的非递归表的深度
template<class T>
int GenList<T>::Depth(GenListNode<T>* ls)
{
    if (ls->tlink == NULL)
    {
        return 1;
    }
    GenListNode<T> *temp = ls->tlink;
    int m = 0;
    int n = 0;
    while (temp != NULL)
    {
        if (temp->utype == 2)
        {
            n = Depth(temp->info.hlink);
            if (m < n)
            {
                m = n;
            }
        }
        temp = temp->tlink;
    }
    return m + 1;
}

//判以s和t为表头的两个表是否相等
template<class T>
bool GenList<T>::Equal(GenListNode<T>* s, GenListNode<T>* t)
{
    int x = 0;
    if ((s->tlink == NULL) && (t->tlink == NULL))
    {
        return true;
    }
    if ((s->tlink != NULL) && (t->tlink != NULL) && (s->tlink->utype == t->tlink->utype))
    {
        if (s->tlink->utype == 1)
        {
            x = (s->tlink->info.value == t->tlink->info.value) ? 1 : 0;
        }
        else
        {
            x = Equal(s->tlink->info.hlink, t->tlink->info.hlink);
        }
        if (x == 1)
        {
            return Equal(s->tlink, t->tlink);
        }
    }
    return false;
}

//释放以ls为附加头结点的广义表
template<class T>
void GenList<T>::Remove(GenListNode<T> *ls)
{
    ls->info.ref--; //附加头结点的引用计数减1
    if (ls->info.ref >= 0)  //如果减到0
    {
        GenListNode<T> *q;
        while (ls->tlink != NULL)   //横扫表顶层
        {
            q = ls->tlink;          //到第一个结点
            if (q->utype == 2)      //递归删除子表
            {
                Remove(q->info.hlink);
                if (q->info.hlink->info.ref <= 0)
                {
                    delete q->info.hlink;   //删除子表附加头结点
                }
            }
            ls->tlink = q->tlink;
            delete q;
        }
    }
}

//从输入流对象输入广义表的字符串描述,建立一个带附加头结点的广义表结构
template<class T>
void GenList<T>::GreateList(istream& in, GenListNode<T> *& ls)
{

}


#endif /* GEN_LIST_H_ */
2.3 主函数(main函数)的实现
  • 文件:main.cpp
#include "GenList.h"


int main()
{
    system("pause");
    return 0;
}

参考文献:
[1]《数据结构(用面向对象方法与C++语言描述)(第2版)》殷人昆——第四章
[2] 百度搜索关键字:广义表
[3] 网络资源: