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

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. vmware全屏后去掉上面的横杠

    全屏后选择查看—>独占模式最上面的杠就没了,而且不按退出快捷键,不会在切换到外面的系统中了.

  2. 基于候选区域的深度学习目标检测算法R-CNN,Fast R-CNN,Faster R-CNN

    参考文献 [1]Rich feature hierarchies for accurate object detection and semantic segmentation [2]Fast R-C ...

  3. node install webpack -cli webpack4.xxxx

    webpack 4.xx 版本 分离了 webpack-cli ; 安装webpack4.xx 需要再安装webpack-cli;

  4. 问题:只能在执行 Render() 的过程中调用 RegisterForEventValidation;结果:只能在执行 Render() 的过程中调用 RegisterForEventValidation

    只能在执行 Render() 的过程中调用 RegisterForEventValidation 当在导出Execl或Word的时候,会发生只能在执行 Render() 的过程中调用 Register ...

  5. 【Android 多媒体应用】使用 TTS

    import java.util.Locale; import android.app.Activity; import android.os.Bundle; import android.speec ...

  6. DAY16-Django之MTV

    MTV模型 Django的MTV分别代表: Model(模型):负责业务对象与数据库的对象(ORM) Template(模版):负责如何把页面展示给用户 View(视图):负责业务逻辑,并在适当的时候 ...

  7. 运行shell脚本报/bin/bash^M: bad interpreter错误排查方法

    今天遇到一个奇怪的问题,从一个服务器上down下来的脚本,在本地电脑做了点修改之后,上传到另外一台服务器上来执行,就报这个错误,问度娘,是编码格式的问题,windows把sh格式的编码改成dos格式的 ...

  8. Shiro权限框架简介

    http://blog.csdn.net/xiaoxian8023/article/details/17892041   Shiro权限框架简介 2014-01-05 23:51 3111人阅读 评论 ...

  9. dp-最小点对问题

    dp-最小点对问题 //最小点对问题 //采用分治思想,先分成两个子集分别求出最短距离d //再对两个子集进行合并,在一个dx2d的矩形中,最多可能有6个点距离小于d //按y排序,当x增长时求出这6 ...

  10. JAVA基础知识总结12(多线程)

    进程:正在进行中的程序.其实进程就是一个应用程序运行时的内存分配空间. 线程:其实就是进程中一个程序执行控制单元,一条执行路径.进程负责的是应用程序的空间的标示.线程负责的是应用程序的执行顺序. 一个 ...