数组是将相同数据类型的元素按照一定顺序排列而成的集合。由于存储单元是一维结构,而数据是多维的结构,则用一组连续存储单元存放数组元素就有个次序约定问题,这也就是数组结构产生的原因。
下面我们看下简单的数组是如何实现的:
#define MAX_ARRAY_DIM 8
#define ERROR -1
#define OK 0
#define UNDERFLOW 4
#define OVERFLOW -2
typedef int Status;
struct Array
{
ElemType* base; //数组元素基址
int dim; //数组维数
int *bounds; //数组维界基址
int *constants;//数组映像函数常量基址
};
//init array
Status init_array(Array &A,int dim,...)
{
int elemtotal = 1,i;
va_list ap;
if(dim<1 || dim>MAX_ARRAY_DIM)
return ERROR;
A.dim = dim;
A.bounds = (int*)malloc(dim*sizeof(int));
if(!A.bounds)
return ERROR;
va_start(ap,dim);
for(i=0;i=0;i--)
A.constants[i]= A.constants[i+1]*A.bounds[i+1];
return OK;
}
void destroy_array(Array &A)
{
if(A.base)
free(A.base);
if(A.bounds)
free(A.bounds);
if(A.constants)
free(A.constants);
A.base = A.bounds = A.constants = NULL;
A.dim = 0;
}
Status locate(Array A,va_list ap,int &off)
{
int i,idx ;
off = 0;
return OK;
}
Status value(ElemType &e,Array A,...)
{
va_list ap;
int i,off=0,idx;
va_start(ap,A);
for(i = 0;i=A.bounds[i])
return ERROR;
off += A.constants[i]*idx;
}
e = *(A.base+off);
return OK;
}
Status assign(Array &A,ElemType e,...)
{
va_list ap;
int i,idx,off=0;
va_start(ap,e);
for(i = 0;i=A.bounds[i])
return ERROR;
off += A.constants[i]*idx;
}
*(A.base+off)=e;
return OK;
}
我们知道数组支持随机存储访问,那么对于数组结构,访问元素的形式才是需要关注的重点,对于一个n维的矩阵,每一维大小为b1,b2,...bn,那么如果给定索引j1,j2,...jn,那么要取得该元素,就需要求其在数组存储单元中的偏移量LOC[j1,j2,...jn]为
矩阵是一个数学概念,但是它在计算机中的表现形式是基于二维数组的。这里我们主要关注稀疏矩阵,所谓稀疏矩阵是指在矩阵中非零元素较少,且分布没有规律。更为准确的描述是假设m×n的矩阵中,有t个元素不为零。令δ=t/(m×n),称δ为矩阵的稀疏因子,通常认为δ<=0.05时称为稀疏矩阵。
下面是基于三元组顺序表的稀疏矩阵压缩存储方式:
typedef int Status ;
#define ERROR -1;
#define OK 0;
//稀疏矩阵的三元组顺序表存储结构
#define MAX_SIZE 100
struct Triple
{
int i,j;//行、列索引
ElemType e;
};
struct TSMatrix
{
Triple data[MAX_SIZE+1];//data[0]未用
int mu,nu,tu;//行数、列数、非零元素数
};
Status create_matrix(TSMatrix &M)
{
int i;
Triple T;
Status k;
printf("请输入矩阵的行数、列数以及非零元素个数:");
scanf("%d,%d,%d",&M.mu,&M.nu,&M.tu);
if(M.tu>MAX_SIZE)
return ERROR;
M.data[0].i = 0;
for(i=1;i<=M.tu;i++){
do{
printf("请按行序顺序输入第%d个非零元素所在的行(1~%d),列(1~%d),元素值:",i,M.mu,M.nu);
scanf("%d,%d,%d",&T.i,&T.j,&T.e);
k=0;
if(T.i<1 || T.i>M.mu || T.j<1 || T.j>M.nu)
k=1;
if(T.iMAX_SIZE)
return ERROR;
Q.tu=q;
return OK;
}
Status sub_matrix(TSMatrix M,TSMatrix N,TSMatrix &X)
{
int i;
if(M.mu!=N.mu || M.nu!=N.nu)
return ERROR;
for(i=1;i<=N.tu;++i)
N.data[i].e*=-1;
add_matrix(M,N,X);
return OK;
}
//转置
void transpose(TSMatrix M,TSMatrix &T)
{
int p,col,q=1;
T.mu = M.nu;
T.nu = M.mu;
T.tu = M.tu;
if(T.tu){
for(col=1;col<=M.nu;++col)
for(p=1;p<=M.tu;++p)
if(M.data[p].j==col){
T.data[q].i=M.data[p].j;
T.data[q].j=M.data[p].i;
T.data[q++].e=M.data[p].e;
}
}
}
//快速转置
Status fast_transpose(TSMatrix M,TSMatrix &T)
{
int p,q;
int col,t;
T.mu = M.nu;
T.nu = M.mu;
T.tu = M.tu;
int* num = (int*)malloc((M.nu+1)*sizeof(int));
if(!num)
return ERROR;
int* cpot=(int*)malloc((M.nu+1)*sizeof(int));
if(!cpot)
return ERROR;
if(T.tu){
for(col=1;col<=M.nu;++col)
num[col]=0;
for(t=1;t<=M.tu;++t)
++num[M.data[t].j];
cpot[1]=1;
for(col=2;col<=M.nu;++col)
cpot[col]=cpot[col-1]+num[col-1];
for(p=1;p<=M.tu;++p){
col=M.data[p].j;
q=cpot[col];
T.data[q].i=M.data[p].j;
T.data[q].j=M.data[p].i;
T.data[q].e=M.data[p].e;
++cpot[col];
}
}
free(num);
free(cpot);
return OK;
}
void copy_matrix(TSMatrix M,TSMatrix &T)
{
T=M;
}
void destroy_matrix(TSMatrix &M)
{
M.mu=M.nu=M.tu = 0;
}
Status mult_matrix(TSMatrix M,TSMatrix N,TSMatrix &Q)
{
int i,j,p,q;
ElemType Qs;
TSMatrix T;
if(M.nu!=N.mu)
return ERROR;
Q.mu=M.mu;
Q.nu=N.nu;
Q.tu=0;
transpose(N,T);
for(i=1;i<=Q.mu;i++){
q=1;
for(j=1;j<=T.mu;j++){
Qs=0;
p=1;
while(M.data[p].iMAX_SIZE)
return ERROR;
Q.data[Q.tu].i=i;
Q.data[Q.tu].j=j;
Q.data[Q.tu].e=Qs;
}
}
}
}
return OK;
}
void print_matrix(TSMatrix M)
{
int i,j,k=1;
Triple *p=M.data+1;
for(i=1;i<=M.mu;i++){
for(j=1;j<=M.nu;j++){
if(k<=M.tu && p->i==i &&p->j==j){
printf("%3d",(p++)->e);
k++;
}else{
printf("%3d",0);
}
}
printf("\n");
}
}
1 0 2 0
0 3 0 4
0 0 5 0
其三元组的顺序表存储形式如下:
i j e
0 [0]
1 1 1 [1]
1 3 2 [2]
2 2 3 [3]
2 4 4 [4]
3 3 5 [5]
... ...
mu=3,nu=4,tu=5
这里需要注意的是,非零值按照一定的序列排序,转置过程需要保证非零元素的顺序,下面是矩阵转置的最简单的实现:
//将M转置
transport(MAtrix M,MAtrix &X):
begin:
X.mu = M.nu;
X.nu = M.mu;
X.tu = M.tu;
if 存在非零元素
for (i=1;i
这个算法由于每次都要遍历每个非零元素,算法复杂度为O(nu*tu)。
考虑,转置的关键问题在于,将i,j进行调换后将元素放置到data中合适的位置,如果我们能预先知道每一列(T中每一行)中的第一个非零元素在data中的位置,那么在将元素做转置操作时,便可直接放到data中的合适位置上去,为了求取每一列中第一个非零元素的位置,需要先求得每一列非零元素的个数。这里定义两个向量num和cpot,num[col]表示矩阵中第col列中非零元的数目,cpot[col]表示M中第col列的第一个非零元在data中的恰当位置。显然有
cpot[1]=1;
cpot[col]=cpot[col-1]+num[col-1] 2<=col<=M.nu
快速转置的算法实现如下:
fast_transpose(Matrix M,Matrix &X)
begin:
X.mu=M.nu;
X.nu=M.mu;
X.tu=M.tu;
if 存在非零元素
for i=1->M.nu
初始化num向量
for j=1->M.tu
求取每列中非零元素个数
cpot[1]=1;
for col=2->M.nu
求每列第一个非零元在data中的序号cpot向量
for p=1->M.tu
do:
取得非零元素的列号j;
通过cpot 取得第j列的第一个非零元素在data中的序号q
M.data[p].j ->X.data[q].i
M.data[p].i->X.data[q].j
M.data[p].e->X.data[q].e
第j列的第一个非零元素在data中序号递增
end