以下内容主要参考了严蔚敏版的数据结构教材。
     广义表是线性表的推广,现在假设有广义表LS={a1,a2,...,an}LS=\{a_1,a_2,...,a_n\}LS={a1​,a2​,...,an​},ai(i=1,2,...,n)a_i(i=1,2,...,n)ai​(i=1,2,...,n)是表中的元素,与线性表不同的是,线性表中的每一个数据元素都属于同一数据对象(或者说类),比如一个英文字符或者是同一类型的一个结构体变量。但是对于广义表中的元素ai(i=1,2,...,n)a_i(i=1,2,...,n)ai​(i=1,2,...,n),它既可以是同一数据对象(或者说类)[原子元素][原子元素][原子元素]也可以是由该数据对象(或者说类)组成的广义表[子表元素][子表元素][子表元素],这样来看的话广义表的定义是一个递归的定义。当广义表非空时,称其第一个元素为表头,称其剩余元素组成的表为表尾。表头可能为[原子元素][原子元素][原子元素]也可能是[子表元素][子表元素][子表元素],但是表尾一定是[子表元素][子表元素][子表元素]。
     现在举例说明如下(数据对象为英文字符):

  • A=()A=()A=(),A是一个空表。
  • B=(e)B=(e)B=(e),B是一个包含一个原子元素的广义表。
  • C=(a,(b,c,d))C=(a,(b,c,d))C=(a,(b,c,d)),C是一个包含一个原子元素元素和一个子表元素(b,c,d)(b,c,d)(b,c,d)的广义表。
  • D=(A,B,C)D=(A,B,C)D=(A,B,C),D是一个包含三个子表元素的广义表。
  • E=(a,E)E=(a,E)E=(a,E),E是一个包含一个原子元素和一个子表元素的广义表。子表元素就是该广义表本身,因此这是一个递归的表。

由于广义表中的元素既可以是[原子元素][原子元素][原子元素]也可以是[子表元素][子表元素][子表元素],因此很难用顺序存储结构,因此通常采用链式存储结构。以下介绍了广义表的两种相近的链式存储结构:

  • 结构一,该结构中有两种节点,表节点和原子节点,如图1所示。表节点用来表示整个广义表或者广义表中的一个[子表元素][子表元素][子表元素]。它有三个数据域,isAtomisAtomisAtom(原子节点也有该数据域)用来表示该节点是否是原子节点或表节点,指针域headheadhead指向该广义表的表头,指针域tailtailtail指向该广义表的表尾。原子节点用来表示广义表中的[原子元素][原子元素][原子元素],除了isAtomisAtomisAtom数据域外,AtomTypeAtomTypeAtomType存储实际的原子类型的记录。图2给出了上面提到的几个广义表例子的该链式表示。
  • 结构二,该结构中也有两种节点,表节点和原子节点,如图3所示。表节点用来表示整个广义表或者广义表中的一个[子表元素][子表元素][子表元素]。它有三个数据域,isAtomisAtomisAtom(原子节点也有该数据域)用来表示该节点是否是原子节点或表节点,指针域headheadhead指向该广义表的表头,指针域nextnextnext指向该广义表的下一个元素。原子节点用来表示广义表中的[原子元素][原子元素][原子元素],除了isAtomisAtomisAtom数据域外,AtomTypeAtomTypeAtomType存储实际的原子类型的记录,指针域nextnextnext指向该广义表的下一个元素。。图4给出了上面提到的几个广义表例子的该链式表示。

从图二和图四可以看出对于空表,两种链式表示不一样,单这是课本上这么画的,我个人觉得,两种结构的空表既可以表示为图2的形式也可以表示为图4的形式。

图1.
图2.
图3.
图4.
class GenListNode
{public:GenListNode(bool atom = false, char data = '\0', GenListNode* h = nullptr, GenListNode* t = nullptr){isAtom = atom;u.character = data;u.ptr.head=h;u.ptr.tail = t;}friend class GenList;
private:bool isAtom;union{char character;struct {GenListNode* head;GenListNode* tail;}ptr;}u;
};
class GenList
{public:GenList(GenListNode* h){front=h;}
private:GenListNode* front;
};class GenListNode
{public:GenListNode(bool atom=false,char data='\0',GenListNode* sub=nullptr){isAtom=atom;u.character =data;u.subListHead =sub;}friend class GenList;
private:bool isAtom;union{char character; GenListNode* subListHead;}u;GenListNode* nextGenListNode;
};
class GenList
{public:GenList(GenListNode* h){front = h;}
private:GenListNode* front;
};

----------------------------分割线----------------------------------------------
     现在我们来用广义表来表示mmm元多项式。一个mmm元多项式的每一项最多有m个变元和一个系数,如果对mmm元多项式的每一项不管其实际变元个数的多少都分配m+1m+1m+1的数据项来存储一个系数和mmm个变元的指数,当多项式中每一项的实际变元个数偏少时会造成空间的极大浪费。如果按照mmm元多项式的每一项的实际变元个数来分配空间的话会造成算法处理以及存储的不便。因此mmm元多项式不适用与顺序表的存储结构。
     现在有一个三元多项式P(x,y,z)=x10y3z2+2x6y3z2+3x5y2z2+x4y4z+6x3y4z+2yz+15=((x10+2x6)y3+3x5y2)z2+((x4+6x3)y4+2y)z+15P(x,y,z)=x^{10}y^3z^2+2x^6y^3z^2+3x^5y^2z^2+x^4y^4z+6x^3y^4z+2yz+15=((x^{10}+2x^6)y^3+3x^5y^2)z^2+((x^4+6x^3)y^4+2y)z+15P(x,y,z)=x10y3z2+2x6y3z2+3x5y2z2+x4y4z+6x3y4z+2yz+15=((x10+2x6)y3+3x5y2)z2+((x4+6x3)y4+2y)z+15。
     我们令:

  • A(x,y)=(x10+2x6)y3+3x5y2A(x,y)=(x^{10}+2x^6)y^3+3x^5y^2A(x,y)=(x10+2x6)y3+3x5y2,B(x,y)=(x4+6x3)y4+2yB(x,y)=(x^4+6x^3)y^4+2yB(x,y)=(x4+6x3)y4+2y,则有:
  • P(x,y,z)=A(x,y)×z2+B(x,y)×z+15P(x,y,z)=A(x,y)\times z^2+B(x,y)\times z+15P(x,y,z)=A(x,y)×z2+B(x,y)×z+15

我们令:

  • C(x)=x10+2x6C(x)=x^{10}+2x^6C(x)=x10+2x6,D(x)=3x5D(x)=3x^5D(x)=3x5,E(x)=x4+6x3E(x)=x^4+6x^3E(x)=x4+6x3,则有:
  • A(x,y)=C(x)y3+D(x)y2A(x,y)=C(x)y^3+D(x)y^2A(x,y)=C(x)y3+D(x)y2,B(x,y)=E(x)y4+2yB(x,y)=E(x)y^4+2yB(x,y)=E(x)y4+2y

从以上内容我们可以看出3元多项式P(x,y,z)P(x,y,z)P(x,y,z)可以分解为变元zzz的多项式,其中A(x,y)A(x,y)A(x,y)和B(x,y)B(x,y)B(x,y)都是二元多项式。A(x,y)A(x,y)A(x,y)和B(x,y)B(x,y)B(x,y)可以分解为变元yyy的多项式,其中C(x)、D(x)、E(x)C(x)、D(x)、E(x)C(x)、D(x)、E(x)都是一元多项式。因此任何一个mmm元多项式都可以分解为mmm个变元中的一个变元的多项式,这个多项式的系数可能为实数,也可能是剩下的m−1m-1m−1个变元的m−1m-1m−1元多项式。递归的这些作为系数的m−1m-1m−1元多项式又可以分解为m−1m-1m−1个变元中的一个变元的多项式,这个多项式的系数可能为实数,也可能是剩下的m−2m-2m−2个变元的m−2m-2m−2元多项式。递归的分解直到作为系数的多项式为一元多项式为止。
     基于mmm元多项式的这种分解特性,可以采用类似广义表的第二中存储结构的存储结构来表示mmm元多项式,如图5所示。

图5.

表结点用来表示系数为多项式的项,原子结点用来表示系数为实数的项。表结点的headheadhead域指向系数多项式的第一项,原子结点的coefficientscoefficientscoefficients域表示系数为实数的项的系数。exponentexponentexponent域表示多项式的项的指数,nextnextnext域指向多项式的下一项。除了与广义表的第二中存储结构的以上区别外,具体在构建mmm元多项式的链式存储结构时,还有以下两种区别。

  • 对于初始的待表示的多项式,比如三元多项式P(x,y,z)P(x,y,z)P(x,y,z)可以先将其看做是某个多项式(只含有一项)的某一项的系数多项式,该广义表的头指针指向的表结点就代表该系数多项式,但是因为初始多项式并不是某个多项式的一项的系数多项式,其指数域为初始多项式中变元的个数,
  • 在表示每一层多项式的表中,会增加一个表头结点,其指数域为该层多项式的变元的数组索引,第三个数据域没有含义。

三元多项式P(x,y,z)P(x,y,z)P(x,y,z)的广义表的链表结构如图6所示。

图6.
class MPNode
{public:MPNode(bool atom = false, int exp=0,int coe = 0, MPNode* sub = nullptr){isAtom = atom;exponent = exp;u.coefficients = coe;nextMPNode = sub;}friend class MPolynomial;
private:bool isAtom;int exponent;union{int coefficients;MPNode* subListHead;}u;MPNode* nextMPNode;
};
class MPolynomial
{public:MPolynomial(MPNode* h=nullptr){front = h;}
private:MPNode* front;
};

----------------------------分割线----------------------------------------

广义表的递归算法:

  • 求广义表的深度:广义表的深度定义为广义表中括弧的重数,例如广义表GL=((),(e),(a,(b,c,d)))GL=((),(e),(a,(b,c,d)))GL=((),(e),(a,(b,c,d)))外向里有三重括弧,因此该广义表的深度为3(图7)。这里在求广义表的深度的时候使用的是广义表的第一种存储结构。求广义表的深度的算法为递归算法:

    • 递归算法的终结状态为遇到原子节点或者是空表,原子节点的深度为0,空表的深度为1。
    • 递归算法迭代访问同一层次的每一个节点并对headheadhead指针递归调用求得每一个字表的深度,它们中的值的最大值加一就是当前广义表的深度。
  • 复制广义表:复制广义表的算法也是递归算法。这里在复制广义表的时候使用的也是广义表的第一种存储结构。(广义表GL=(a,(b,c,d))GL=(a,(b,c,d))GL=(a,(b,c,d))的递归调用过程如图8所示)第一种存储结构将广义表看做表头和表尾,在复制的时候:
    • 首先复制当前节点的原子表节点标志位。
    • 然后分别递归复制表节点的表头和表尾,直到遇到空节点或原子节点的时候终止递归调用。
图7.
图8.
class GenListNode
{public:GenListNode(bool atom = false, char data = '\0', GenListNode* h = nullptr, GenListNode* t = nullptr){isAtom = atom;u.character = data;u.ptr.head = h;u.ptr.tail = t;}GenListNode* getHead(){return u.ptr.head;}GenListNode* getTail(){return u.ptr.tail;}void setFlag(bool value){isAtom = value;}void setAtom(char value){u.character = value;}void setHead(GenListNode* value){u.ptr.head = value;}void setTail(GenListNode* value){u.ptr.tail = value;}void copyNode(GenListNode* &ptr){ptr->setFlag(isAtom);if (isAtom){ptr->setAtom(u.character);}else{if (u.ptr.head != nullptr){GenListNode* temp = new GenListNode();u.ptr.head->copyNode(temp);ptr->setHead(temp);}else{ptr->setHead(nullptr);}if (u.ptr.tail != nullptr){GenListNode* temp = new GenListNode();u.ptr.tail->copyNode(temp);ptr->setTail(temp);}else{ptr->setTail(nullptr);}}return ;}int depth(){if (isAtom){return 0;}int max = 0;int temp = 0;if (u.ptr.head!=nullptr){max = u.ptr.head->depth();}GenListNode* ptr= u.ptr.tail;for (;ptr;ptr=ptr->getTail()){if (ptr->getHead()==nullptr){temp = 1;}else{temp = ptr->getHead()->depth();}if (temp>max){max = temp;}}return max + 1;}
private:bool isAtom;union{char character;struct{GenListNode* head;GenListNode* tail;}ptr;}u;
};
class GenList
{public:GenList(GenListNode* h=nullptr){front = h;}void setFront(GenListNode* value){front = value;}int depth(){if (front== nullptr){return 1;}else{return front->depth();}}int copyGList(GenList &newGL){if (front == nullptr){return 1;}else{GenListNode* temp = new GenListNode();front->copyNode(temp);newGL.setFront(temp);}}
private:GenListNode* front;
};

--------------------------------------------------------------------------------------------------
     下面要说的是广义表的创建。这里采用的也是以上介绍的第一种存储结构并且假设原子类型为英文字符。那么一般的广义表将如GL=(a,(b,c,d))GL=(a,(b,c,d))GL=(a,(b,c,d))这样的形式,该广义表写成字符串的形式就是"(a,(b,c,d))"。创建广义表的函数原型为voidcreateGList(GenListNode∗&front,stringLStr)void \ createGList(GenListNode* \ \& \ front,string\ LStr)void createGList(GenListNode∗ & front,string LStr),其中参数LStrLStrLStr就是广义表的字符串形式,参数frontfrontfront可以看成是广义表的头指针。该函数的作用就是根据广义表的字符串表示来构建其链表结构。
     函数intsever(string&str,string&hstr)int\ sever(string\ \& str,string\ \&hstr)int sever(string &str,string &hstr)为辅助函数。它的作用是取出字符串strstrstr中第一个逗号前的所有字符构成的字符串并赋值给hstrhstrhstr并将剩下的除第一个逗号外的所有字符组成的字符串赋值给字符串strstrstr。
     这里的算法为递归算法且与上面求广义表的深度的算法的递归过程类似(把广义表看成是含有n个并行的同一级别的子表,对n个子表进行递归)。广义表GL=(a,(b,c,d))GL=(a,(b,c,d))GL=(a,(b,c,d))的递归建表过程如图9所示。

图9.
int sever(string & str,string &hstr)
{int len = str.length();string subString;int i = 0;int k = 0;do{subString = str.substr(i,1);if (subString =="("){++k;}else if (subString == ")"){--k;}++i;} while ((i < len) && ((subString != ",") || (k != 0)));cout << "i=" << i << endl;if (i < len){hstr = str.substr(0,i-1);str = str.substr(i,len-i);}else{hstr = str;str = "";}return 1;
}void createGList(GenListNode* &front,string LStr)
{GenListNode* ptr = nullptr;GenListNode* q = nullptr;GenListNode* temp = nullptr;string subStr = "";string hStr = "";if (LStr==""){front = nullptr;}else{front =new GenListNode;if (LStr.length==1){front->setFlag(true);front->setAtom(LStr[0]);}else{front->setFlag(false);ptr = front;subStr = LStr.substr(1,LStr.length()-2);do{sever(subStr, hStr);createGList(temp,hStr);ptr->setHead(temp);temp = nullptr;q = ptr;if (!subStr.empty()){ptr = new GenListNode;ptr->setFlag(false);q->setTail(ptr);}} while (!subStr.empty());q->setTail(nullptr);}}return;
}
//简单测试程序
int main()
{string LStr = "(a,(b,(c,d)))";GenListNode* front = nullptr;GenList GL;GenList GLCopy;createGList(front, LStr);GL.setFront(front);GL.copyGList(GLCopy);cout<<GL.depth()<<endl;cout << GLCopy.depth();}

广义表(Generalized Lists)相关推荐

  1. 广义表及其存储方式简介

    广义表(Lists,又称列表)是线性表的推广.线性表定义为n>=0个元素a1,a2,a3,-,an的有限序列.线性表的元素仅限于原子项,原子是作为结构上不可分割的成分,它可以是一个数或一个结构, ...

  2. 【数据结构和算法笔记】:广义表

    目录 广义表概念: 表示方法: 括号表示法 子表加匿名表示法 广义表储存结构:​ 广义表的算法设计: 广义表概念: ○广义表(Lists,又称列表)是线性表的推广. ○线性表定义为n>=0个元素 ...

  3. 广义表的链式定义和基础操作

    广义表的定义 广义表(Lists,又称列表)是线性表的推广.线性表定义为n>=0个元素a1,a2,a3,-,an的有限序列.线性表的元素仅限于原子项,原子是作为结构上不可分割的成分,它可以是一个 ...

  4. 数据结构 习题 第五章 多维数组和广义表 (C语言描述)

    最近在复习数据结构,所以想把平时上课做的习题做个总结,如果大家有遇到这方面的问题就可以参考一下了,废话不多说,直接开始吧. 1.单选题 稀疏矩阵一般的压缩存储方法有两种,即( D) A. 二维数组和三 ...

  5. 【课上笔记】第五章 数组和广义表

    数组和广义表 5.1多维数组 5.1.1数组的逻辑结构 数组是我们熟悉的一种数据结构,可以看作线性表的推广. 数组作为一种数据结构其特点是结构中的元素本身可以是具有某种结构的数据,但属于同一类型.比如 ...

  6. c++数据结构之广义表

    最近学习了广义表,我们知道广义表也是一种线性表,而顾名思义广义表就是不止一个表,下面来举个栗子: A=( ) B=(1 , 2,3) C=(1 ,2 ,3, ( a , b ,c) ) D=(1, 2 ...

  7. Java数据结构和算法:字符串、数组和广义表

    数组和广义表是与前述的线性表有所区别的数据结构.它们可以看成是线性表在下述含义上的扩展:线性表中的元素本身也是一个数据结构 字符串 字符串的定义.存储结构 字符串(string)是由n (n≥0) 个 ...

  8. java 广义表_数据结构:广义表的实现(Java)

    Java实现广义表: package 广义表; import java.util.Stack; public class Test { public final int TAG_TABLE = 1; ...

  9. 数据结构05数组和广义表

    第五章 数组 和 广义表 数组和广义表可以看成是线性表在下述含义上的扩展:表中的数据元素本身也是一个数据结构. 5.1 数组的定义 n维数组中每个元素都受着n个关系的约束,每个元素都有一个直接后继元素 ...

  10. 数据结构数组计算机中的应用,2018考研计算机:数据结构数组和广义表复习重点...

    2018考研计算机:数据结构数组和广义表复习重点 2017-08-17 16:00 | 考研集训营 <数据结构(C语言版)>复习重点在二.三.六.七.九.十章,考试内容两大类:概念,算法, ...

最新文章

  1. 如何修改word中的单位信息、用户信息及文档属性
  2. iOS 开发音视频流[1]---FFmpeg
  3. android 退出程序提示是否退出对话框
  4. 【转】实战 SSH 端口转发
  5. 微信小程序~自定义属性设置和获取(data-)
  6. 2020-11-04
  7. 腾讯终于摘掉“游戏公司”帽子!B端业务也稳了
  8. 计算机网络讨论课感悟,计算机网络课程学习心得体会
  9. Python操作Redis:键(Key)
  10. VALSE学习(十二):视频时序建模和动作识别
  11. 在html中写python代码的语法和特点-----基于webpy的httpserver
  12. 北京大学肖臻老师《区块链技术与应用》公开课笔记:以太坊原理(三):智能合约
  13. 记录进行Uniprot转化为Entrez ID的过程
  14. [Codeforces Round #428 DIV2E (CF839E)] Mother of Dragons
  15. SyntaxError: Non-ASCII character ‘\xe7‘ in file F:/python_code/test/venv/Shan.py on line 7,
  16. python循环次数教程_Python基础教程-循环
  17. WSL2 Ubuntu中apt update命令报错,无法解析域名解决方法
  18. android 定位 闪退_Unity3D研究院之全方位定位Android闪退(九十三)
  19. tda4vm如何SPL方式加载MCU域的核?
  20. 输入一个角度的弧度值x,计算该角的余弦值

热门文章

  1. java 问号运算符_JAVA问号?运算符的用法,问号表达式
  2. c++ 11 for循环
  3. android 自动剪裁图片,android使用系统裁剪图片
  4. AU降噪 李兴兴
  5. TcaplusDB X 黎明觉醒,探索不止,黎明将至
  6. 请假代码java web_学生请假管理系统
  7. Python问题:NotImplementedError: The confidence keyword argument is only available if OpenCV is install
  8. 人这一辈子,都在为选择买单
  9. 嘉兴 机器人仓库 菜鸟_菜鸟物流嘉兴未来园区的工业机器人系统运维员的一天...
  10. 请假时间计算方式java_java计算两段时间的重复天数