看数据结构写代码(52) 广义表的扩展线性链表存储表示

广义表 的另一种 存储结构是 扩展线性链表存储表示,这种 存储结构的 根 节点 必 存在,并且 根节点的 表尾 为空,将 根节点的 表尾 放 在 表头 的 表尾 指针上。

这样 从 表头 一直 就可以 遍历 所有 同级 节点。

具体j结构 如下:

例如 下面的 广义表 ,用 扩展线性链表 表示为:

而 头尾 存储表示,是 把 表头 和 表尾 都放在 根节点 的 指针上。其存储结构如下:

所以 其 实现 代码略有 不同,要 小心 处理

下面 上代码:

// GList2.cpp : 定义控制台应用程序的入口点。
//

// GList.cpp : 定义控制台应用程序的入口点。
//广义表的扩展线性链表存储方式

#include "stdafx.h"
#include <cstdlib>
#include <cstring>
#define MAX_SIZE 500
typedef char ATomType;
enum ElemTag{
	Tag_Atom,
	Tag_List,
};

enum E_State{
	E_State_Error = 0,
	E_State_Ok = 1,
};

typedef struct GLNode{
	ElemTag tag;
	union {
		ATomType data;//原子数据
		GLNode * hLink;//表头
	};
	GLNode * nextLink;//指向后继节点》。
}*GList;

void initGList(GList * list){
	*list = NULL;
}
//最简版的 subString,没有判断边界条件,效率最高
void subString(char * s,char * sub,int startIndex,int len){
	for (int i = 1; i < startIndex; i++,s++);
	for (int i = 0; i < len; i++) sub[i] = s[i];
	sub[len] = '\0';
}

//分离 出 表头 字符串.
void strSep(char * sub,char * hSub){
	int i =0;
	int k = 0;//左括号不匹配的个数
	int len = strlen(sub);
	for (;i < len; i++){
		if (sub[i] == '(') k++;
		if (sub[i] == ')') k--;
		if (sub[i] == ',' && k == 0)break;
	}
	if (i < len){
		subString(sub,hSub,1,i);
		subString(sub,sub,i+2,len-i-1);
	}
	else{//表头即为 sub
		subString(sub,hSub,1,len);
		sub[0] = '\0';
	}
	//printf("%s\t%s\n",hSub,sub);
}

void createGList(GList * list,char * string){
	GList p = *list = (GList)malloc(sizeof(GLNode));
	if (strcmp(string,"()") == 0){
		p->tag = Tag_List;
		p->hLink = p->nextLink = NULL;
	}
	else {
		int len = strlen(string);
		if (len == 1){//原子结构
			p->tag = Tag_Atom;
			p->nextLink = NULL;
			p->data = string[0];
		}
		else{
			p->nextLink = NULL;
			p->tag = Tag_List;
			char sub[MAX_SIZE];
			subString(string,sub,2,len-2);//去掉 最外层 ()
			char hSub[MAX_SIZE];
			strSep(sub,hSub);
			createGList(&p->hLink,hSub);
			p = p->hLink;
			//创建头结点后继
			while (sub[0] != '\0'){
				strSep(sub,hSub);
				createGList(&p->nextLink,hSub);
				p = p->nextLink;
			}
		}
	}
}
//后序释放..
void destoryGList(GList * list){
	if (*list != NULL){
		if ((*list)->tag != Tag_Atom){
			destoryGList(&(*list)->hLink);
		}
		destoryGList(&(*list)->nextLink);
		free(*list);
		*list = NULL;
	}
}

void copyList(GList * to,GList from){
	if (from != NULL){
		GList p = *to = (GList)malloc(sizeof(GLNode));
		p->tag = from->tag;
		if (from->tag == Tag_Atom){
			p->data = from->data;
		}
		else{
			copyList(&(*to)->hLink,from->hLink);
		}
		copyList(&(*to)->nextLink,from->nextLink);
	}
	else{//少加了下面的两句
		*to = NULL;
	}
}

//求广义表的长度
//list = (a1,a2,a3....an), 长度 为n
int listLen(GList list){
	int len = 0;
	list = list->hLink;
	while (list != NULL){
		len ++;
		list = list->nextLink;
	}
	return len;
}
//求广义表的深度 ,广义表括弧的重数..
//list = (a1,a2,a3....an), 深度为:max(listDepth(a1),listDepth(a2),listDepth(a3)...)+1
int listDepth(GList list){
	if (list == NULL || list->tag == Tag_List && list->hLink == NULL){
		return 1;
	}
	else if(list->tag == Tag_Atom){
		return 0;
	}
	else
	{
		int max = 0;
		GList p = list->hLink;
		for (;p != NULL; p=p->nextLink){
			int depth = listDepth(p);
			if (max < depth){
				max = depth;
			}
		}
		return max +1;
	}
}

bool isListEmpty(GList list){
	return list == NULL ? true : false;
}

GList getHead(GList list){
	return list == NULL ? NULL : list->hLink;
}

GList getTail(GList list){
	return list == NULL ? NULL : list->hLink->nextLink;
}
//插入一个元素在表头
GList insertFirst(GList * list,ATomType data){
	//错误
	//GList newList = (GList) malloc(sizeof(GLNode));
	//newList->tag = Tag_List;
	//newList->nextLink = NULL;
	GList  head = (GList) malloc(sizeof(GLNode));
	//newList->hLink = head;
	head->tag = Tag_Atom;
	head->data = data;
	GList  p = (*list)->hLink;
	(*list)->hLink = head;
	head->nextLink = p;;
	//*list = newList;
	return *list;
}

void deleteFirst(GList * list){
	GList  p = (*list)->hLink->nextLink;
	(*list)->hLink->nextLink = NULL;
	destoryGList(list);
	*list = p;
}

void printGList(GList list){
	if (list != NULL){
		if (list->tag == Tag_Atom){//原子节点 没有头节点..
			printf("%c",list->data);
		}
		else{
			printGList(list->hLink);
		}
		printGList(list->nextLink);
	}
}

int _tmain(int argc, _TCHAR* argv[])
{
	printf("-----------------创建广义表----------------\n");
	printf("请输入广义表,用() 表示表类型,用,分割表成员:");
	char s[MAX_SIZE];
	scanf("%s",s);
	GList list;
	createGList(&list,s);
	printGList(list);
	int len = listLen(list);
	int depth = listDepth(list);
	char * isEmpty = isListEmpty(list) ? "表为空" : "表不空";
	printf("\n表长为:%d,表深:%d,%s",len,depth,isEmpty);
	GList head = getHead(list);
	GList tail = getTail(list);
	//printf("\n-----------------表头----------------\n");
	//printGList(head);
	printf("\n-----------------表尾----------------\n");
	printGList(tail);
	printf("\n-----------------在表头插入一个元素----------------\n");
	insertFirst(&list,'z');
	printGList(list);
	printf("\n-----------------删除表头----------------\n");
	deleteFirst(&list);
	printGList(list);
	printf("\n-----------------拷贝广义表----------------\n");
	GList copy;
	copyList(&copy,list);
	printGList(copy);
	destoryGList(&list);
	return 0;
}

运行截图:

源码网盘地址:点击打开链接

时间: 2024-10-03 13:27:48

看数据结构写代码(52) 广义表的扩展线性链表存储表示的相关文章

_DataStructure_C_Impl:广义表的扩展线性链表存储

#include<stdio.h> #include<stdlib.h> #include<string.h> #include"SeqString.h" typedef char AtomType; typedef enum{ATOM,LIST} ElemTag;//ATOM=0,表示原子,LIST=1,表示子表 typedef struct GLNode{ ElemTag tag; //标志位tag用于区分元素是原子还是子表 union{ Ato

5-6-广义表(扩展线性链表存储表示)-数组和广义表-第5章-《数据结构》课本源码-严蔚敏吴伟民版

课本源码部分 第5章  数组和广义表 - 广义表(扩展线性链表存储表示) ——<数据结构>-严蔚敏.吴伟民版        源码使用说明  链接??? <数据结构-C语言版>(严蔚敏,吴伟民版)课本源码+习题集解析使用说明        课本源码合辑  链接??? <数据结构>课本源码合辑        习题集全解析  链接??? <数据结构题集>习题解析合辑        本源码引入的文件  链接? Status.h.SequenceString.c  

看数据结构写代码(37) 图的十字链表的表示与实现

图的邻接表在 查找 有向图的 出度 很 方便,但是 在 查找 入度 时,需要遍历整个图.如果想要 方便的 查找 入度,需要 建立 逆邻接表.十字链表 正好 就是 邻接表 和 逆邻接表的集合.具体结构图如下: 感觉 十字链表 在 查找 入度时 方便 一些,其他 跟 邻接表没什么区别. 源代码 网盘地址:点击打开链接 代码如下: // CrossLinkGraph.cpp : 定义控制台应用程序的入口点. //有向图的十字链表表示法 #include "stdafx.h" #include

看数据结构写代码(51) 广义表

广义表是一种非线性的数据结构.但如果广义表的每个元素都是原子,它就变成了线性表.广义表广泛地用于人工智能等领域的LISP语言. 广义表一般记作 LS = (a1, a2, ···, an), n是它的长度,ai可以是单个元素(原子),也可以是广义表(子表),当广义表非空时,称第一个元素a1为LS的表头,称其余元素组成的表为LS的表尾.注意:表头是元素(可以是原子,也可以是广表),表尾一定是广义表.E=(a, E)是一个递归的表.D=(( ),(e),(a,(b,c,d)))是多层次的广义表,长度

看数据结构写代码(32) 赫夫曼树编码以及译码

杂谈:最近有点慵懒,不好不好.好几天都没写代码,原本准备上星期完结 树 这一章节的.现在 又耽误了.哎.要抓紧时间啊. 下面直接上代码: 可以到我的网盘下载源代码,或者 直接拷贝下面的源代码 运行 网盘地址:点击打开链接 // HuffmanTree.cpp : 定义控制台应用程序的入口点. //哈弗曼编码,译码 #include "stdafx.h" #include <stdlib.h> #include <cstring> enum E_State { E

看数据结构写代码(36) 图的邻接表表示与实现

图的邻接表表示法,是为每一个顶点建立一个链表,链表里存放着相同弧尾的 弧的信息,这些链表顺序存放在数组中.下面是无向图g2的邻接表 邻接表 比 邻接矩阵 节省空间,同时 也带来一些操作上的 不便,例如 看 两个顶点是否 相邻,需要 遍历 链表,在 求 无向图顶点的度时,只需 遍历 顶点的链表,而 求 有向图 顶点的度 需要 遍历 整个图 查找 弧头 为这个顶点的 个数. 如果 不想这样做,可以 建立 逆邻接表,即 链表里 存放着 相同 弧头的 弧 的信息. 下一节 要说的 十字链表 类似于这种结

看数据结构写代码(61) 哈希表

前面说的 各种查找都是 基于 "比较" 的基础 来进行 查找的.查找的 效率 要 看 比较的 次数.那么 有没有 不需要 比较,就可以 找到 想要的数据的 方法呢? 哈希表 就是 这样的 一种方法,它用  数组 作为 保存 关键字的 数据原型,通过 一个 哈希 函数f(k),来找到 关键字 存储的位置,从而 找到想要的信息. 例如 我们 想要解决 这样的一个问题: 假设这有一个各种字母组成的字符串,假设这还有另外一个字符串,而且这个字符串里的字母数相对少一些.什么方法能最快的查出所有小

看数据结构写代码(38) 图的邻接多重表表示法与实现

图的邻接多重表 是 无向图的 另一种表示法.其与 邻接表 的差别 仅仅 在于 ,邻接表 用 两个 顶点 来表示 一条边,而 邻接多重表 用一个 顶点来表示一条边.这样使得 邻接多重表 在 某些操作 要 来的 方便.例如 将 搜索过的边 做记号 或者 删除 一条边. 下面是邻接多重表的结构: 下面的 6条边 用 6个弧 节点表示,用12个指针指向,每个弧节点被 指向2次.这样使得我们 在 释放内存的时候 需要格外小心. 下面上代码: 源码工程文件网盘地址:点击打开链接 // AMLGraph.cp

看数据结构写代码(53) 静态查找表(线性查找,二分查找,斐波那契查找,插值查找)

查找定义:根据给定的某个值,在查找表中确定一个其关键字等于给定值的数据元素(或记录). 查找表分类:静态查找表和动态查找表. 静态查找表:只查找,而不进行插入,删除. 动态查找表:在查找过程中同时插入查找表中不存在的数据元素,或者从查找表中删除已经存在的某个数据元素. 静态表的 查找 大致 四种 算法: 线性查找,二分查找,斐波那契查找和插值查找. 其中 在线性查找之前,对表 无要求.对于 其余三种 需要 在查找之前 排序.插值查找 除了 需要 排序,还需要 均匀分布. 下面 给出代码: 线性查