广义表是对线性表的扩展——线性表存储的所有的数据都是原子的(一个数或者不可分割的结构),且所有的数据类型相同。而广义表是允许线性表容纳自身结构的数据结构。

广义表定义:

广义表是由n个元素组成的序列:LS = (a1,a2, ... an);其中 ai是一个原子项或者是一个广义表。n是广义表的长度。若ai是广义表,则称为LS的子表。

广义表表头和表尾:  若广义表LS不空,则a1,称为LS的表头,其余元素组成的子表称为表尾。

广义表的长度: 若广义表不空,则广义表所包含的元素的个数,叫广义表的长度。

广义表的深度: 广义表中括号的最大层数叫广义表的深度。

例如:

对广义表LS=((),a,b,(a,b,c),(a,(a,b),c))

表头为子表LSH = ();

表尾为子表LST = (a,b,(a,b,c),(a,(a,b),c));

广义表LS的长度:5

广义表LS的深度:3

对于广义表的操作都是建立在已经构建好的广义表上,那么如何通过一个广义表字符串构造一个广义表?

广义表的存储结构——广义表有多重存储结构,以下只讲代码中使用的存储结构,代码中采用以下存储结构:

tag data pH pT

tag    :tag == 0 ; 表示该节点为原子节点 。tag == 1 ; 表示该节点为表节点

data  :data是原子节点的数据,为表节点时该值域无效。

pH    :广义表的表头——是一个表节点或原子节点。

pT    :广义表的表尾——必定是一个表节点 或者 null。

表节点存储结构选择好了,那么如何来构造广义表呢?(比如:LS = ((),a,b,(a,b,c),(a,(a,b),c))), 根据以下规则,构造出来的广义表如下图:

header表示表头 , 带圈的指针表示由该符号创建的对应的节点(为了图片清晰有些节点没有画)。

对于一个广义表总有一个header节点指向该表的表节点,一个node表示当前正在操作的节点。

当遇到‘(’ 时构造一个表节点,并且将该符号压栈charStack,如果栈中的数据长度 > 1 , 表明广义表的深度加深一层 ,此时将该节点压入栈nodeStack,并且让node的pH节点指向新构造的节点。其代码如下:

if (ts.charAt(i) == mStartSymb) {
tmpNode = new Node(null, null, TAG_TABLE, null);
// tableNode = tableNode.mPt;
symbStack.push(ts.charAt(i));
if (symbStack.size() > 1) {
nodeStck.push(tableNode);
tableNode.mPh = tmpNode;
tableNode = tableNode.mPh;
} else {
tableNode.mPt = tmpNode;
tableNode = tableNode.mPt;
}
}

其中mStartSymb 表示广义表的 '表起始指示符' ,  symbStack.push(ts.charAt(i));将 '表起始指示符压栈' , 接下来判断symbStack栈的大小,代码:

nodeStck.push(tableNode);
tableNode.mPh = tmpNode;
tableNode = tableNode.mPh;

将当前的表节点压栈 , 接着表头指向新的node , 当前节点向前滑动一个位置。

当遇到原子节点符号(如:’a‘) 时,则创建一个原子节点,并且让表头指向该节点,其代码如下:

else {
itemNode = new Node(null, null, TAG_ITEM, ts.charAt(i));
tableNode.mPh = itemNode;
}

当遇到符号 ’,‘ 时构造一个表节点,让当前节点的表尾指向新的节点,其代码如下:

else if (ts.charAt(i) == ',') {
tableNode.mPt = new Node(null, null, TAG_TABLE, null);
tableNode = tableNode.mPt;
}

当遇到符号 ')' 时,做两件事

1、如果  symbStack 的长度 > 1 , 表明此时并没有回到表的最外层,肯定存在一个nodeStack中的节点需要出栈,接着让与之对应的 ’(‘ 符号出栈,其代码如下:

else if (ts.charAt(i) == mEndSymb) {
if (symbStack.isEmpty()) {
throw new IllegalArgumentException(
"IllegalArgumentException in constructor GeneralizedTable!...");
}
if (symbStack.size() > 1) {
tableNode = nodeStck.pop();
}
symbStack.pop();
}

当表字符串结束,切symStack的长度为0时,表明是一个格式正确的表字符串,否则说明该表字符串的格式错误,不予处理。

至此,一个广义表就构造OK了。根据上述原理,构造一个广义表的完整代码如下:

public GeneralizedTable(String genTable) {
if (genTable == null) {
throw new NullPointerException(
"genTable is null in constructor GeneralizedTable!...");
}
initTable(genTable);
} private void initTable(String genTable) {
String ts = genTable.replaceAll("\\s", "");
int len = ts.length();
Stack<Character> symbStack = new Stack<Character>();
Stack<Node> nodeStck = new Stack<Node>();
initSymbolicCharactor(ts);
mGenTable = new Node(null, null, TAG_TABLE, null);
Node itemNode, tableNode = mGenTable, tmpNode;
for (int i = 0; i < len; i++) {
if (ts.charAt(i) == mStartSymb) {
tmpNode = new Node(null, null, TAG_TABLE, null);
// tableNode = tableNode.mPt;
symbStack.push(ts.charAt(i));
if (symbStack.size() > 1) {
nodeStck.push(tableNode);
tableNode.mPh = tmpNode;
tableNode = tableNode.mPh;
} else {
tableNode.mPt = tmpNode;
tableNode = tableNode.mPt;
}
} else if (ts.charAt(i) == mEndSymb) {
if (symbStack.isEmpty()) {
throw new IllegalArgumentException(
"IllegalArgumentException in constructor GeneralizedTable!...");
}
if (symbStack.size() > 1) {
tableNode = nodeStck.pop();
}
symbStack.pop();
} else if (ts.charAt(i) == ',') {
tableNode.mPt = new Node(null, null, TAG_TABLE, null);
tableNode = tableNode.mPt;
} else {
itemNode = new Node(null, null, TAG_ITEM, ts.charAt(i));
tableNode.mPh = itemNode;
}
} if (!symbStack.isEmpty()) {
throw new IllegalArgumentException(
"IllegalArgumentException in constructor GeneralizedTable!...");
}
} private void initSymbolicCharactor(String ts) {
mStartSymb = ts.charAt(0);
switch (mStartSymb) {
case '(':
mEndSymb = ')';
break;
case '{':
mEndSymb = '}';
break;
case '[':
mEndSymb = ']';
break;
default:
throw new IllegalArgumentException(
"IllegalArgumentException ---> initSymbolicCharactor");
}
}

注释:本代码中支持 ( , )  , { , } ,  [ , ]  为"广义表标示符"的广义表字符串(默认是())。

求广义表的长度: 根据广义表长度的定义,该表的长度,等于原子节点或表节点的个数,即 header.pT != null 的个数 , 其代码如下:

public int length() { // 广义表的长度
if (mGenTable == null || mGenTable.mPt == null) {
return -1;
}
int tLen = 0;
Node node = mGenTable;
while (node.mPt != null) {
node = node.mPt;
if (node.mPh == null && node.mPt == null) {
break;
}
tLen++;
}
return tLen;
}

广义表的深度:因为广义表由
表头
表尾 组成 , 所以 , 广义表的深度是 表头、表尾中的最大深度。由此定义,得到如下代码:

public int depth() { // 广义表的深度
if (mGenTable == null) {
throw new NullPointerException("Generalized Table is null !.. ---> method depth");
}
return depth(mGenTable);
} private int depth(Node node) {
if (node == null || node.mTag == TAG_ITEM) {
return 0;
}
int depHeader = 0, depTear = 0;
depHeader = 1 + depth(node.mPh);
depTear = depth(node.mPt);
return depHeader > depTear ? depHeader : depTear;
}

广义表的表头:广义表的第一项称为表头,表头可能是一个原子项和广义表。但是不管如何,他都是第一个的pH指向的内容:其代码如下:

public GeneralizedTable getHeader() {
if (isEmpty())
return null;
Node node = mGenTable.mPt;
GeneralizedTable gt = new GeneralizedTable();
gt.mGenTable.mPt = node.mPh;
return gt;
}

广义表的表尾:广义表的表尾必定是一个广义表,但不管由什么子表组成,都是广义表的pT所指向的内容:求解广义表表尾的代码如下:

public GeneralizedTable getTear() {
if (isEmpty())
return null;
Node node = mGenTable.mPt;
GeneralizedTable gt = new GeneralizedTable();
gt.mGenTable.mPt = node.mPt;
return gt;
}

打印广义表的内容:这里打印广义表内容是指,打印所有原子项中的数据,一个深度优先打印的代码如下:

public void print() {
print(mGenTable);
} private void print(Node node) {
if (node == null) {
return;
}
if (node.mTag == 0) {
System.out.print(node.mData.toString() + " \t");
}
print(node.mPh);
print(node.mPt); }

下面是整个广义表操作的代码:

import java.util.Stack;

/**
* 广义表操作:
* 1、广义表的构造 :
* 1.1 构造一个空的广义表
* 1.2 根据现有的广义表,构造一个新的广义表
* 1.3 根据广义表字符串构造一个广义表
* 2、广义表的深度
* 3、广义表的长度
* 4、按照深度优先顺序打印广义表
* 5、求广义表表头
* 6、求广义表表尾
*
*/
public class GeneralizedTable { public static final int TAG_ITEM = 0; // 原子节点
public static final int TAG_TABLE = 1; // 表节点
/*
* 广义表支持的符号包括'(' , ')' , '{' , '}' , '[' , ']'
* 广义表表示符号,使用字符串构造广义表时第一个字符必须是'(', '{' , '[' 之一 并以')' , '}' , ']' 之一结束,
* 并且各符号相对应
*/
private char mStartSymb = '(';
private char mEndSymb = ')';
private Node mGenTable; public GeneralizedTable() {
mGenTable = new Node(null, null, TAG_TABLE, null);
} // 使用广义表 src 构造一个新的广义表
public GeneralizedTable(GeneralizedTable src) {
if (src != null) {
mGenTable = src.mGenTable;
} } /**
* @param genTable
*/
public GeneralizedTable(String genTable) {
if (genTable == null) {
throw new NullPointerException(
"genTable is null in constructor GeneralizedTable!...");
}
initTable(genTable);
} private void initTable(String genTable) {
String ts = genTable.replaceAll("\\s", "");
int len = ts.length();
Stack<Character> symbStack = new Stack<Character>();
Stack<Node> nodeStck = new Stack<Node>();
initSymbolicCharactor(ts);
mGenTable = new Node(null, null, TAG_TABLE, null);
Node itemNode, tableNode = mGenTable, tmpNode;
for (int i = 0; i < len; i++) {
if (ts.charAt(i) == mStartSymb) {
tmpNode = new Node(null, null, TAG_TABLE, null);
// tableNode = tableNode.mPt;
symbStack.push(ts.charAt(i));
if (symbStack.size() > 1) {
nodeStck.push(tableNode);
tableNode.mPh = tmpNode;
tableNode = tableNode.mPh;
} else {
tableNode.mPt = tmpNode;
tableNode = tableNode.mPt;
}
} else if (ts.charAt(i) == mEndSymb) {
if (symbStack.isEmpty()) {
throw new IllegalArgumentException(
"IllegalArgumentException in constructor GeneralizedTable!...");
}
if (symbStack.size() > 1) {
tableNode = nodeStck.pop();
}
symbStack.pop();
} else if (ts.charAt(i) == ',') {
tableNode.mPt = new Node(null, null, TAG_TABLE, null);
tableNode = tableNode.mPt;
} else {
itemNode = new Node(null, null, TAG_ITEM, ts.charAt(i));
tableNode.mPh = itemNode;
}
} if (!symbStack.isEmpty()) {
throw new IllegalArgumentException(
"IllegalArgumentException in constructor GeneralizedTable!...");
}
} private void initSymbolicCharactor(String ts) {
mStartSymb = ts.charAt(0);
switch (mStartSymb) {
case '(':
mEndSymb = ')';
break;
case '{':
mEndSymb = '}';
break;
case '[':
mEndSymb = ']';
break;
default:
throw new IllegalArgumentException(
"IllegalArgumentException ---> initSymbolicCharactor");
}
} public void print() {
print(mGenTable);
} private void print(Node node) {
if (node == null) {
return;
}
if (node.mTag == 0) {
System.out.print(node.mData.toString() + " \t");
}
print(node.mPh);
print(node.mPt); } public int depth() { // 广义表的深度
if (mGenTable == null) {
throw new NullPointerException("Generalized Table is null !.. ---> method depth");
}
return depth(mGenTable);
} private int depth(Node node) {
if (node == null || node.mTag == TAG_ITEM) {
return 0;
}
int depHeader = 0, depTear = 0;
depHeader = 1 + depth(node.mPh);
depTear = depth(node.mPt);
return depHeader > depTear ? depHeader : depTear;
} public int length() { // 广义表的长度
if (mGenTable == null || mGenTable.mPt == null) {
return -1;
}
int tLen = 0;
Node node = mGenTable;
while (node.mPt != null) {
node = node.mPt;
if (node.mPh == null && node.mPt == null) {
break;
}
tLen++;
}
return tLen;
} public GeneralizedTable getHeader() {
if (isEmpty())
return null;
Node node = mGenTable.mPt;
GeneralizedTable gt = new GeneralizedTable();
gt.mGenTable.mPt = node.mPh;
return gt;
} public GeneralizedTable getTear() {
if (isEmpty())
return null;
Node node = mGenTable.mPt;
GeneralizedTable gt = new GeneralizedTable();
gt.mGenTable.mPt = node.mPt;
return gt;
} public boolean isEmpty() {
if (mGenTable == null) {
return true;
}
Node node = mGenTable.mPt;
return node == null || node.mPh == null;
} public class Node {// 广义表节点
Node mPh; // 广义表的表节点
Node mPt; // 广义表表尾节点
int mTag; // mTag == 0 , 院子节点 ; mTag == 1 , 表节点 。
Object mData; // 广义表的数据值 public Node(Node ph, Node pt, int tag, Object data) {
mPh = ph;
mPt = pt;
mTag = tag;
mData = data;
}
} /**
* @param args
*/
public static void main(String[] args) {
// String tStr = "((),(a,b,c),a,d,((d,g,(c))),(k,g),c)";
String p = "((),a,b,(a,b,c),(a,(a,b),c))";
String p2 = "((()),2)";
// String space = "()";
String big = "{{a,b},{{a,g},{h},{a,n,f,{a,b,c}}},c}";
String middle = "[[p],[[d,f,[g]]],[h],[2]]";
GeneralizedTable gTab = new GeneralizedTable(middle);
// GeneralizedTable header, tear;
// // gTab.print();
// // System.out.println();
System.out.println("length: " + gTab.length());
System.out.println("depth: " + gTab.depth());
//
// header = gTab.getHeader();
// if (header != null) {
// System.out.println("header: ");
// header.print();
// }
// tear = gTab.getTear();
//
// if (tear != null) {
// System.out.println("tear: ");
// tear.print();
// }
// gTab.print();
// System.out.println();
// GeneralizedTable gTab4 = null;
// GeneralizedTable gTab2 = new GeneralizedTable(gTab4);
// gTab2.print();
// gTab2 = new GeneralizedTable(gTab);
// gTab2.print();
} }

广义表的内容就先写到这里 , 后续有新内容再补充 。

广义表操作 (ava实现)——广义表深度、广义表长度、打印广义表信息的更多相关文章

  1. CoreData多表操作.

    这次给大家带来的是CoreData多表操作的使用. 首先我们要对CoreData来进行多表操作我们先要创建至少两个实体在工程中. 在创建完成这两个对应的工程实体文件和工程中的类文件后我们现在需要创建一 ...

  2. 数据库 -- mysql表操作

    一,存储引擎介绍 存储引擎即表类型,mysql根据不同的表类型会有不同的处理机制 详见:https://www.cnblogs.com/peng104/p/9751738.html 二,表介绍 表相当 ...

  3. 数据库_mysql多表操作

    多表操作        实际开发中,一个项目通常需要很多张表才能完成.例如:一个商城项目就需要分类表(category).商品表(products).订单表(orders)等多张表.且这些表的数据之间 ...

  4. Hive 基本语法操练(一):表操作

    Hive 和 Mysql 的表操作语句类似,如果熟悉 Mysql,学习Hive 的表操作就非常容易了,下面对 Hive 的表操作进行深入讲解. **(1)先来创建一个表名为student的内部表** ...

  5. Django-website 程序案例系列-18 多表跨表操作优化

    详解Django的 select_related 和 prefetch_related 函数对 QuerySet 查询的优化 在数据库有外键的时候,使用 select_related() 和 pref ...

  6. Mysql常用表操作 | 单表查询

    160905 常用表操作 1. mysql -u root -p 回车 输入密码   2. 显示数据库列表 show databases     3. 进入某数据库 use database data ...

  7. Sql Server系列:数据表操作

    表是用来存储数据和操作数据的逻辑结构,用来组织和存储数据,关系数据库中的所有数据都表现为表的形式,数据表由行和列组成.SQL Server中的数据表分为临时表和永久表,临时表存储在tempdb系统数据 ...

  8. MySQL连表操作之一对多

    引入 当我们在数据库中创建表的时候,有可能某些列中值内容量很大,而且重复. 例子:创建一个学生表,按学校年纪班级分,表的内容大致如下: id name partment 1 xxx x学校x年级x班级 ...

  9. 学习MySQL之单表操作(二)

    ##单表操作 ##创建表 CREATE TABLE t_employee( empno ), ename ), job ), MGR ), Hiredate DATE DEFAULT '0000-00 ...

随机推荐

  1. 【Unity笔记】第三人称相机跟随

    第三人称,摄像机跟在角色后上方. void Update () { myCamera.position = transform.position + , ); myCamera.LookAt(tran ...

  2. HTML(三):表单元素

    表单元素概述 表单(Form),用于收集用户信息.提交用户请求等处理过程        1.设计表单,并放入一些输入域        2.网站访问者在自己的计算机上填写上述输入域,并提交到服务器端   ...

  3. 1​1​.​0​5​9​2​M​晶​振​与12M晶振

    标准的51单片机晶振是1.2M-12M,一般由于一个机器周期是12个时钟周期,所以先12M时,一个机器周期是1US,好计算,而且速度相对是最高的(当然现在也有更高频率的单片机). 11.0592M是因 ...

  4. json_decode() expects parameter 1 to be string, object given

    $data = Weann\Socialite\Facades\Socialite::driver('wechat')->user();//是字符串 $data=json_encode($dat ...

  5. ASP.NET实现类似Excel的数据透视表

    代码: /Files/zhuqil/Pivot.zip 数据透视表提供的数据三维视图效果,在Microsoft Excel能创建数据透视表,但是,它并不会总是很方便使用Excel.您可能希望在Web应 ...

  6. C++中前置声明的应用与陷阱

    前置声明的使用 有一定C++开发经验的朋友可能会遇到这样的场景:两个类A与B是强耦合关系,类A要引用B的对象,类B也要引用类A的对象.好的,不难,我的第一直觉让我写出这样的代码: // A.h #in ...

  7. 关于ARM中的tst、cmp、bne、beq指令

    一.关于cmp的详细用法 假设现在AX寄存器中的数是0002H,BX寄存器中的数是0003H. 执行的指令是:CMP AX, BX 执行这条指令时,先做用AX中的数减去BX中的数的减法运算. 列出二进 ...

  8. 详解JNDI的lookup资源引用 java:/comp/env

    ENC的概念:     The application component environment is referred to as the ENC, the enterprise naming c ...

  9. unity3d绘画手册-------地形高度调节

    高度 所有地形 (terrain) 编辑工具的使用都很简单.您可以在场景视图 (scene view)中逐步绘制地形 (terrain).对于高度工具和其他所有工具,您只需选中工具,然后在场景视图 ( ...

  10. 【MongoDB】数组长度查询

    db.groupedInfo.count({'surveyInfo.surveyAndUserID.0':{$exists:1}})