广义表,又称为列表。记作:

LS = (a1,a2,…,an) ;( LS 为广义表的名称, an 表示广义表中的数据)。

广义表可以看作是线性表的推广。两者区别是:线性表中的数据元素只能表示单个数据元素;广义表中的单个数据元素 a,既可以是单个元素,也可以是广义表。

原子和子表

在广义表中,单个元素被称为 “原子”;包含的广义表被称为 “子表”。

例如:

  1. A = ()  :A 表示一个广义表,只不过表是空的,广义表 A 的长度为 0。
  2. B = (e)  :广义表 B 中只有一个原子 e ,长度为 1。
  3. C = (a,(b,c,d)) :广义表 C 中有两个元素,原子 a 和子表 (b,c,d) ,广义表C的长度为 2。
  4. D = (A,B,C) :广义表 D 中有三个元素:子表 A、B、C,长度为 3 ,这种表示方式等同于: D = ((),(e),(b,c,d)) 。
  5. E = (a,E)  :广义表 E 中有两个元素,原子 a 和它本身,长度为 2 。这是一个递归的表,等同于:E = (a,(a,(a,…)))。
A = () 和 A = (()) 是不一样的:前者是空表,长度为 0 ;后者表的长度为 1 ,包含的元素是一个子表,只不过这个子表是空表。

表头和表尾

当广义表不为空时,称表中的第一个元素为表的 “表头” ;剩余所有元素组成的表为 “表尾” 。

任何一个非空广义表,表尾肯定是广义表。

例如:上边例子中的 D = (A,B,C) ,子表 A 为广义表 D 的表头;而 (B,C) 组成的表为 D 的表尾。

非空广义表是由表头和表尾构成,反过来说也对:给定一个表头和表尾,可以唯一确定一个广义表。

广义表中结点结构

由于广义表中的数据元素类型分为原子和子表,难以使用顺序存储结构表示,所以通常采用链式存储结构。

根据原子和子表的不同,链式存储中的结点需要用两种不同的结构表示。对于原子来说,需要由两部分组成:标志位 + 值域(如图1(A));子表需要由三部分组成:标志位 + 指向表头的指针域 + 指向表尾的指针域(如图1(B))。

两者都有一个相同的标志位,作用是为了能够区分出原子和字表,一般标志位为1,表示子表;标志位为0,表示原子。

图1 广义表的链表结点结构

代码表示:

typedef struct GLNode
{
  int tag;  //标志域
  union
  {
    char atom;  //原子结点的值域
    struct
    {
      struct GLNode *hp, *tp;
    }ptr;  //子表结点的指针域,hp指向表头;tp指向表尾
  };
}*Glist;

例如,使用图1的链表结构表示广义表 C = (a,(b,c,d)),效果图为:


图2 广义表C的结构示意图

实现代码为:

Glist creatGlist(Glist C)
{
  // 广义表C
  C = (Glist)malloc(sizeof(Glist));
  C->tag = ;
  // 表头原子‘a’
  C->ptr.hp = (Glist)malloc(sizeof(Glist));
  C->ptr.hp->tag = ;
  C->ptr.hp->atom = 'a';
  // 表尾子表(b,c,d),是一个整体
  C->ptr.tp = (Glist)malloc(sizeof(Glist));
  C->ptr.tp->tag = ;
  C->ptr.tp->ptr.hp = (Glist)malloc(sizeof(Glist));
  C->ptr.tp->ptr.tp = NULL;
  // 开始存放下一个数据元素(b,c,d), 表头为‘b’,表尾为(c,d)
  C->ptr.tp->ptr.hp->tag = ;
  C->ptr.tp->ptr.hp->ptr.hp = (Glist)malloc(sizeof(Glist));
  C->ptr.tp->ptr.hp->ptr.hp->tag = ;
  C->ptr.tp->ptr.hp->ptr.hp->atom = 'b';
  C->ptr.tp->ptr.hp->ptr.tp = (Glist)malloc(sizeof(Glist));
  // 存放子表(c,d),表头为c,表尾为d
  C->ptr.tp->ptr.hp->ptr.tp->tag = ;
  C->ptr.tp->ptr.hp->ptr.tp->ptr.hp = (Glist)malloc(sizeof(Glist));
  C->ptr.tp->ptr.hp->ptr.tp->ptr.hp->tag = ;
  C->ptr.tp->ptr.hp->ptr.tp->ptr.hp->atom = 'c';
  C->ptr.tp->ptr.hp->ptr.tp->ptr.tp = (Glist)malloc(sizeof(Glist));
  // 存放表尾d
  C->ptr.tp->ptr.hp->ptr.tp->ptr.tp->tag = ;
  C->ptr.tp->ptr.hp->ptr.tp->ptr.tp->ptr.hp = (Glist)malloc(sizeof(Glist));
  C->ptr.tp->ptr.hp->ptr.tp->ptr.tp->ptr.hp->tag = ;
  C->ptr.tp->ptr.hp->ptr.tp->ptr.tp->ptr.hp->atom = 'd';
  C->ptr.tp->ptr.hp->ptr.tp->ptr.tp->ptr.tp = NULL;
  return C;
}

结点结构的另一种表示方式

除了上边的那种表示结点的方式,还可以采用另外一种表示形式,不同在于:表结点和原子结点都添加了一个指向下一个数据元素的指针;而子表结点中只保留了指向表头结点的指针,删除了指向表尾的指针。


图3 广义表的另一种结点结构

代码表示为:

typedef struct GLNode
{
  int tag;  //标志域
  union
  {
    int atom;  //原子结点的值域
    struct GLNode *hp;  //子表结点的指针域,hp指向表头
  };
  struct GLNode *tp;  //这里的tp相当于链表的next指针,用于指向下一个数据元素
}*Glist;

例如,用这种结构结构表示C = (a,(b,c,d)),效果图为:


图4 广义表C的结构示意图

实现代码:

Glist creatGlist(Glist C)
{
  C = (Glist)malloc(sizeof(Glist));
  C->tag = ;
  C->hp = (Glist)malloc(sizeof(Glist));
  C->tp = NULL;
  // 表头原子a
  C->hp->tag = ;
  C->atom = 'a';
  C->hp->tp = (Glist)malloc(sizeof(Glist));
  C->hp->tp->tag = ;
  C->hp->tp->hp = (Glist)malloc(sizeof(Glist));
  C->hp->tp->tp = NULL;
  // 原子b
  C->hp->tp->hp->tag = ;
  C->hp->tp->hp->atom = 'b';
  C->hp->tp->hp->tp = (Glist)malloc(sizeof(Glist));
  // 原子c
  C->hp->tp->hp->tp->tag = ;
  C->hp->tp->hp->tp->atom = 'c';
  C->hp->tp->hp->tp->tp = (Glist)malloc(sizeof(Glist));
  // 原子d
  C->hp->tp->hp->tp->tp->tag = ;
  C->hp->tp->hp->tp->tp->atom = 'd';
  C->hp->tp->hp->tp->tp->tp = NULL;
  return C;
}

总结

在编写代码时,一定要注意不要破坏广义表中数据元素之间的关系,例如:C1 = (a,b,c,d)和 C2 = (a,(b,c),d),两个广义表中数据元素是一样的,但是数据元素之间的关系不同,在 C1 中,各原子之间是并列的,而 C2 中,原子 a 和子表 (b,c) 和 d 是并列的。

补:M元多项式的表示

例如:

P(x,y,z) = x10y3z2 + 2x6y3z2 + 3x5y2z2 + x4y4z + 6x3y4z + 2yz + 15

这是一个3元多项式(有3个变量:x,y,z),使用广义表表示M元多项式,首先需要对多项式做一下变形:

P(x,y,z)=((x10+2x6)y3+3x5y2)z2+((x4+6x3)y4+2y)z+15

经过变形后,P(x,y,z)可以这样表示:

P(x,y,z)=Az2+Bz+15,其中:A=Cy3+Dy2,B=Ey4+Fy,C=x10+2x6,D=3x5,E=x4+6x3,F=2

经过两轮转化后,P这个 3 元多项式分解成了由 A 多项式和 B 多项式组成的一元多项式(只有一个变元 z ),而 A 也变成了由 C 多项式和 D 多项式组成的一元多项式,…。

当全部转化成能用一元多项式表示时,每一个一元多项式只需要存储各项的指数和系数就可以了。

广义表中每个结点的构成如图5所示:


图5 多项式结点构成

代码表示:

typedef struct MPNode
{
  int tag;  //区分原子结点和子表结点(0代表原子;1代表子表)
  int exp;  //存放指数域
  union
  {
    int coef;  //存放多项式的系数
    struct MPNode *hp;  //当多项式系数为子表时,用它
  };
  struct MPNode *tp;  //相当于线性链表的next,指向下一个数据元素
}*MPList;
注意:在表示多项式的时候,每一个一元多项式,都要额外添加一个表头结点,用于记录此一元多项式中的变元(是x,y还是z),而所有的变元可以预先存储在数组中,这样就可以利用每一个表头结点中的 exp 变量表示变元所在数组中的位置下标。

实现代码:

MPList initP(MPList P)
{
  char a[] = "xyz";
  MPList F = (MPList)malloc(sizeof(MPList));
  F->tag = ;
  F->exp = ;  // 表示F这个一员多项式中的变元位a[0],也就是x
  F->hp = NULL;
  F->tp = (MPList)malloc(sizeof(MPList));
  F->tp->tag = ;
  F->tp->exp = ;   // x的指数为0
  F->tp->coef = ;   // 系数为2
  F->tp->tp = NULL;  // tp截止,说明F=2;
  MPList E = (MPList)malloc(sizeof(MPList));
  E->tag = ;
  E->exp = ;  // E中变元位a[0],即x
  E->hp = NULL;
  E->tp = (MPList)malloc(sizeof(MPList));
  E->tp->tag = ;
  E->tp->exp = ;
  E->tp->coef = ;
  E->tp->tp = (MPList)malloc(sizeof(MPList));
  E->tp->tp->tag = ;
  E->tp->tp->exp = ;
  E->tp->tp->coef = ;
  E->tp->tp->tp = NULL;// 截止,E=1*x4+6*x3(x后为它的指数)
  MPList D = (MPList)malloc(sizeof(MPList));
  D->tag = ;
  D->exp = ;// D中变元为a[0],即x
  D->hp = NULL;
  D->tp = (MPList)malloc(sizeof(MPList));
  D->tp->tag = ;
  D->tp->exp = ;
  D->tp->coef = ;
  D->tp->tp = NULL;  // 截止,D=3*x5(5是x的指数);
  MPList C = (MPList)malloc(sizeof(MPList));
  C->tag = ;
  C->exp = ;  // C中变元为a[0]=x;
  C->hp = NULL;
  C->tp = (MPList)malloc(sizeof(MPList));
  C->tp->tag = ;
  C->tp->exp = ;
  C->tp->coef = ;
  C->tp->tp = (MPList)malloc(sizeof(MPList));
  C->tp->tp->tag = ;
  C->tp->tp->exp = ;
  C->tp->tp->coef = ;
  C->tp->tp->tp = NULL;  // C=1*x10+2*x6
  MPList B = (MPList)malloc(sizeof(MPList));
  B->tag = ;
  B->exp = ;  // B中变元为a[1]=y
  B->hp = NULL;
  B->tp = (MPList)malloc(sizeof(MPList));
  B->tp->tag = ;
  B->tp->exp = ;
  B->tp->hp = E;
  B->tp->tp = (MPList)malloc(sizeof(MPList));
  B->tp->tp->tag = ;
  B->tp->tp->exp = ;
  B->tp->tp->hp = F;
  B->tp->tp->tp = NULL;  // B=E*y4+F*x1;
  MPList A = (MPList)malloc(sizeof(MPList));
  A->tag = ;
  A->exp = ;  // A中变元为a[1]=y;
  A->hp = NULL;
  A->tp = (MPList)malloc(sizeof(MPList));
  A->tp->tag = ;
  A->tp->exp = ;
  A->tp->hp = C;
  A->tp->tp = (MPList)malloc(sizeof(MPList));
  A->tp->tp->tag = ;
  A->tp->tp->exp = ;
  A->tp->tp->hp = D;
  A->tp->tp->tp = NULL;  // A=C*y3+D*y2;
  P = (MPList)malloc(sizeof(MPList));
  P->tag = ;
  P->exp = ;  // 表示表元的数量
  P->hp = (MPList)malloc(sizeof(MPList));
  P->tp = NULL;
  P->hp->tag = ;
  P->hp->exp = ;  // P中变元为a[2]=z;
  P->hp->hp = NULL;
  P->hp->tp = (MPList)malloc(sizeof(MPList));
  P->hp->tp->tag = ;
  P->hp->tp->exp = ;
  P->hp->tp->hp = A;
  P->hp->tp->tp = (MPList)malloc(sizeof(MPList));
  P->hp->tp->tp->tag = ;
  P->hp->tp->tp->exp = ;
  P->hp->tp->tp->hp = B;
  P->hp->tp->tp->tp = (MPList)malloc(sizeof(MPList));
  P->hp->tp->tp->tp->tag = ;
  P->hp->tp->tp->tp->exp = ;
  P->hp->tp->tp->tp->coef = ;
  P->hp->tp->tp->tp->tp = NULL;  // P=A*z2+B*z1+15
  return P;
}

数据结构28:广义表及M元多项式的更多相关文章

  1. javascript实现数据结构:广义表

    原文:javascript实现数据结构:广义表  广义表是线性表的推广.广泛用于人工智能的表处理语言Lisp,把广义表作为基本的数据结构. 广义表一般记作: LS = (a1, a2, ..., an ...

  2. 数据结构:广义表的实现(Java)

    广义表的简单理解在这篇博文中:https://blog.csdn.net/lishanleilixin/article/details/87364496,在此不做赘述. Java实现广义表: pack ...

  3. 数据结构 c++ 广义表

    // CTest.cpp : 定义控制台应用程序的入口点. // #include "stdafx.h" #include <iostream> #include &l ...

  4. 数据结构5.4_m元多项式的表示

    三元多项式表示如下: P(x,y,z) = x10y3z2 + 2x6y3z2 + 3x5y2z2 + x4y4z + 6x3y4z + 2yz + 15 然后对式子进行变形: P(x,y,z)=(( ...

  5. 数据结构(C语言第2版)-----数组,广义表,树,图

    任何一个算法的设计取决于选定的数据结构,而算法的实现依赖于采用的存储结构. 之前线性表的数据元素都是非结构的原子类型,元素的值是不可再分的.下面学习的这两个线性表是很特殊的,其中数据元素本身也可能是一 ...

  6. 数据结构算法C语言实现(十九)--- 5.5&5.6&5.7广义表

    一.简述 传说Lisp的基本数据结构就是广义表,广义表也是具有典型递归属性的数据结构,此外,由于建表要处理字符串,用C语言处理起来也是一脸懵逼.....最后自己还想写一个将广义表还原成字符串的函数,一 ...

  7. 广义表操作 (ava实现)——广义表深度、广义表长度、打印广义表信息

    广义表是对线性表的扩展——线性表存储的所有的数据都是原子的(一个数或者不可分割的结构),且所有的数据类型相同.而广义表是允许线性表容纳自身结构的数据结构. 广义表定义: 广义表是由n个元素组成的序列: ...

  8. 【C/C++】实现数据结构广义表

    1. 广义表的定义     每个元素可以为Atom,原子,也可以为线性表.      线性表的推广.线性表元素有唯一的前驱和后继,为线性表,而广义表是多层次的线性表      表头:第一个元素,可能是 ...

  9. 数据结构(C语言版)-第4章 串、数组和广义表

    补充:C语言中常用的串运算 调用标准库函数 #include<string.h> 串比较,strcmp(char s1,char s2) 串复制,strcpy(char to,char f ...

随机推荐

  1. handlebars中的partial

    高级玩家:partial 比较推崇使用分页来实现组件化.分页跟helper一样需要先注册.在hbs模块中可以批量注册,比较简单. hbs.registerPartials(__dirname + '/ ...

  2. 冷扑大师AI简史:你用德扑来游戏,人家用来发Science

    前言 人类又输了...... 创新工场组织的一场“人工智能和顶尖牌手巅峰表演赛中”,机器人AI冷扑大师赢了人类代表队龙之队 792327 记分牌,最后 200 万奖励归机器人所有. 在围棋项目上人类的 ...

  3. windows 修改端口数据及连接时间

    最近线上遇到windows机器访问其他机器的时候失败的情况.实际就是本地的端口不够用造成的. D:\>netsh interface ipv4 show dynamicportrange pro ...

  4. Ok6410裸机驱动学习(三)C语言内嵌汇编

    1.C语言内嵌汇编使用方法 C内嵌汇编以关键字”_asm_或asm开始,下辖4个部分,各部分之间用“:”分开,第一部分是必须写的,后面3个部分可以省略,但是分号:不能省略 优化后的代码 2.汇编程序框 ...

  5. DAY10-MYSQL初识

    一 数据库管理软件的由来 基于我们之前所学,数据要想永久保存,都是保存于文件中,毫无疑问,一个文件仅仅只能存在于某一台机器上. 如果我们暂且忽略直接基于文件来存取数据的效率问题,并且假设程序所有的组件 ...

  6. [Python Study Notes]pd.read_csv()函数读取csv文件绘图

    ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' ...

  7. 【总结整理】WebGIS基础

    1.万维网:www是world wide web的简称是在超文本基础上形成的信息网 2.互联网:即广域局域网及单机按照一定的通讯协议组成的国际计算机网络 3.WebGIS:网络地理信息系统,指基于In ...

  8. .NET回归 HTML----表单元素(1)和一些常用的标记

    表单就是-----用于搜集不同类型的用户输入. 表单元素指的是不同类型的 input 元素.复选框.单选按钮.提交按钮等等. 首先将表单元素分为三个类型.文本类,按钮类,选择类. 表单可以嵌套在表中, ...

  9. Opengl创建几何实体——四棱锥和立方体

    //#include <gl\glut.h>#include <GL\glut.h>#include <iostream> using namespace std; ...

  10. c语言实战: 计算时间差

    计算时间差有两种,一种是把时间都转化为分钟数,一种是把时间都转化为小时,后者是会用到除法所以不可避免产生浮点数,所以我们选择转化为分钟数来计算. //题目:给定两个时间点计算它们的时间差,比如,1:5 ...