目录
数组
1 抽象数据类型数组的形式定义
ADT Array{
数据对象: ji = 0,…,bi - 1, i = 1,2,…,n,
D={ aj1j2…jn | n(>0)称为数组的维数,bi是数组第i维的长度。ji是数组元素的第i维的下标, aj1j2…jn ϵ ElemSet }
数据关系: R = { R1,R2,…,R3}
Ri = { <aj1…ji…jn , aj1…ji+1…jn> |
0<=jk<=bk-1 , 1<=k<=n 且 k!=i,
0<=ji<=bi-2 , aj1…ji…jn , aj1…ji+1…jn ϵ D,i=2,…,n}
基本操作:
InitArray( &A, n, bound1, …, boundn )
操作结果:若数组n和各维长度合法,则构造相应的数组A,并返回OK。
DestroyArray( &A )
操作结果:销毁数组A。
Value( A, &e, index1,…, indexn )
初始条件:A是n维数组,e为元素变量,随后是n个下标值。
操作结果:若各下标不超界,则e赋值为所指的A的元素值,并返回OK。
Assgin( &A, e, index1,…, indexn )
初始条件:A是n维数组,e为元素变量,随后是n个下标值。
操作结果:若各下标不超界,则将e的值赋给所指的A的元素值,并返回OK。
}ADT Array
这是一个C语言风格的定义。当n=1时,n维数组就退化为定长的线性表。反之,n维数组也可以看成是线性表的推广。
2 数组的顺序表示和实现
由于数组一般不做插入和删除,也就是说,一旦建立了数组,则结构中的数据元素个数和元素之间的关系就不发生变动了。因此,采用顺序存储结构表示数组是自然的事了。由于存储单元是一维的结构,而数组是多维的结构,则用一组连续存储单元存放数组的数据元素就有个次序约定问题。
下面仅用以行序为主序的存储结构为例子说明。
(1) 数组的顺序存储表示
#include <stdarg.h> //标准头文件,提供宏va_start,va_arg和va_end,用于存取变长参数表
#define MAX_ARRAY_DIM 3 //假设数组维数的最大值为3
typedef struct{
ElemType *base; //数组元素基址,由InitArray分配
int dim; //数组维数
int *bounds; //数组维界基址,由InitArray分配
int *constants; //数组映像函数常量基址,由InitArray分配
}Array;
(2) 基本操作
Status
InitArray( Array &A, int dim, ... ){
//若维数dim和随后的各维长度合法,则构造相应的数组A,并返回OK。
va_list var_arg;
if( dim < 1 || dim > MAX_ARRAY_DIM )
return ERROR;
A.dim = dim;
A.bounds = (int *)malloc( dim * sizeof( int ) );
if( !A.bounds )
exit(OVERFLOW); //若各维长度合法,则存入A.bounds ,并求出A的元素总数elemtotal
elemtotal = 1;
va_start( var_arg, dim ); //var_arg是存放变长参数信息的数组
for( i = 0; i < dim; i++ ){
A.bounds[ i ] = va_arg( var_arg, int );
if( A.bounds[ i ] < 0)
return UNDERFLOW;
elemtotal * = A.bounds[ i ];
}
va_end( var_arg );
A.base = ( ElemType *)malloc( elemtotal * sizeof( ElemType ) );
if( !A.base )
exit( OVERFLOW );
//求映像函数的常数ci,并存入A.constants[i-1],i=1,...,dim
A.constants = (int *)malloc( dim * sizeof( int ) );
if( !A.constants )
exit( OVERFLOW );
A.constants[ dim - 1 ] = 1; //L=1,指针的递减以元素的大小为单元
for( i = dim - 2; i>=0; --i ){
A.constants[ i ] = A.bounds[ i + 1 ] * A.constants[ i + 1 ];
}
return OK;
}
Status
DestroyArray( Array &A ){
//销毁数组A
if( !A.base ) return ERROR;
free( A.base ); A.base = NULL;
if( !A.bounds ) return ERROR;
free( A.bounds ); A.bounds = NULL;
if( !A.constants ) return ERROR;
free( A.constants ); A.constants = NULL;
return OK;
}
Status
Locate( Array A, va_list ap, int &off ){
//若ap指示的各下标值合法,则求出该元素在A中的相对地址off
off = 0;
for( i = 0; i<A.dim; ++i ){
ind = va_arg( ap, int );
if( ind < 0 || ind >= A.bounds[ i ] )
return OVERFLOW;
off + = A.constants[ i ] * ind;
}
return OK;
}
Status
Value( Array A, ElemType &e, ... ){
//A是n维数组,e为元素变量,随后是n个下标值。
//若各下标不超界,则e赋值为所指定的A的元素值,并返回OK。
va_start( var_arg, e );
if( ( result = Locate( A, var_arg, off )) <= 0 )
return result;
e = *( A.base + off );
return OK;
}
Status
Assgin( Array &A, ElemType e, ... ){
//A是n维数组,e为元素变量,随后是n个下标值
//若下标不超界,则将e的值赋给所指定的A的元素,并返回OK。
va_start( var_arg, e );
if( ( result = Locate( A, var_arg, off )) <= 0 )
return result;
*( A.base + off ) = e;
return OK;
}
3 矩阵的压缩存储
所谓压缩存储是指:为多个值相同的元只分配一个存储空间;对零元不分配空间。
假若值相同的元素或者零元素在矩阵中的分布有一定的规律,则我们称此类矩阵为特殊矩阵;反之,称为稀疏矩阵。
特殊矩阵在这不做讲解,以下仅为稀疏矩阵。
(1) 抽象数据类型稀疏矩阵的形式定义
ADT SparseMatrix{
数据对象:D = { aij | i = 1,2,…m; j = 1, 2, …, n; ai,j ϵ ElemSet ,m 和 n 分别称为矩阵的行数和列数 }
数据关系:R = { Row, Col }
Row = { <ai,j, ai,j+1> | 1<=i<=m,1<=j<=n-1}
Col = {<ai,j, ai+1,j> | 1<=i<=m-1,1<=j<=n }
基本操作:
CreateSMatrix( &M )
操作结果:创建稀疏矩阵M。
DestroySMatrix( &M )
初始条件:稀疏矩阵M存在。
操作结果:销毁稀疏矩阵M。
PrintSMatrix( M )
初始条件:稀疏矩阵M存在。
操作结果:输出稀疏矩阵M。
CopySMatrix( M, &T )
初始条件:稀疏矩阵M存在。
操作结果:由稀疏矩阵M复制得到T。
AddSMatrix( M , N, &Q )
初始条件:稀疏矩阵M与N的行数和列数对应相等。
操作结果:求稀疏矩阵和Q=M+N。
SubSMatrix( M , N, &Q )
初始条件:稀疏矩阵M与N的行数和列数对应相等。
操作结果:求稀疏矩阵差Q=M-N。
MultSMatrix( M , N, &Q )
初始条件:稀疏矩阵M的列数等于N的行数。
操作结果:求稀疏矩阵乘积Q=MxN。
TransposeSMatrix( M, &T )
初始条件:稀疏矩阵M存在。
操作结果:求稀疏矩阵M的转置矩阵T。
}ADT SparseMatrix
(2) 稀疏矩阵的三元组顺序存储表示
按照压缩存储的概念,只存储稀疏矩阵的非零元。因此,除了存储非零元的值外,还必须同时记下它的所在行和列的位置(i,j)。反之,一个三元组(i,j,aij)唯一确定了矩阵A是一个非零元。
#define MAXSIZE 12500 //假设非零元素个数的最大值为12500
typedef struct{
int i,j; //非零元的行下标和列下标
ElemType e;
}Triple;
typedef struct{
Triple data[ MAXSIZE +1 ]; //非零元三元组表,data[0]未用
int mu,nu,tu; //矩阵的函数,列数和非零元素个数
}TSMatrix;
(3) 稀疏矩阵的十字链表存储表示
typedef struct QLNode{
int i,j; //该非零元的行和列的下标
ElemType e;
struct QLNode *right,*down //该非零元所所在行表和列表的后继链域
}QLNode,*QLink;
typedef struct{
QLink *rhead,*chead; //行和列链表头指针向量基址
int mu,nu.tu; //稀疏矩阵的行数,列数和非零元个数
}CrossList;