BDS之数组与矩阵

数组

数组是将相同数据类型的元素按照一定顺序排列而成的集合。由于存储单元是一维结构,而数据是多维的结构,则用一组连续存储单元存放数组元素就有个次序约定问题,这也就是数组结构产生的原因。

下面我们看下简单的数组是如何实现的:

#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]为

BDS之数组与矩阵_第1张图片

矩阵

矩阵是一个数学概念,但是它在计算机中的表现形式是基于二维数组的。这里我们主要关注稀疏矩阵,所谓稀疏矩阵是指在矩阵中非零元素较少,且分布没有规律。更为准确的描述是假设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");
	}
}

这里,我们看看矩阵转置的操作。矩阵的转置是将矩阵中元素的行列位置进行互换。这里我们讨论稀疏矩阵的转置,对于一个矩阵A,如:

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




你可能感兴趣的:(基础数据结构,数组,矩阵,数据结构)