数据结构之数组与广义表

联系

数组和广义表可看作一种扩展的线性数据结构,其特殊性在于数据元素的构成上。从组成线性表的元素角度看,数组是由具有某种结构的数据元素构成,广义表则是由单个元素或子表构成的。数组和广义表是线性表的推广。

数组

1.数组的定义
从逻辑结构上,数组可以看成是对一般线性表的扩充。一维数组即为线性表,而二维数组可以定义为其数据元素为一维数组(线性表)的线性表。以此类推,N维数组是数据元素为N-1维数组的线性表。
2.数组的顺序存储
原因: 一旦给定数组的维数n及各维长度bi(1≤i≤n),则该数组中元素的个数就是确定的,数组的基本操作不涉及数组结构的变化。因此对于数组而言,采用顺序存储表示比较适合。
方法: 内存储器的结构是一维的,对于一维数组可直接采用顺序存储,用一维的内存存储表示多维数组,就必须按照某种次序将数组中元素排成一个线性序列,然后将这个线性序列存放在一维的内存储器中,这就是数组的顺序存储结构。
分类: 按行序存储和按列序存储
二维数组Am✖n 以行为主的存储序列为:
a11,a12,…,a1n,a21,a22,…,a2n,…,am1,am2,…,amm
以列为主的存储序列为:
a11,a21,…,am1,a12,a22,…,am2,…,a1n,a2n,…,amn
计算:
(1)一维数组的地址计算
Loc(A[i])=Loc(A[1])+(i-1)✖size
(2)二维数组的地址计算
如果每个元素占size个存储单元:
Loc(A[i][j])=Loc(A[1][1])+((i-1)✖n+(j-1))✖size
如果每个元素占一个存储单元:
Loc(A[i][j])=Loc(A[1][1])+(i-1)✖n+(j-1)
(3)三维数组的地址计算
Loc(A[i][j][k])=Loc(A[1][1][1])+((i-1)✖m✖n+(j-1)✖n+(k-1))✖size
当 j1,j2,j3的下限分别为c1,c2,c3,上限分别为d1,d2,d3
Loc(A[j1][j2][j3])=Loc(A[c1][c2][c3])+(j1-c1)✖((d2-c2+1)✖(d3-c3+1)+(j2-c2)✖(d3-c3+1)+(j3-c3))✖size
(4)n维数组的地址计算
Loc(A[j1][j2]…[jn])=Loc(A[c1][c2]…[cn])+Σ(i=1到n)ai✖(ji-ci)
其中,ai=size✖Π(k=i+1到n)(dk-ck+1),1≤i≤n
3.特殊矩阵的压缩存储
(1)规律分布的特殊矩阵
这类矩阵中元素分布的规律可以用数学公式来反映,通常利用这些规律将其压缩存储于一维数组中。
三角矩阵:
在这里插入图片描述
下三角矩阵中元素aij(i≥j),在一维数组中的存储单元的下标为:
Loc(A[i][j])=Loc(A[1][1])+(i✖(i-1)/2+j-1)
注意:对于对称矩阵,因其元素满足aij=aji,我们可以为每一对相等的元素分配一个存储空间,即只存下三角(或上三角)矩阵,从而将n²个元素压缩到n(n+1)/2个空间中
带状矩阵:
在这里插入图片描述
Loc(A[i][j])=Loc(A[1][1])+(3(i-1)-1+j-i+1)✖size
=Loc(A[1][1])+(2(i-1)+j-1)✖size
(2)稀疏矩阵
在这里插入图片描述
稀疏矩阵指的是大多数元素为0的矩阵。从直观上讲,当非零元素个数低于总元素的30%时,这样的矩阵为稀疏矩阵。
稀疏矩阵的三元组表表示法:
稀疏矩阵的三元组表类型定义

#define MAXSIZE 1000			/*非零元素的最大个数*/
typedef struct
{
	int row,col;				/*非零元素的行下标和列下标*/
	ElementType e;				/*非零元素的值*/
}Triple;
typedef struct
{
	Triple data[MAXSIZE+1];		/*非零元素的三元组表,data[0]未用*/
	int m,n,len;				/*矩阵的行数,列数和非零元素的个数*/
}TSMatrix;

对于稀疏矩阵的压缩存储,采取只存储非零元素的方法。由于稀疏矩阵中非零元素aij的分布没有规律,因此,在存储非零元素值的同时,还必须存储非零元素在矩阵中所处的行号和列号,这就是稀疏矩阵的三元组表表示法。
在这里插入图片描述
稀疏矩阵的转置运算
第一步:将三元组表中的行列对换
第二步:若转置后的三元组表以行序为主序存放,则对转置后的三元组表按行标递增排列,反之亦然。
稀疏矩阵的链式存储结构:十字链表
十字链表的类型定义:

typedef struct OLNode
{
	int row,col;				/*非零元素的行下标和列下标*/
	ElementType value;
	struct OLNode *right,*down;	/*非零元素所在行表,列表的后继链域*/
}OLNode;*OLink;
typedef struct
{
	OLink *row_head,*col_head;	/*行、列表的头指针向量*/
	int m,n,len;				/*稀疏矩阵的行数、列数、非零元素的个数*/
}CrossList;

为了避免大量移动元素,使用十字链表,能够灵活插入因运算而产生的新的非零元素,删除因运算而产生的新的非零元素,实现矩阵的各种运算。
在这里插入图片描述
除了(row,col,value)以外,还要添加两个链域:right用于链接同一行中的下一个非零元素,down用于链接同一列中的下一个非零元素。表示如下:
在这里插入图片描述

广义表

1.广义表的概念
广义表是n个数据元素(d1,d2,…dn)的有限序列,di既可以是单个元素,还可以是一个广义表,通常记作GL=(d1,d2,…dn)。其中d1是广义表表头,GL其余部分组成的表(d2,d3,…dn)称为广义表表尾。
2.广义表的存储结构
由于广义表中的数据元素既可以是单个元素,也可以是子表,因此对于广义表来说,难以用顺序存储结构来表示它,通常用链式存储结构来表示。
(1)广义表的头尾链表存储结构
任何一个非空的广义表都可以将其分解成表头和表尾两部分,繁殖,一对确定的表头和表尾可以唯一的确定一个广义表。因此:
表结点:由三个域构成,标志域、指向表头的指针域和指向表尾的指针域
元素结点:只需两个域,标志域和值域
广义表头尾链表存储结构类型定义

typedef enum {ATOM,LIST} ElemTag;/*ATOM=0,表示原子;LIST=1,表示子表*/
typedef struct GLNode
{
	ElemTag tag;				/*标志位tag用来区分原子结点和表结点*/
	union
	{
		AtomType atom;			/*原子结点的值域atom*/
		struct {struct GLNode *hp,*tp;} htp;/*表结点的指针域htp,包括表头指针域hp和表尾指针域tp*/
	}atom_htp;					/*atom_htp是原子结点的值域atom和表结点的指针域htp的联合体域*/
}GLNode,*GList;

(2)广义表的同层结点链存储结构
这种结构中,表结点和元素结点都由三个域构成
表结点:标志域、指向表头的指针域和指向表尾的指针域
元素结点:标志域、值域和指向表尾的指针域
广义表的同层结点链存储结构类型定义如下

typedef enum {ATOM,LIST} ElemTag;/*ATOM=0,表示原子;LIST=1表示子表*/
typedef struct GLNode
{
	ElemTag tag;
	union
	{
		AtomType atom;
		struct GLNode *hp;		/*表头指针域*/
	}atom_hp;					/*atom_hp是原子结点的值域atom和表结点的表头指针域hp的联合体域*/
	struct GLNode *tp;			/*同层下一个结点的指针域*/
}GLNode,*GList;

3.广义表的操作
以头尾链表为例
(1)求广义表L的表头

GList Head(GList L)
{
	if(L==NULL)					/*空表无表头*/
		return 0;
	if(L->tag==ATOM)			/*原子不是表*/
		exit(0);
	else
		return(L->atom_htp.htp.hp);
}

(2)求广义表L的表尾

GList Tail(GList L)
{
	if(L==NULL)					/*空表无表尾*/
		return(0);
	if(L->tag==ATOM)			/*原子不是表*/
		exit(0);
	else
		return(L->atom_htp.htp.tp);
}

(3)求广义表L的长度

int Length(GList L)
{
	int k=0;
	GLNode *s;
	if(L==NULL)
		return(0);
	if(L->tag==ATOM)
		exit(0);
	s=L;
	while(s!=NULL)
	{
		k++;
		s=s->atom_htp.htp.hp;
	}
	return(k);
}

(4)求广义表L的深度

int Depth(GList L)
{
	int d,max;
	GLNode *s;
	if(L==NULL)
		return(1);
	if(L->tag==ATOM)
		return(0);
	s=L;
	while(s!=NULL)
	{
		d=Depth(s->atom_htp.htp.hp);
		if(d>max)
			max=d;
		s=s->atom_htp.htp.hp;
	}
	return(max+1);				/*表的深度等于最深子表的深度加一*/
}

(5)求广义表L中原子数目

int CountAtom(GList L)
{
	int n1,n2;
	if(L==NULL)
		return(0);
	if(L->tag==ATOM)
		return(1);
	n1=CountAtom(L->atom_htp.htp.hp);	/*求表头中的原子数目*/
	n2=CountAtom(L->atom_htp.htp.tp);	/*求表尾中的原子数目*/
	return(n1+n2);
}

(6)复制广义表L
复制S表至T表

int CopyGList(GList S,GList *T)
{		
	if(S==NULL)							/*复制空表*/
		{
			*T=NULL;
			return(1);
		}
	*T=(GLNode*)malloc(sizeof(GLNode));
	if(*T==NULL)
		return(0);
	(*T)->tag=S->tag;
	if(S->tag==ATOM)
		(*T)->atom=S->atom;				/*复制单个原子*/
	else
	{
		CopyGList(S->atom_htp.htp.hp,&((*T)->atom_htp.htp.hp));/*复制表头*/
		CopyGList(S->atom_htp.htp.tp,&((*T)->atom_htp.htp.tp));/*复制表尾*/
	}
	return(1);
}
  • 15
    点赞
  • 97
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值