数组与广义表

本文介绍了数组和广义表作为线性数据结构的特殊性,重点讲解了数组的顺序存储,包括一维、二维和三维数组的地址计算。接着探讨了特殊矩阵的压缩存储,如三角矩阵和稀疏矩阵的三元组表表示法。还讨论了矩阵转置的不同算法,包括用三元组表实现稀疏矩阵转置。最后,详细阐述了广义表的存储结构,如头尾链表和同层结点链,并简要提及了操作实现。
摘要由CSDN通过智能技术生成

4.1 定义

数组与广义表可看做一种扩展的线性数据结构其特殊性反映在数据元素的构成上。从组成线性表的元素角度看,数组是由具有某种结构的数据元素构成,广义表则是由单个元素或子表构成的。即数组和广义表中的数据元素可以是单个元素,也可以是一个具有线性结构的数据。

4.2 数组的顺序存储与实现

1.一维数组的地址计算:设一维数组A=a1,a2,…an,数组中每个元素占size单元,则ai的地址: l o c ( a 1 ) + s i z e ∗ ( i − 1 ) loc(a_1)+size\ast(i-1) loc(a1)+size(i1)
2.二维数组的地址计算:Am×n按以行为主存储,下标从1开始, l o c ( a i j ) = l o c ( a 11 ) + s i z e ∗ ( n ∗ ( i − 1 ) + j − 1 ) loc(a_{ij})=loc(a_{11})+size\ast(n\ast(i-1)+j-1) loc(aij)=loc(a11)+size(n(i1)+j1)
3.三维数组的地址计算:Ar×m×n以按行为主存储,下标从1开始,
l o c ( a i j k ) = l o c ( a   111 ) + s i z e ∗ ( ( i − 1 ) ∗ m ∗ n + ( j − 1 ) ∗ n + ( k − 1 ) ) loc(a_{ijk})=loc(a~_{111})+size\ast((i-1)\ast m\ast n+(j-1)\ast n+(k-1)) loc(aijk)=loc(a 111)+size((i1)mn+(j1)n+(k1))
4.n维数组的地址计算:A[c_1…d_1,c_2…d_2,…c_n…d_n],按行为主存储, l o c ( j 1 , j 2 , . . . , j n ) = l o c ( c 1 , c 2 , . . . , c n ) + ∑ i = 1 n α i ∗ ( j i − c i ) loc(j_1,j_2,...,j_n)=loc(c_1,c_2,...,c_n)+\sum_{i=1}^{n}\alpha_i\ast(j_i-c_i) loc(j1,j2,...,jn)=loc(c1,c2,...,cn)+i=1nαi(jici)

4.3 特殊矩阵的压缩存储

4.3.1 规律分布的特殊矩阵

1.三角矩阵
以下三角矩阵为例:只存非零元素,即存储到一个大小为n×(n-1)/2的一维数组中: l o c [ i , j ] = l o c [ 1 , 1 ] + s i z e ∗ ( i ∗ ( i − 1 ) / 2 + j − 1 ) loc[i,j]=loc[1,1]+size\ast(i\ast (i-1)/2+j-1) loc[i,j]=loc[1,1]+size(i(i1)/2+j1).
2.带状矩阵:
以三对角带状矩阵为例:只存非零元素,即存储到一个大小为3n-2的一维数组中: l o c [ i , j ] = l o c [ 1 , 1 ] + s i z e ∗ ( 2 ( i − 1 ) + j − 1 ) loc[i,j]=loc[1,1]+size\ast(2(i-1)+j-1) loc[i,j]=loc[1,1]+size(2(i1)+j1).

4.3.2 非零元素很少的稀疏矩阵

1.稀疏矩阵的三元组表表示法

//类型定义
#define MAXSIZE 500
typedef int ElemType;
typedef struct
{
	int row,col;
	ElemType e;
}Triple;
typedef struct
{
	Triple data[MAXSIZE];
	int m,n,len;
}TSMatrix;

2.稀疏矩阵的链式存储结构——十字链表
能够灵活地插入因运算而产生的新的非零元素,实现矩阵的各种运算。

//类型定义
typedef struct OLNode
{
	int row,col;
	ElemType value;
	struct OLNode * right,*down;
}OLNode,*OLink;
typedef struct
{
	OLink *row_head,*col_head;
	int m,n,len; 
}CrossList;

4.4 矩阵的转置

4.4.1 经典算法
void TransMatrix(ElemType source[m][n],ElemType dest[n][m])
{
	int i,j;
	for(i=0;i<m;i++)
		for(j=0;j<n;j++)
			dest[j][i]=source[i][j];
}
4.4.2 用三元组表实现稀疏矩阵的转置

1.列序递增转置法

//简单转置
void TransposeTSMatrix(TSMatrix A,TSMatrix &B)
{
	IniArray(B);
	int i,j,k=1;
	B.m=A.n;
	B.n=A.m;
	B.len=A.len;
	for(i=1;i<=A.n;i++)
	{
		for(j=1;j<=A.len;j++)
		{
			if(A.data[j].col==i)
			{
				B.data[k].row=A.data[j].col;
				B.data[k].col=A.data[j].row;
				B.data[k].e=A.data[j].e;
				j++,k++;
			}
		}
	}
}

2.一次定位快速转置法
需要预先计算以下数据:
1).待转置矩阵三元组表A每一列中非零元素的总个数num[]
2).待转置矩阵每一列中第一个非零元素在三元组表B中的位置position[]

//快速转置
void FastTransposeTSMatrix(TSMatrix A,TSMatrix &B)
{
	IniArray(B);
	int col,i,p,q;
	int num[MAXSIZE],position[MAXSIZE];
	B.len=A.len,B.m=A.n,B.n=A.m;
	if(B.len)
	{
		for(col=1;col<=A.n;col++)
		{
			num[col]=0;
		}
		for(i=1;i<=A.len;i++)
		{
			num[A.data[i].col]++;
		}
		position[1]=1;
		for(col=2;col<=A.n;col++)
		{
			position[col]=position[col-1]+num[col-1];
		}
		for(p=1;p<=A.len;p++)
		{
			col=A.data[p].col,q=position[col];
			B.data[q].col=A.data[p].row;
			B.data[q].row=A.data[p].col;
			B.data[q].e=A.data[p].e;
			position[col]++;
		}
	}
}
4.4.3 十字链表
//建立十字链表
int CreateCrossList(CrossList * M)
{
	int m,n,t,i,j;
	ElemType e;
	OLNode* p,*q;
	scanf("%d %d %d",&m,&n,&t);//读入行数列数和非零元素个数 
	M->m=m,M->n=n,M->len=t;
	
	if(!(M->row_head=(OLink*)malloc((m+1)*sizeof(OLink))))	return 0;
	if(!(M->col_head=(OLink*)malloc((n+1)*sizeof(OLink))))	return 0;
	M->row_head=M->col_head=NULL; 
	scanf("%d %d %d",&i,&j,&e);
	while(i!=0)
	{
		if(!(p=(OLink)malloc(sizeof(OLNode))))	return 0;
		p->row=i,p->col=j,p->value=e;
		if(M->row_head[i]==NULL)	M->row_head[i]=p;
		else{
			/*寻找行表中的插入位置*/
			q=M->row_head[i];
			while(q->right!=NULL&& q->right->col<j)
				q=q->right;
			p->right=q->right,q->right=p;
		}
		if(M->col_head[j]==NULL)	M->col_head[j]=p;
		else{
			/*寻找列表中的插入位置*/
			q=M->col_head[j];
			while(q->down!=NULL&& q->down->row<i)
				q=q->down;
			p->down=q->down,q->down=p;
		}		
		scanf("%d %d %d",&i,&j,&e);
	}
} 

4.5 广义表

4.5.1 存储结构

1.头尾链表存储结构

typedef char AtomType;
typedef enum{ATOM,LIST} ElemTag;
typedef struct GLNode
{
	ElemTag tag;
	union
	{
		AtomType atom;
		struct{struct GLNode* hp,*tp;
		}htp;
	}atom_htp;
}GLNode,*GList;

2.同层结点链存储结构

typedef char AtomType;
typedef enum{ATOM,LIST} ElemTag;
typedef struct GLNode
{
	ElemTag tag;
	union
	{
		AtomType atom;
		struct GLNode* hp;
	}atom_hp;
	struct GLNode* tp;
}GLNode,*GList;
4.5.2 操作实现

以头尾链表存储结构为例

typedef char AtomType;
typedef enum{ATOM,LIST} ElemTag;
typedef struct GLNode
{
	ElemTag tag;
	union
	{
		AtomType atom;
		struct{struct GLNode* hp,*tp;
		}htp;
	}atom_htp;
}GLNode,*GList;

GList Head(GList L)//求广义表L的表头 
{
	if(L==NULL)	return (NULL);//空表无表头 
	if(L->tag==ATOM)	exit(0);//原子不是表 
	else return(L->atom_htp.htp.hp);
}
GList Tail(GList L)//求广义表L的表尾 
{
	if(L==NULL)	return(NULL);
	if(L->tag==ATOM)	exit(0);
	else return(L->atom_htp.htp.tp);	
}
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.tp;	
	} 
	return k;
}
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.tp;	
	} 
	return (max+1);
} 
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);
}
int CopyGList(GList S,GList * T)//复制广义表 
{
	if(S==NULL)	
	{
		*T=NULL;
		return 1;
	}	
	*T=(GLNode *)malloc(sizeof(GLNode));
	if(S->tag==ATOM)	(*T)->atom_htp.atom=S->atom_htp.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;
} 
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值