广义表的基本操作实现

广义表的四个特征:(1)广义线性表;(2)元素复合性;(3)元素递归性;(4)元素共享性

广义表的上述四个特征对于他的使用价值和应用效果起到了很大的作用。广义表的结构相当灵活,它可以兼容线性表、数组、树和有向图等各种常用的数据结构。当二维数组的每行或每列作为子表处理时,二维数组就是一个广义表;如果限制广义表中元素的共享和递归,广义表和树对应;如果限制广义表的递归并允许数据共享,则广义表和图对应。

广义表的基本操作有:(1)创建一个广义表(我以头尾链表作为存储结构);(2)取表头;(3)取表尾;(4)求广义表深度;(5)求广义表长度,(5)求广义表原子个数;

(6)复制广义表等。

现将完整代码粘在这儿,便于以后复习。(代码可能有些许错误,如看到,望指出,谢谢!)

(一)、存储结构和函数定义(函数定义.h)

#include<iostream>
#include<stdio.h>
using namespace std;
#define MaxLength 60
typedef struct{
char str[MaxLength];
int length;
}SString;
typedef char AtomType;
typedef enum{ ATOM, LIST } ElemTag;//ATOM=0,表示原子,LIST=1,表示子表
typedef struct Node
{
ElemTag tag;                //标志位tag用于区分元素是原子还是子表
union
{
AtomType atom;      //AtomType是原子结点的值域,用户自己定义类型
struct
{
struct Node *hp, *tp;        //hp指向表头,tp指向表尾
}ptr;
};
}*GList, GLNode;
//串函数定义
void StrAssign(SString *S, char cstr[]);    //串赋值函数
int StrEmpty(SString S);                    //串判空函数
void StrCopy(SString *T, SString S);        //串复制函数
void StrClear(SString *S);                  //串清空函数
int StrLength(SString S);                   //求串长函数
int StrCompare(SString S, SString T);       //串比较函数
int StrInsert(SString *S, int pos, SString T);//串插入函数
int StrDelete(SString *S, int pos, int len);  //串删除函数
int StrCat(SString *T, SString S);            //串连接函数
int StrIndex(SString S, int pos, SString T);  //串定位函数
int StrReplace(SString *S, SString T, SString V);//串替换函数
void StrPrint(SString S);                        //串输出函数
int SubString(SString *Sub, SString S, int pos, int len);  //求子串函数
//广义表函数定义
void Error(char *s);                    //错误处理函数
void CreateList(GList *L, SString S);   //创建头尾链表函数
void Init_GList(GList &GL);             //初始化广义表函数
void CopyList(GList *T, GList L);       //复制广义表函数
int GListLength(GList L);               //求广义表长度函数
int GListDepth(GList L);			    //求广义表深度函数
int CountAtom(GList L);                 //求广义表中原子结点的数目函数
void PrintGList(GList L);               //遍历输出广义表函数
void GetHead(GList L);               //求广义表表头函数
void GetTail(GList L);                //求广义表表尾函数
void DistributeString(SString *Str, SString *HeadStr);
//将非空字符串str分割成两部分:HSTR为第一个字符‘,’,之前的子串,SRE为之后的子串

(二).函数实现(函数实现.cpp)

#include "stdafx.h"
#include<iostream>
#include<string>
#include<stdio.h>
#include"函数结构声明.h"
//串函数实现部分
//串赋值函数实现
void StrAssign(SString *S, char str[])
{
	int i;
	for (i = 0; str[i] != '\0'; i++)
		S->str[i] = str[i];   //将常量cstr中的字符赋值给串S
	S->length = i;
}
//判断串是否为空,串为空返回1,否则返回0
int StrEmpty(SString S)
{
	if (S.length == 0)
		return 1;
	else
		return 0;
}
//求串的长度操作
int StrLength(SString S)
{
	return S.length;
}
//串的复制操作
void StrCopy(SString *T, SString S){
	int i;
	for (i = 0; i<S.length; i++)  //将串S的字符赋值给串T
		T->str[i] = S.str[i];
	T->length = S.length;       //将串S的长度赋值给串T
}

int StrCompare(SString S, SString T)
{   //串的比较操作
	int i;
	for (i = 0; i<S.length&&i<T.length; i++)//比较两个串中的字符
	{
		if (S.str[i] != T.str[i])        //如果出现字符不同,则返回两个字符的差值
			return (S.str[i] - T.str[i]);
	}
	return (S.length - T.length); //如果比较完毕,返回两个串的长度的差值
}

int StrInsert(SString *S, int pos, SString T)
{//串的插入操作。在S中第pos个位置插入T分为三种情况
	int i;
	if (pos<0 || pos - 1>S->length){    //插入位置不正确,返回0
		Error("插入位置不正确");
		return 0;
	}
	if (S->length + T.length <= MaxLength){    //第一种情况,插入子串后串长≤MaxLength,即子串T完整地插入到串S中
		for (i = S->length + T.length - 1; i >= pos + T.length - 1; i--) //在插入子串T前,将S中pos后的字符向后移动len个位置
			S->str[i] = S->str[i - T.length];
		for (i = 0; i<T.length; i++)  //将串插入到S中
			S->str[pos + i - 1] = T.str[i];
		S->length = S->length + T.length;
		return 1;
	}
	else if (pos + T.length <= MaxLength){   //第二种情况,子串可以完全插入到S中,但是S中的字符将会被截掉
		for (i = MaxLength - 1; i>T.length + pos - i; i--)      //将S中pos以后的字符整体移动到数组的最后
			S->str[i] = S->str[i - T.length];
		for (i = 0; i<T.length; i++)      //将T插入到S中
			S->str[i + pos - 1] = T.str[i];
		S->length = MaxLength;
		return 0;
	}
	else{      //第三种情况,子串T不能被完全插入到S中,T中将会有字符被舍弃
		for (i = 0; i<MaxLength - pos; i++) //将T直接插入到S中,插入之前不需要移动S中的字符
			S->str[i + pos - 1] = T.str[i];
		S->length = MaxLength;
		return 0;
	}
}
int StrDelete(SString *S, int pos, int len)
{//在串S中删除pos开始的len个字符
	int i;
	if (pos<0 || len<0 || pos + len - 1>S->length){
		Error("删除位置不正确,参数len不合法");
		return 0;
	}
	else{
		for (i = pos + len; i <= S->length - 1; i++)
			S->str[i - len] = S->str[i];
		S->length = S->length - len;
		return 1;
	}
}
//串的连接操作
int StrCat(SString *T, SString S)
{
	int i, flag;
	if (T->length + S.length <= MaxLength){
		for (i = T->length; i<T->length + S.length; i++)
			T->str[i] = S.str[i - T->length];
		T->length = T->length + S.length;
		flag = 1;
	}
	else if (T->length<MaxLength){
		for (i = T->length; i<MaxLength; i++)
			T->str[i] = S.str[i - T->length];
		T->length = MaxLength;
		flag = 0;
	}
	return flag;
}
//截取子串操作
int SubString(SString *Sub, SString S, int pos, int len)
{
	int i;
	if (pos<0 || len<0 || pos + len - 1>S.length)
	{
		Error("参数pos和len不合法");
		return 0;
	}
	else
	{
		for (i = 0; i<len; i++)
			Sub->str[i] = S.str[i + pos - 1];
		Sub->length = len;
		return 1;
	}
}
//串的定位操作
int StrIndex(SString S, int pos, SString T)  //BF算法实现
{
	int i, j;
	if (StrEmpty(T))
		return 0;
	i = pos;
	j = 0;
	while (i<S.length&&j<T.length){
		if (S.str[i] == T.str[j]){
			i++;
			j++;
		}
		else{
			i = i - j + 1;
			j = 0;
		}
	}
	if (j >= T.length)
		return i - j + 1;
	else
		return 0;
}
//串的替换操作
int StrReplace(SString *S, SString T, SString V)
{
	//将S中所有的T替换为V
	int i;
	int flag;
	if (StrEmpty(T))
		return 0;
	i = 0;
	do{
		i = StrIndex(*S, i, T);//找到T在S中的位置
		if (i){
			StrDelete(S, i, StrLength(T));    //删除找到的T
			flag = StrInsert(S, i, V);       //在i位置插入V
			if (!flag)
				return 0;
			i += StrLength(V);
		}
	} while (i);
	return 1;
}
//串的清空操作
void StrClear(SString *S){
	S->length = 0;
}
//串的输出操作
void StrPrint(SString S){
	int i;
	for (i = 0; i<S.length; i++){
		cout << S.str[i];
	}
	cout << endl;
}

//广义表函数实现部分
void Error(char *s)                       //错误处理函数
{
	cout << s << endl;
	exit(1);
}

void  GetHead(GList L)
//求广义表的表头结点操作
{
	if (L == NULL)   Error("空表不能取表头!");
	GLNode *Head = L->ptr.hp;
	if (Head->tag == ATOM)
		cout << "表头:" << Head->atom << endl;
	else
	{
		cout << "表头:";
		PrintGList(Head);
		cout << endl;
	}
}
void  GetTail(GList L)
//求广义表的表尾操作
{
	if (L == NULL)   Error("空表不能取表头!");
	GLNode *tail = L->ptr.tp;
	cout << "表尾:";
	PrintGList(tail);
	cout << endl;
}
int GListLength(GList L)
//求广义表的长度操作
{
	int length = 0;
	GLNode *p = L;
	if (p == NULL)  return 0;
	else
	{
		length = GListLength(p->ptr.tp);
	}
	return length + 1;

}
int GListDepth(GList L)
//求广义表的深度操作
{
	int max, depth;
	GLNode *p;
	if (!L)                          //如果广义表非空,则返回1
		return 1;
	if (L->tag == ATOM)                 //如果广义表是原子,则返回0
		return 0;
	for (max = 0, p = L; p; p = p->ptr.tp)         //逐层处理广义表
	{
		depth = GListDepth(p->ptr.hp);
		if (max<depth)
			max = depth;
	}
	return (max + 1);
}
int CountAtom(GList L)//求广义表中原子结点的数目,并返回
{
	int n1, n2;
	if (L == NULL) return 0;
	if (L->tag == ATOM) return 1;
	n1 = CountAtom(L->ptr.hp);           //求表头中的原子数目
	n2 = CountAtom(L->ptr.tp);           //求表尾中的原子数目
	return (n1 + n2);
}
void CopyList(GList *T, GList L)
//广义表的复制操作。由广义表L复制得到广义表T
{
	if (!L)                          //如果广义表为空,则T为空表
		*T = NULL;
	else
	{
		*T = (GList)malloc(sizeof(GLNode));   //表L不空,为T建立一个表结点
		if (*T == NULL)
			Error("内存申请失败!");
		(*T)->tag = L->tag;
		if (L->tag == ATOM)            //复制原子
			(*T)->atom = L->atom;
		else                        //递归复制子表
		{
			CopyList(&((*T)->ptr.hp), L->ptr.hp);
			CopyList(&((*T)->ptr.tp), L->ptr.tp);
		}
	}
}
void DistributeString(SString *Str, SString *HeadStr)
//将串Str分离成两个部分,HeadStr为第一个逗号之前的子串,Str为逗号后的子串
{
	int len, i, k;
	SString Ch, Ch1, Ch2, Ch3;
	len = StrLength(*Str);                //len为Str的长度
	StrAssign(&Ch1, ",");                //将字符','、'('和')'分别赋给Ch1,Ch2和Ch3
	StrAssign(&Ch2, "(");
	StrAssign(&Ch3, ")");
	SubString(&Ch, *Str, 1, 1);            //Ch保存Str的第一个字符
	for (i = 1, k = 0; i <= len&&StrCompare(Ch, Ch1) || k != 0; i++) //搜索Str最外层的第一个括号
	{
		SubString(&Ch, *Str, i, 1);        //取出Str的第一个字符
		if (!StrCompare(Ch, Ch2))         //如果第一个字符是'(',则令k加1
			k++;
		else if (!StrCompare(Ch, Ch3))    //如果当前字符是')',则令k减去1
			k--;
	}
	if (i <= len)                           //串Str中存在',',它是第i-1个字符
	{
		SubString(HeadStr, *Str, 1, i - 2);  //HeadStr保存串Str','前的字符
		SubString(Str, *Str, i, len - i + 1);  //Str保存串Str','后的字符
	}
	else                                //串Str中不存在','
	{
		StrCopy(HeadStr, *Str);          //将串Str的内容复制到串HeadStr
		StrClear(Str);                  //清空串Str
	}
}
void CreateList(GList *L, SString S)
//采用头尾链表创建广义表
{
	SString Sub, HeadSub, Empty;
	GList p, q;
	StrAssign(&Empty, "()");
	if (!StrCompare(S, Empty))            //如果输入的串是空串则创建一个空的广义表
		*L = NULL;
	else
	{
		if (!(*L = (GList)malloc(sizeof(GLNode))))     //为广义表生成一个结点
			Error("内存分配失败!");
		if (StrLength(S) == 1)                         //广义表是原子,则将原子的值赋值给广义表结点
		{
			(*L)->tag = ATOM;
			(*L)->atom = S.str[0];
		}
		else                                        //如果是子表
		{
			(*L)->tag = LIST;
			p = *L;
			SubString(&Sub, S, 2, StrLength(S) - 2);     //将S去除最外层的括号,然后赋值给Sub
			do
			{
				DistributeString(&Sub, &HeadSub);    //将Sub分离出表头和表尾分别赋值给HeadSub和Sub
				CreateList(&(p->ptr.hp), HeadSub);    //递归调用生成广义表
				q = p;
				if (!StrEmpty(Sub))                  //如果表尾不空,则生成结点p,并将尾指针域指向p
				{
					if (!(p = (GLNode *)malloc(sizeof(GLNode))))
						Error("内存分配失败!");
					p->tag = LIST;
					q->ptr.tp = p;
				}
			} while (!StrEmpty(Sub));
			q->ptr.tp = NULL;
		}
	}
}
void PrintGList(GList L)
//输出广义表的元素
{
	if (!L)  cout << "()";
	else
	{
		if (L->tag == ATOM)
			cout << L->atom;
		else
		{
			cout << '(';
			GLNode *p = L;
			while (p)
			{
				PrintGList(p->ptr.hp);
				p = p->ptr.tp;
				if (p)  cout << ',';
			}
			cout << ')';
		}
	}
}

(三)主函数测试(主函数测试.cpp)

#include "stdafx.h"
#include<iostream>
#include<stdio.h>
#include"函数结构声明.h"

int _tmain(int argc, _TCHAR* argv[])
{
	GList L, T;
	SString S;
	char str[60];
	int depth, length;
	cout << "请输入广义表:" << endl;
	cin >> str;
	StrAssign(&S, str);                //将字符串赋值给串S
	CreateList(&L, S);                  //由串创建广义表L
	cout << "输出广义表L中的元素:" << endl;
	PrintGList(L);                     //输出广义表中的元素
	cout << endl;
	cout << "广义表L表头是:" << endl;
	GetHead(L);
	cout << "广义表L表尾是:" << endl;
	GetTail(L);
	cout << "广义表L中的原子数目是:" << CountAtom(L) << endl;
	length = GListLength(L);          //求广义表的长度
	cout << "广义表L的长度:" << length << endl;
	depth = GListDepth(L);            //求广义表的深度
	cout << "广义表L的深度:" << depth << endl;
	CopyList(&T, L);
	cout << "由广义表L复制得到广义表T广义表T的元素为:" << endl;
	PrintGList(T);
	return 0;
}
时间: 2024-10-08 09:26:55

广义表的基本操作实现的相关文章

广义表的表示javascript

广义表是线性表的推广,也有人称其为列表. 那么它和线性表有什么区别呢?线性表中每个成员只能是单个元素,而广义表中的成员可以是单个元素,也可以是广义表,分别称为广义表的原子和子表.下面举几个广义表的例子. A=(); B=(e); C=(a,(b,c,d)); D=((),(e),(a,(b,c,d))); E=(a,E); 由于广义表中的数据元素可以具有不同的结构(原子或列表),因此难以用顺序存储结构表示,通常采用链式存储结构.由于列表中的元素可以是原子也可以是列表,所以需要两种结构的节点,一种

数据结构与算法系列研究四——数组和广义表

稀疏矩阵的十字链表实现和转置 一.数组和广义表的定义 数组的定义1:一个 N 维数组是受 N 组线性关系约束的线性表.           二维数组的逻辑结构可形式地描述为:           2_ARRAY(D,R)              其中 D={aij} | i=0,1,...,b1-1; j=0,1,...,b2-1;aij∈D0}              R={Row,Col}              Row={<aij,ai,j+1>|0<=i<=b1-1;

数据结构——广义表

定义 Python中的list就是一种广义表,使用起来非常方便.广义表的特点就是能够存储不同类型的元素,也支持嵌套使用,即表中还有表.关于广义表的定义还有几本操作归纳如下: ADT Linear List: 元素组成: 能存储不同元素类型的表结构叫做广义表,支持嵌套操作. 基本操作: InitGList() 创建一个空表 DestoryGList() 销毁一个表 GListLength()  获取表的长度 GListDepth()  获取表的深度 PrintList() 遍历一次表 Insert

javascript实现数据结构:广义表

原文:javascript实现数据结构:广义表  广义表是线性表的推广.广泛用于人工智能的表处理语言Lisp,把广义表作为基本的数据结构. 广义表一般记作: LS = (a1, a2, ..., an) LS是广义表的名称,n是它的长度,ai可以是单个元素,也可以是广义表,分别称为广义表LS的原子和子表.习惯上,用大写字母表示广义表的名称,小写字母表示原子.当广义表LS非空时,称第一个元素a1为LS的表头,称其余元素组成的表(a2, a3, ..., an)是LS的表尾. 下面列举一些广义表的例

第五章:1.数组和广义表 -- 数组

前言: 2.3.4章讨论的线性结构中的数据元素都是非结构的原子类型,元素的值是不再分解的.本章讨论的两种数据结构---数组和广义表可以看成是线性表在下述含以上的扩展:表中的数据元素本身也是一个数据结构. 其中.数组是一种比较熟知的数据类型,几乎所有程序语言都把数组类型设定为固有类型,前两节节以抽象数据类型的形式讨论数组的定义和实现,使读者加深对数组的理解. 目录: 1.数组的定义 2.数组的顺序表示和实现 3.矩阵的压缩存储 4.广义表的定义 5.广义表的存储结构 6.m元多项式的表示 7.广义

数据结构习题之多维数组和广义表

第五章 多维数组和广义表 一.基本要求.重点.难点 本章目的是介绍多维数组的逻辑结构特征及其存储方式.特殊矩阵和稀疏矩阵的压缩存储方法.本章重点是熟悉多维数组的存储方式.矩阵的压缩存储方式,难点是稀疏矩阵的压缩存储方示下实现的算法. 二.考核目标.考核要求 1.多维数组,要求达到"理解"层次 1.1多维数组的逻辑特征. 1.2多维数组的顺序存储结构及地址计算方式. 1.3数组是一种随机存取结构的原因. 2.矩阵的压缩存储,要求达到"理解"层次 2.1特殊矩阵和稀疏矩

广义表 的实现

广义表是非线性结构,其定义是递归的. 以下给出几种简单的广义表模型: 由上图我们可以看到,广义表的节点类型无非head.value.sub三种,这里设置枚举类型,利用枚举变量来记录每个节点的类型: enum  Type { HEAD,   //头节点 VALUE,  //值节点 SUB,    //子表节点 }; 每个节点都有自己的类型以及next指针,除此之外,如果该节点是VALUE类型还要分配空间存储该节点的有效值:但是若该节点是SUB类型,就需定义一个指针指向子表的头. 这里我们可以用联合

广义表总结

/**********************          WZ  ASUST 2016 表的实现与表头表尾问题 缺函数:找值 **********************/ #include<iostream> #include<assert.h> #include<string> using namespace std;   //实现广义表的结构 // 节点的类型:来代替直接写3类 结构体 enum Type//枚举类型 {     HEAD,     VAL

广义表 (五)

5.1广义表-广义表的定义和基本运算 顾名思义,广义表是线性表的推广.也有人称其为列表(Lists,用复数形式以示与统称的表List 的区别). ⒈广义表的定义和性质 我们知道,线性表是由n 个数据元素组成的有限序列.其中每个组成元素被限定为单元素,有时这种限制需要拓宽.例如,中国举办的某体育项目国际邀请赛,参赛队清单可采用如下的表示形式: (俄罗斯,巴西,(国家,河北,四川),古巴,美国,(),日本) 在这个拓宽了的线性表中,韩国队应排在美国队的后面,但由于某种原因未参加,成为空表.国家队.河