广义表基础定理概念
- 广义表是一种线性存储结构,既可以储存不可再分的元素,也可以存储广义表,LS = (a1,a2,…,an),其中,LS 代表广义表的名称,an 表示广义表存储的数据,广义表中每个 ai 既可以代表单个元素,也可以代表另一个广义表。
- 以构建为主的思路里,一个括号认为是一组列表。就算是NULL括号,也需要作为tag=1的列表组
- 广义表中存储的单个元素称为 “原子”,而存储的广义表称为 “子表”。
例如 :广义表 LS = {1,{1,2,3}},则此广义表的构成 :广义表 LS 存储了一个原子 1 和子表 {1,2,3}。
tag=0,原子,tga=1是列表,单个原子的存放也是需要首先列表1存放3地址,单个原子是atom两个地址
广义表存储数据的一些常用形式:
A = ():A 表示一个广义表,只不过表是空的。
B = (e):广义表 B 中只有一个原子 e。
C = (a,(b,c,d)) :广义表 C 中有两个元素,原子 a 和子表 (b,c,d)。
D = (A,B,C):广义表 D 中存有 3 个子表,分别是A、B和C。这种表示方式等同于 D = ((),(e),(b,c,d)) 。
E = (a,E):广义表 E 中有两个元素,原子 a 和它本身。这是一个递归广义表,等同于:E = (a,(a,(a,…)))。
当广义表不是空表时,称第一个数据(原子或子表)为"表头",剩下的数据构成的新广义表为"表尾"。
除非广义表为空表,否则广义表一定具有表头和表尾,且广义表的表尾一定是一个广义表。
tag 标记位、hp 指针和 tp 指针。
tag 标记位用于区分此节点是原子还是子表,通常原子的 tag 值为 0,子表的 tag 值为 1;
子表节点中的 hp 指针用于连接本子表中存储的原子或子表;
tp 指针用于连接广义表中下一个原子或子表。
广义表结构体
typedef struct GNode{
int tag; // 标志域, 0表示原子, 1表示子表
union{
char atom; // 原子结点的值域
struct{
struct GNode * hp, *tp;
}ptr; // 子表结点的指针域, hp指向表头, tp指向表尾
}subNode;
}GLNode, *Glist;
广义表一级表达
a和bcd作为两个链表组。链表a是单原子而不是有括号的链表标记,所以a单个原子拉下来,bcd是链表组,那么就是链表组下来展开,单原子接着链表下来就行。常用版
广义表二级表达
另一种存储结构的原子的节点也由三部分构成,分别是 : tag 标记位、原子值和 tp 指针构成;表示子表的节点由三部分构成,分别是 : tag 标记位、hp 指针和 tp 指针,就没有那么多的迭代,直接使用。
typedef struct GNode {
int tag; // 标志域, 0表示原子, 1表示子表
union {
int atom; // 原子结点的值域
struct GNode* hp; // 子表结点的指针域, hp指向表头
}subNode;
struct GNode* tp; // 这里的tp相当于链表的next指针, 用于指向下一个数据元素
}GLNode, *Glist;
长度是指包含数据元素的个数,深度是括号数量
代码实现
广义表的复制思想 : 任意一个非空广义表来说,都是由两部分组成:表头和表尾。反之,只要确定的一个广义表的表头和表尾,那么这个广义表就可以唯一确定下来。因此复制一个广义表,也是不断的复制表头和表尾的过程。如果表头或者表尾同样是一个广义表,依旧复制其表头和表尾。
复制广义表的过程,其实就是不断的递归复制广义表中表头和表尾的过程,递归的出口有两个:
如果当前遍历的数据元素为空表,则直接返回空表。
如果当前遍历的数据元素为该表的一个原子,那么直接复制,返回即可
// 广义表的复制, C为复制目标广义表,*T为指向复制后的广义表
void copyGlist(Glist C, Glist *T){
// 如果C为空表,那么复制表直接为空表
if (!C) {
*T=NULL;
}
else{
*T=(Glist)malloc(sizeof(GNode)); // C不是空表,给T申请内存空间
// 申请失败,程序停止
(*T)->tag=C->tag; // 复制表C的tag值
// 判断当前表元素是否为原子,如果是,直接复制
if (C->tag==0) {
(*T)->atom=C->atom;
}else{ //运行到这,说明复制的是子表
copyGlist(C->ptr.hp, &((*T)->ptr.hp)); //复制表头
copyGlist(C->ptr.tp, &((*T)->ptr.tp)); //复制表尾
}
}
}
#include<bits/stdc++.h>
using namespace std;
typedef struct node{
int tag; //用于识别单元素与子表
union //大括号中多选一
{
char data; //单元素
struct node* child; //子表
}val;
struct node* next; //指向下一个元素
}GLNode;
GLNode* create(char*& elem) {
GLNode* L;
char c = *elem++;
if (c != '\0') {
L = (GLNode*)malloc(sizeof(GLNode));
if (c == '(') {
L->tag = 1;
L->val.child = create(elem);
}
else if (c == ')') {
L = NULL;
}
else if (c == NULL) {
L->val.child = NULL;
}
else {
L->tag = 0;
L->val.data = c;
}
}
else L = NULL;
c = *elem++ ;
if (L != NULL) {
if (c == ',')L->next = create(elem);
else L->next = NULL;
}
return L;
}
void Print(GLNode* s)
{
if (s != NULL) //如果L不为空
{
if (s->tag == 0) //如果元素是原子
printf("%c", s->val.data); //打印数值
else
{
printf("("); //是子表打印'('
if (s->val.child == NULL) //如果是空表,则打印'#'
printf("'\0'");
else //否则递归输出广义表
{
Print(s->val.child);
}
printf(")");
}
if (s->next != NULL) //广义表是否为遍历完毕
{
printf(","); //打印','
Print(s->next); //递归输出广义表
}
}
}
int Getlength(GLNode* p) {
int num = 0;
p = p->val.child;
while (p) {
num++;
p = p->next;
}
printf("%d", num);
}
int getheight(GLNode* s) {
int num = 1, k;
if (s->tag == 0) {
return 0;
}
if (s == NULL) {
return 1;
}
GLNode* p;
p = s;
while (p) {
k = getheight(p->val.child);
if (k > num)num = k;
p = p->next;
}
printf("%d", num+1);
}
int countc = 0;
int Number(GLNode* s) {
GLNode* p;
p = s;
if (p == NULL) return 0;
if (p->tag == 1) {
Number(p->val.child);
}
if (p->tag == 0) {
countc++;
}
if (p->next != NULL) {
p = p->next;
Number(p);
}
else {
return countc;
}
}