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

广义表定义:

广义表是由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. Android——单例模式

    详细的各种模式 http://mobile.51cto.com/android-419145.htm http://wenku.baidu.com/link?url=f3yjQ6YvslvHcWJLb ...

  2. HDFS入门

    HDFS入门 欢迎关注我的个人博客:http://www.cnblogs.com/yjd_hycf_space 更多大数据以及编程相关的精彩文章 为什么我们需要HDFS 文件系统由三部分组成:与文件管 ...

  3. StarRTC , AndroidThings , 树莓派小车,公网环境,视频遥控(二)小车端

    原文地址:http://blog.starrtc.com/?p=94 1 创建工程IDE:Android Studio 3.1:File>New>New Project>输入项目名& ...

  4. 搭建Maven环境——使用本地的maven环境

    1.安装JDK. 2.Maven是 Apache 下的一个项目,官网下载 Maven:http://maven.apache.org/download.cgi 系统变量:M2_HOME= G:\vis ...

  5. java.lang.UnsatisfiedLinkError: No implementation found for int com.xxx.xx中的couldn’t find “XX.so”或loadLibrary("xxx")失败

    我觉得这是个神坑,虽然早几年网上就很多po出来的解决方式,但是同样的问题,我的bug却稳如泰山,一点用都没有,好气 下面总结一下 这里前面先是有个系统打印信息 I/System.out: loadLi ...

  6. C# - 简单介绍TaskScheduler

    task Scheduler根据定义 The task Scheduler by the definition blurb. “Is the class where the usage context ...

  7. 7 款灵巧实用的 CSS3/jQuery 工具

    作为 Web 前端开发者,应该对 jQuery 比较熟悉,对免费开源的 jQuery 也用的非常多.但是随着 CSS3 标准的诞生和发展,很多 jQuery 插件也都纷纷应用了 CSS3 新标准,也因 ...

  8. Qt中的串口编程之一

    QtSerialPort 简介 功能介绍 SerialPort SerialPortInfo 源代码 编译和安装 配置编译环境 Perl只是在Qt5的时候才需要Qt4的情况下可以不配置 使用如下推荐步 ...

  9. 《FPGA全程进阶---实战演练》第三章之PCB叠层

    1.双面板 在双层板设计layout时,最好不要不成梳状结构,因为这样构成的电路,回路面积较大,但是只要对较重要的信号加以地保护,布线完成之后将空的地方敷上地铜皮,并在多个过孔将两个地连接起来,可以弥 ...

  10. C++ 模板类友元之输出流操作符重载

    几个关键点: 需要前置声明!--奇怪的是别人告诉我也可以不需要,但我这里不行! 友元函数的函数名后面的<>,必须要有. #include <stdio.h> #include ...