/* 广义表的头尾链表存储表示 */typedef enum{ATOM,LIST}ElemTag; /* ATOM==0:原子,LIST==1:子表 */typedef struct GLNode{ElemTag tag; /* 公共部分,用于区分原子结点和表结点 */union /* 原子结点和表结点的联合部分 */{AtomType atom; /* atom是原子结点的值域,AtomType由用户定义 */struct{struct GLNode *hp,*tp;}ptr; /* ptr是表结点的指针域,prt.hp和ptr.tp分别指向表头和表尾 */}a;}*GList,GLNode; /* 广义表类型 */

下图是根据上方程序定义的广义表(a,(b,c,d))的存储结构。它的长度为 2,第 1 个元素为原子 a,第 2 个元素为子表(b,c,d)。

完整代码:

下面代码中广义表的书写形式串为SString类型,广义表的书写形式串为HString类型的请转看:https://blog.csdn.net/qq_42185999/article/details/105670495

typedef int Status; /* Status是函数的类型,其值是函数结果状态代码,如OK等 */
typedef int Boolean; /* Boolean是布尔类型,其值是TRUE或FALSE */#include<malloc.h> /* malloc()等 */
#include<stdio.h> /* EOF(=^Z或F6),NULL */
#include<process.h> /* exit() */
#include<limits.h> //常量INT_MAX和INT_MIN分别表示最大、最小整数/* 函数结果状态代码 */
#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0
#define INFEASIBLE -1
#define OVERFLOW -2 typedef char AtomType; /* 定义原子类型为字符型 *//* ---------------------------------  广义表的头尾链表存储表示    --------------------------------*/typedef enum { ATOM, LIST }ElemTag; /* ATOM==0:原子,LIST==1:子表 */
typedef struct GLNode
{ElemTag tag; /* 公共部分,用于区分原子结点和表结点 */union /* 原子结点和表结点的联合部分 */{AtomType atom; /* atom是原子结点的值域,AtomType由用户定义 */struct{struct GLNode *hp, *tp;}ptr; /* ptr是表结点的指针域,prt.hp和ptr.tp分别指向表头和表尾 */}a;
}*GList, GLNode; /* 广义表类型 *//* ---------------------------------------------------------------------------------------------*//* ---------------------------  广义表的头尾链表存储的基本操作(11个)  --------------------------*/Status InitGList(GList *L)
{ /* 创建空的广义表L */*L = NULL;return OK;
}void DestroyGList(GList *L) /* 广义表的头尾链表存储的销毁操作 */
{ /* 销毁广义表L */GList q1, q2;if (*L){if ((*L)->tag == ATOM){free(*L); /* 删除原子结点 */*L = NULL;}else /* 删除表结点 */{q1 = (*L)->a.ptr.hp;q2 = (*L)->a.ptr.tp;free(*L);*L = NULL;DestroyGList(&q1);DestroyGList(&q2);}}
}Status CopyGList(GList *T, GList L)
{ /* 采用头尾链表存储结构,由广义表L复制得到广义表T。算法5.6 */if (!L) /* 复制空表 */*T = NULL;else{*T = (GList)malloc(sizeof(GLNode)); /* 建表结点 */if (!*T)exit(OVERFLOW);(*T)->tag = L->tag;if (L->tag == ATOM)(*T)->a.atom = L->a.atom; /* 复制单原子 */else{CopyGList(&((*T)->a.ptr.hp), L->a.ptr.hp);/* 复制广义表L->ptr.hp的一个副本T->ptr.hp */CopyGList(&((*T)->a.ptr.tp), L->a.ptr.tp);/* 复制广义表L->ptr.tp的一个副本T->ptr.tp */}}return OK;
}int GListLength(GList L)
{ /* 返回广义表的长度,即元素个数 */int len = 0;if (!L)return 0;if (L->tag == ATOM)return 1;while (L){L = L->a.ptr.tp;len++;}return len;
}int GListDepth(GList L)
{ /* 采用头尾链表存储结构,求广义表L的深度。算法5.5 */int max, dep;GList pp;if (!L)return 1; /* 空表深度为1 */if (L->tag == ATOM)return 0; /* 原子深度为0 */for (max = 0, pp = L; pp; pp = pp->a.ptr.tp){dep = GListDepth(pp->a.ptr.hp); /* 求以pp->a.ptr.hp为头指针的子表深度 */if (dep > max)max = dep;}return max + 1; /* 非空表的深度是各元素的深度的最大值加1 */
}Status GListEmpty(GList L)
{ /* 判定广义表是否为空 */if (!L)return TRUE;elsereturn FALSE;
}GList GetHead(GList L)
{ /* 取广义表L的头 */GList h, p;if (!L){printf("空表无表头!\n");exit(0);}p = L->a.ptr.tp;L->a.ptr.tp = NULL;CopyGList(&h, L);L->a.ptr.tp = p;return h;
}GList GetTail(GList L)
{ /* 取广义表L的尾 */GList t;if (!L){printf("空表无表尾!\n");exit(0);}CopyGList(&t, L->a.ptr.tp);return t;
}Status InsertFirst_GL(GList *L, GList e)
{ /* 初始条件: 广义表存在 *//* 操作结果: 插入元素e作为广义表L的第一元素(表头,也可能是子表) */GList p = (GList)malloc(sizeof(GLNode));if (!p)exit(OVERFLOW);p->tag = LIST;p->a.ptr.hp = e;p->a.ptr.tp = *L;*L = p;return OK;
}Status DeleteFirst_GL(GList *L, GList *e)
{ /* 初始条件: 广义表L存在 *//* 操作结果: 删除广义表L的第一元素,并用e返回其值 */GList p;*e = (*L)->a.ptr.hp;p = *L;*L = (*L)->a.ptr.tp;free(p);return OK;
}void Traverse_GL(GList L, void(*v)(AtomType))
{ /* 利用递归算法遍历广义表L */if (L) /* L不空 */if (L->tag == ATOM) /* L为单原子 */v(L->a.atom);else /* L为广义表 */{Traverse_GL(L->a.ptr.hp, v);Traverse_GL(L->a.ptr.tp, v);}
}/* --------------------------------------------------------------------------------------------------*//* 广义表的书写形式串为SString类型 *//* ----------------------------------  串的定长顺序存储表示  -----------------------------------*/#define MAXSTRLEN 40 /* 用户可在255以内定义最大串长(1个字节) */
typedef char SString[MAXSTRLEN + 1]; /* 0号单元存放串的长度 *//* ---------------------------------------------------------------------------------------------*//* -------------------------  需要用到的串采用定长顺序存储结构的基本操作  ------------------------*/Status StrAssign(SString T, char *chars)
{ /* 生成一个其值等于chars的串T */int i;if (strlen(chars) > MAXSTRLEN)return ERROR;else{T[0] = strlen(chars);for (i = 1; i <= T[0]; i++)T[i] = *(chars + i - 1);return OK;}
}Status StrCopy(SString T, SString S)
{ /* 由串S复制得串T */int i;for (i = 0; i <= S[0]; i++)T[i] = S[i];return OK;
}Status StrEmpty(SString S)
{ /* 若S为空串,则返回TRUE,否则返回FALSE */if (S[0] == 0)return TRUE;elsereturn FALSE;
}int StrCompare(SString S, SString T)
{ /* 初始条件: 串S和T存在 *//* 操作结果: 若S>T,则返回值>0;若S=T,则返回值=0;若S<T,则返回值<0 */int i;for (i = 1; i <= S[0] && i <= T[0]; ++i)if (S[i] != T[i])return S[i] - T[i];return S[0] - T[0];
}int StrLength(SString S)
{ /* 返回串的元素个数 */return S[0];
}Status ClearString(SString S)
{ /* 初始条件:串S存在。操作结果:将S清为空串 */S[0] = 0;/* 令串长为零 */return OK;
}Status SubString(SString Sub, SString S, int pos, int len)
{ /* 用Sub返回串S的第pos个字符起长度为len的子串。算法4.3 */int i;if (pos<1 || pos>S[0] || len<0 || len>S[0] - pos + 1)return ERROR;for (i = 1; i <= len; i++)Sub[i] = S[pos + i - 1];Sub[0] = len;return OK;
}/* -----------------------------------------------------------------------------------------------*/void sever(SString str, SString hstr) /* 算法5.8  SString是数组,不需引用类型 */
{ /* 将非空串str分割成两部分:hsub为第一个','之前的子串,str为之后的子串 */int n, k, i; /* k记尚未配对的左括号个数 */SString ch, c1, c2, c3;n = StrLength(str);StrAssign(c1, ",");StrAssign(c2, "(");StrAssign(c3, ")");SubString(ch, str, 1, 1);for (i = 1, k = 0; i <= n && StrCompare(ch, c1) || k != 0; ++i){ /* 搜索最外层的第一个逗号 */SubString(ch, str, i, 1);if (!StrCompare(ch, c2))++k;else if (!StrCompare(ch, c3))--k;}if (i <= n){SubString(hstr, str, 1, i - 2);SubString(str, str, i, n - i + 1);}else{StrCopy(hstr, str);ClearString(str);}
}Status CreateGList(GList *L, SString S) /* 算法5.7 */
{ /* 采用头尾链表存储结构,由广义表的书写形式串S创建广义表L。设emp="()" */SString sub, hsub, emp;GList p, q;StrAssign(emp, "()");if (!StrCompare(S, emp))*L = NULL; /* 创建空表 */else{*L = (GList)malloc(sizeof(GLNode));if (!*L) /* 建表结点 */exit(OVERFLOW);if (StrLength(S) == 1) /* S为单原子 */{(*L)->tag = ATOM;(*L)->a.atom = S[1]; /* 创建单原子广义表 */}else{(*L)->tag = LIST;p = *L;SubString(sub, S, 2, StrLength(S) - 2); /* 脱外层括号 */do{ /* 重复建n个子表 */sever(sub, hsub); /* 从sub中分离出表头串hsub */CreateGList(&p->a.ptr.hp, hsub);q = p;if (!StrEmpty(sub)) /* 表尾不空 */{p = (GLNode *)malloc(sizeof(GLNode));if (!p)exit(OVERFLOW);p->tag = LIST;q->a.ptr.tp = p;}} while (!StrEmpty(sub));q->a.ptr.tp = NULL;}}return OK;
}/* 主程序 */void visit(AtomType e)
{printf("%c ", e);
}void main()
{char p[80];SString t;GList l, m;InitGList(&l);InitGList(&m);printf("空广义表l的深度=%d l是否空?%d(1:是 0:否)\n", GListDepth(l), GListEmpty(l));printf("请输入广义表l(书写形式:空表:(),单原子:a,其它:(a,(b),b)):\n");gets(p);StrAssign(t, p);CreateGList(&l, t);printf("广义表l的长度=%d\n", GListLength(l));printf("广义表l的深度=%d l是否空?%d(1:是 0:否)\n", GListDepth(l), GListEmpty(l));printf("遍历广义表l:\n");Traverse_GL(l, visit);printf("\n复制广义表m=l\n");CopyGList(&m, l);printf("广义表m的长度=%d\n", GListLength(m));printf("广义表m的深度=%d\n", GListDepth(m));printf("遍历广义表m:\n");Traverse_GL(m, visit);DestroyGList(&m);m = GetHead(l);printf("\nm是l的表头,遍历广义表m:\n");Traverse_GL(m, visit);DestroyGList(&m);m = GetTail(l);printf("\nm是l的表尾,遍历广义表m:\n");Traverse_GL(m, visit);InsertFirst_GL(&m, l);printf("\n插入l为m的表头,遍历广义表m:\n");Traverse_GL(m, visit);printf("\n删除m的表头,遍历广义表m:\n");DestroyGList(&l);DeleteFirst_GL(&m, &l);Traverse_GL(m, visit);printf("\n");DestroyGList(&m);
}

运行结果:

广义表的头尾链表存储表示(第五章 P115 算法5.5,5.6,5.8)相关推荐

  1. (C语言!)广义表(头尾链表)的建立和输出

    s 零零散散花了近半天的时间,查看各种资料,总算是完成了头尾链表存储结构的广义表的建立以及一种输出. 第一次写一篇文章记录一下此时的思路,唉,免不了过两天就忘了! 一 ,首先,结构体的定义很常规. t ...

  2. 广义表的存储结构--头尾链表存储表示/扩展线性链表存储表示

    //广义表的存储结构 //1.头尾链表存储表示 typedef enum {ATOM,LIST} ElemTag;//0:原子,1:子表 typedef struct GLNode {     Ele ...

  3. 广义表的概念及存储表示

    文章目录 广义表的概念 广义表的特性 广义表的表头和表尾 广义表的链接存储表示 头尾表示法 扩展线性链表表示法 广义表的概念 广义表的定义:广义表是 n ( n ≥ 0 ) n\ (n≥0) n (n ...

  4. C语言——数据结构之广义表(概念及其存储结构)

    前言 本节我们来说说C语言中的广义表.主要介绍广义表的概念定义,并说明其存储结构,算法中将使用到递归思想. 广义表是线性表的一种推广,在数据结构中有广泛应用. 一.广义表的概念 1.广义表的概念 (1 ...

  5. 简易个人信息登记系统(基于广义表,单链表)

    2019-2020 数据结构课程设计 一.需求分析 1)基本需求 1.记录个人信息 2.使用适当的数据结构储存个人信息 3.个人信息包括姓名,身份证号码,出生日期(包括年,月,日),兴趣 爱好(包括兴 ...

  6. 稀疏矩阵的十字链表存储表示和实现(第五章 P104 算法5.4)

    稀疏矩阵的十字链表存储 当矩阵的非零元个数和位置在操作过程中变化较大时,就不宜采用顺序存储结构来表示三元组的线性表.对这种类型的矩阵,采用链式存储结构表示三元组的线性表更为恰当. 在链表中,每个非零元 ...

  7. 广义表头尾链表存储结构_详解Redis五种数据结构的底层原理

    1,redis有五种基本数据结构:string.hash.set.zset.list:底层redis是通过c语言来实现这w五种结构的,具体是如何实现的,我们具体看一下. 2,SDS "sim ...

  8. 广义表头尾链表存储结构_单向循环链表的存储结构和操作

    单向循环链表的存储结构 单向循环链表(Circular Linked List)是单向链表的一种扩充,当单向链表带有头结点时,把单向链表中尾结点的指针域由空指针改为头结点的指针(当单向链表不带头结点时 ...

  9. 稀疏矩阵的三元组表与十字链表存储

    三元组表:存储稀疏矩阵的非零元素,以及该元素所在的行.列信息,极大的节省了空间(如相比于一般的二维数组的存储),而且三元组表的某些算法的时间效率也要优于经典算法,如基于三元组表的一次快速转置算法等等 ...

最新文章

  1. 9成P2P平台面临出局,千亿资本何去何从?
  2. java获取系统电量_android操作系统怎么获得电量
  3. objective-c 面试题
  4. 设置虚拟机和本机时间同步方法
  5. Go的sync.Cond(四)
  6. BookSmart Self Publishing
  7. 字符串表达式求值 C#实现
  8. php event_base_new,php event拓展基本使用
  9. 安装fastdfs依赖包
  10. python-基础回顾
  11. 关于RDP协议的分析 附上RDP 协议初步分析.pdf文件
  12. 优雅地修改多模块maven项目中的版本号
  13. html2cavans
  14. 电脑连接ios开发配置
  15. sqlmap基本命令
  16. 方法重载和方法重写的区别
  17. 量子计算机能做到0延迟吗,延迟选择量子擦除实验
  18. zblog模板 php,卢松松博客模板zblogphp版 适合seo功能强大(已支持1.6)
  19. 好未来谢华亮:AI 在教育行业中的应用
  20. Conda太慢 试试这个加速工具

热门文章

  1. 手机芯片的AP、BP和CP
  2. 安卓obb文件的使用进阶
  3. Flask+ZUI 开发小型工具网站(三)——登录功能
  4. 今天14:00 | NeurIPS 专场一 青年科学家专场
  5. echarts饼图自定义设置颜色的三种方式
  6. 82.【LibraryManger】
  7. eltable 无数据文案修改_写文案不断打磨修改,让你的文案简单易懂
  8. Windows 10操作系统配置L2TP方法
  9. 从实战经验来看 究竟如何才能做出赚钱的量化投资策略?
  10. 0基础单片机入门知识:怎么使用数字万用表以及注意事项