广义表——LISP的基石

news2025/1/21 8:45:21

        线性表中存放的是同一类型的元素,而广义表是线性表的推广,即广义表中除包含类型相同的元素外,还可以包含具有其自身结构的元素。在人工智能领域使用十分广泛的 LISP语言中,广义表是一种基本数据类型,LISP 语言中的数据和函数都是采用符号表达式定义的,这种符号表达式就是广义表。

广义表的定义及表示

        广义表(Generalized Table)是n(n>=0)个元素的有限序列,表示为 gt =(a1,a2,...,an),其中每一个元素 ai 或者是原子,或者是一个广义表,n 为 gt 的长度,称为表长原子为广义表中不可再分的数据元素,gt 中的广义表称为 gt 的子表。
        广义表的书面表示方法是将所有元素包含在一对圆括号中,元素之间用逗号分隔,并规定用大写英文字母表示广义表,用小写英文字母表示原子。若广义表为空(n=0),则表示广义表中没有任何元素,表示为 “()” ;若广义表 gt 非空,则称第一个元素 a1 为 gt 的表头,其余元素组成的表(a2,a3,...,an) 称为  gt 的表尾。显然,表头可能是原子,也可能是一个广义表,但表尾一定是广义表。
        子表中的元素也可以是广义表,这样使得广义表一般呈现层次结构(递归广义表除外),类似于树形结构,子表嵌套的最大层次称为广义表的深度,广义表的深度也可以看成广义表的括号表示中括号嵌套的最大次数。

【例】各种类型的广义表的表长、表头、表尾与表的深度

A =():空表,表长为0,表头为空(原子),表尾为空表,深度为0。
B=(a,b,c):表长为3,表头为原子a,表尾为(b,c),其三个元素都为原子,退化为线性表,表的深度为 1。
C=((a,b),c,(d,e,t)):表长为3,表头为广义表(a,b),表尾为(c,(d,e,t)),表的深度为2。
D=(a,D):具有递归特性的广义表,称为递归广义表,即广义表以自己作为子表,相当于D=(a,(a,(a,……)),表的深度为无穷大。如果在广义表的子表中以当前广义表作为自己的子表,如D=(a,(b,D)),这类广义表也是递归广义表,与间接递归对应,可以称为间接递归广义表。如果广义表的子表是递归的,则该广义表也是递归的。

(为了区分,图中的有向单线表示指向下一个结点的指针(next),有向双线表示指向子表的指针(link))

          通常用带头结点的链表表示广义表。由于链表中的结点可能为原子,也可能为子表,因此在结点中需要加一个标志 tag标明该结点的类型,并规定:
         (1)当tag 为false 时,结点为原子;
         (2)当tag 为true时,结点为子表。

#include<iostream>
using namespace std;
typedef char datatype;

typedef struct gtNode {
	bool tag; //tag为false,表示原子,tag为true,表示子表
	/*
		为了有效的利用存储空间,在广义表的类型定义中用一个共用体ele存放结点的元素,
		当tag=false时,ele存放的是原子的值(data);
		当tag=true 时,ele存放的子表的头结点(link)。
		即data和link二选一。
	*/
	union {
		datatype data;
		gtNode* link;
	}ele;
	gtNode* next;
	gtNode() :tag(false),next(NULL){
		ele.data = '\0';
		ele.link = NULL;
	};
}*gTable;

//广义表中插入结点操作
// 利用以下两个函数在广义表插入结点的顺序是从后往前插入
// 如果元素为子表,则自底向上创建临时表
//在结点gt的后面插入一个原子,原子的值为x
void gt_insert(gTable& gt, datatype x) {
	if (gt == NULL) {
		gt = new gtNode;
	}
	gTable tmp = new gtNode;
	tmp->ele.data = x;
	tmp->next = gt->next; //tmp->tag默认为false
	gt->next = tmp;
}

//在结点gt的后面插入一个子表gt1
void gt_insert(gTable& gt, gTable gt1) {
	if (gt == NULL) gt = new gtNode;
	gTable tmp = new gtNode; //定义子表的头结点
	tmp->tag = true, tmp->ele.link = gt1;
	tmp->next = gt->next; //将tmp插入gt的后面
	gt->next = tmp;
}

//遍历广义表(但不适合递归广义表,会出现死循环)
void gt_traverse(gTable gt) {
	gt = gt->next;
	while (gt != NULL) {
		if (!gt->tag)cout << gt->ele.data << " ";//输出原子
		else {
			cout << endl << "子表:";
			gt_traverse(gt->ele.link);
			cout << endl;
		}
		gt = gt->next;
	}
}

//判断两个广义表是否相等
//判断两个子表是否相同
bool gt_equal(gTable gt1, gTable gt2) {
	gt1 = gt1->next, gt2 = gt2->next;
	if (gt1 == NULL && gt2 == NULL)return true; 
	if (gt1 == NULL || gt2 == NULL)return false;

	if (gt1->tag != gt2->tag) return false;

	if (gt1->tag == false) {
		if (gt1->ele.data == gt2->ele.data)
			return gt_equal(gt1, gt2);
		else
			return false;
	}
	else //当前结点都为子表,则比较子表
		return gt_equal(gt1->ele.link, gt2->ele.link);
}

int main()
{
	gTable gt = NULL, gt1 = NULL, gt2 = NULL; //gt为表的头指针
	gt_insert(gt1, 'f'), gt_insert(gt1, 'e'), gt_insert(gt1, 'd'); //创建广义表gt1=(d,e,f);
	gt_insert(gt, gt1); //将gt1插入gt中
	gt_insert(gt, 'c'); //在gt的开始位置插入一个值为c的原子
	gt_insert(gt2, 'b'); 
	gt_insert(gt2, 'a');//创建广义表gt2=(a,b)
	gt_insert(gt, gt2); //将gt2插入gt的开始位置

	gt_traverse(gt);
	gt_traverse(gt1);
	gt_traverse(gt2);
}

        广义表的功能相当强大,使用也比较灵活,它可以兼容线性表、矩阵、树和有向图等各种常用的数据结构:当广义表中的元素都为原子时,就是一个线性表;当将矩阵的每一行作为子表时,就可以用广义表表示矩阵;非递归广义表可以看成一棵树;任何一个广义表都可以看成一个图。后面介绍的针对树和图的操作及算法基本都适用于广义表。

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/151868.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Vue3案例-todoMVC-pinia版 (可跟做练手)

列表展示功能 &#xff08;1&#xff09; 在main.js中引入pinia import { createApp } from vue import App from ./App.vue import { createPinia } from pinia import ./styles/base.css import ./styles/index.cssconst pinia createPinia() createApp(App).use(pinia).m…

Spring源码学习~11、Bean 的加载步骤详解(二)

Bean 的加载步骤详解&#xff08;二&#xff09; 一、循环依赖 1、什么是循环依赖 循环依赖就是循环引用&#xff0c;即两个或多个 bean 互相之间持有对方&#xff0c;如下图&#xff1a; 循环引用不是循环调用&#xff0c;循环调用是方法之间的环调用&#xff0c;循环调用是…

谷粒学院——Day18【权限管理Spring Security、配置中心Nacos、代码托管git】

❤ 作者主页&#xff1a;欢迎来到我的技术博客&#x1f60e; ❀ 个人介绍&#xff1a;大家好&#xff0c;本人热衷于Java后端开发&#xff0c;欢迎来交流学习哦&#xff01;(&#xffe3;▽&#xffe3;)~* &#x1f34a; 如果文章对您有帮助&#xff0c;记得关注、点赞、收藏、…

Linux搭建Gitlab保姆级教程

文章目录1、gitlab安装1.1、gitlab介绍1.1.1、概念1.1.2、gitlab与github的区别1.1.3、gitlab的优势1.1.4、gitlab主要服务构成1.1.5、gitlab的工作流程1.2、准备工作1.3、安装1.4、配置1.5、启动1.6、测试2、gitlab安装目录3、gitlab常用命令4、注册账号5、gitlab相关设置5.1、…

上半年要写的博客文章23

上半年要写的博客文章21 这里写自定义目录标题欢迎使用Markdown编辑器新的改变功能快捷键合理的创建标题&#xff0c;有助于目录的生成如何改变文本的样式插入链接与图片如何插入一段漂亮的代码片生成一个适合你的列表创建一个表格设定内容居中、居左、居右SmartyPants创建一个…

ArcGIS基础实验操作100例--实验76按格网统计点要素

本实验专栏参考自汤国安教授《地理信息系统基础实验操作100例》一书 实验平台&#xff1a;ArcGIS 10.6 实验数据&#xff1a;请访问实验1&#xff08;传送门&#xff09; 高级编辑篇--实验76 按格网统计点要素 目录 一、实验背景 二、实验数据 三、实验步骤 &#xff08;1&…

java EE 初阶 — CAS 的介绍

文章目录CAS1. 什么是 CAS2. CAS 是怎么实现的3. CAS 有哪些应用3.1 实现原子类3.2 实现自旋锁4. CAS 的 ABA 问题4.1 什么是 ABA 问题4.2 ABA 问题引来的 BUG4.3 解决方案5. 相关面试题CAS 1. 什么是 CAS CAS&#xff1a;全称 Compare and swap&#xff0c;字面意思&#xff…

设计模式——工厂方法模式

文章目录1. 工厂方法模式的定义2. 工厂方法模式的类图3. 工厂方法模式的作用4. 工厂方法模式的实现1. 工厂方法模式的定义 定义了一个创建对象的接口&#xff0c;但由子类决定要实例化的类是哪一个。工厂方法让类把实例化推迟到子类。 2. 工厂方法模式的类图 3. 工厂方法模式…

[教程]一文搞懂STM32使用DHT11采集温湿度

1、DHT11简介 DHT11数字温湿度传感器是一款含有已校准数字信号输出的温湿度复合传感器。它应用专用的数字模块采集技术和温湿度传感技术&#xff0c;确保产品具有极高 的可靠性与卓越的长期稳定性。传感器包括一个电阻式感湿元件和一个NTC测 温元件&#xff0c;并与一个高性能8…

GO语言基础-08-内建函数-make()、new()

文章目录1. make1.1 概述1.2 示例&#xff08;make切片&#xff09;1.3 示例&#xff08;make map&#xff09;1.4 示例&#xff08;make 通道&#xff09;2. new2.1 概念2.2 示例&#xff08;new 切片&#xff09;2.3 示例&#xff08;new和make对比&#xff09;2.4 示例&…

Java基础算法每日5道详解(2)

83. Remove Duplicates from Sorted List 从排序列表中删除重复项 Given the head of a sorted linked list, delete all duplicates such that each element appears only once. Return the linked list sorted as well. Example 1: Input: head [1,1,2] Output: [1,2]Exa…

20230109测试ToyBrick的RK3588开发板运行Buildroot的V20220811版本

20230109测试ToyBrick的RK3588开发板运行Buildroot的V20220811版本 2023/1/9 14:25 开发板&#xff1a;Toybrick的TB-RK3588X开发板 SDK&#xff1a;RK3588_LINUX_20220811\rk3588-linux-20220811.tar.gz_06 H:\BaiduNetdiskDownload\RK3588_LINUX_20220811 rk3588-linux-2022…

【SQLyog错误号码2058解决办法】

当你遇到下图这个错误时&#xff0c;是由于SQLyog在8.0以上版本采用了新的加密方式。 解决办法&#xff1a; win R打开 &#xff0c; 输入cmd&#xff0c;打开命令行窗口&#xff0c; 然后连接你的SQLyog版本的服务器&#xff0c; mysql -uroot -P3306 -p注意&#xff1a;…

【Kotlin】数字类型 ( 安全转换函数 | 浮点型转整型 )

文章目录一、安全转换函数二、浮点型转整型一、安全转换函数 在 Kotlin 中 , 将 字符串 String 类型 转为 数字类型 , 如果 字符串 代表的数字类型 与 要换转的 数字类型 不匹配 , 就会出异常 ; 如 : 执行如下代码 , 就会报异常 ; 字符串内容是 0.5 , 显然是一个 Double 类…

Kotlin Flow响应式编程,StateFlow和SharedFlow

本文同步发表于我的微信公众号&#xff0c;扫一扫文章底部的二维码或在微信搜索 郭霖 即可关注&#xff0c;每个工作日都有文章更新。 大家好&#xff0c;今天是Kotlin Flow响应式编程三部曲的最后一篇。 其实回想一下我写这个Kotlin Flow三部曲的初衷&#xff0c;主要还是因为…

基于瑞芯微平台cif接口dvp相机的视频接入(ov2640、rv1126为例)

基于瑞芯微平台cif接口dvp相机的视频接入&#xff08;ov2640、rv1126为例&#xff09;名词定义视频格式sensor与ispI2CXCLK行场同步信号DATA抓图名词定义 CIF&#xff0c;指RK芯片中的VIP模块&#xff0c;用以接收Sensor数据并保存到Memory中&#xff0c;仅转存数据&#xff0c…

Komo 综合资产收集和漏洞扫描工具

前言 因工作中的需要&#xff0c;开发了这款综合资产收集和漏洞扫描工具&#xff0c;方便在工作中各方面的收集资产和漏洞扫描&#xff0c;同时也可用于挖洞。 Komo已经在工作中辅助我挖到过一些漏洞&#xff0c;同时轻便了我资产收集的过程。 Komo is a comprehensive asset c…

【图像处理OpenCV(C++版)】——3.3 几何变换之极坐标变换

前言&#xff1a; &#x1f60a;&#x1f60a;&#x1f60a;欢迎来到本博客&#x1f60a;&#x1f60a;&#x1f60a; &#x1f31f;&#x1f31f;&#x1f31f; 本专栏主要结合OpenCV和C来实现一些基本的图像处理算法并详细解释各参数含义&#xff0c;适用于平时学习、工作快…

MATLAB | 如何从热图中提取数据

这期做了个可能有用的小工具&#xff0c;一般论文中热图很少给出数据&#xff0c;于是就想写个小工具通过热图上的颜色估计出数据值来&#xff0c;目前写了个初版的工具分享给大家&#xff01; 工具函数 由于只是初版&#xff0c;要手动改的地方还是不少的&#xff0c;要设置…

PHP多商户AI智能在线客服系统源码 机器人自动回复 即时通讯聊天系统源码

一套智能在线客服系统源码 多商户网页客服系统源码 支持二十种国际语言 带机器人自动回复。 框架&#xff1a;Thinkphp5workerman&#xff0c; 环境&#xff1a;nginxphp7.3mysql5.6 支持H5公众号APP小程序 了解更多可私信我&#xff01; 系统功能&#xff1a; 1、支持国际…