广义表数据实现

广义表基础定理概念

  • 广义表是一种线性存储结构,既可以储存不可再分的元素,也可以存储广义表,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;
	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

磊哥哥讲算法

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值