[数据结构]第五章-数组和广义表(读书笔记1)

第五章-数组和广义表

数组和广义表可以看成是线性表在下述含义上的扩展:表中的数据元素本身也是一个数据结构。

5.1 数组的定义
当n=1时,n维数组就退化为定长的线性表。反之,n维数组也可以看成是线性表的推广。数组一旦被定义,它的维数和维界就不再改变。
typedef ElemType Array2[m][n];
等价于
typedef ElemType Array1[n];
typedef Array1 Array2[m];

5.2 数组的顺序表示和实现
对于数组,一旦规定了它的维数和各维的长度,便可为它分配存储空间。下面是顺序存储表示和实现。

/*标准头文件,提供宏va_start,va_arg和va_end*/
/*用于存取变长参数表*/
#include <stdarg.h>	
/*假设数组维数的最大值为8*/
#define MAX_ARRAY_DIM 8 
typedef int ElemType;

typedef struct{
	/*数组元素基址,由InitArray分配*/
	ElemType *base;
	/*数组维数*/
	int dim;
	/*数组维界基址,由InitArray分配*/
	int *bounds;
	/*数组映像函数常量基址,由InitArray分配*/
	int *constants;
}Array;

Status InitArray(Array *A, int dim,...)
{/*若维数dim和各维长度合法,则构造相应的数组A,并返回OK*/
	int elemtotal;
	int 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){
		exit(OVERFLOW);
	}
	/*若各维长度合法,则存入A.bounds,并求出A的元素总数elemtotal*/
	elemtotal = 1;
	/*ap为va_list类型,是存放变长参数表信息的数组*/
	va_start(ap,dim);
	for (i = 0; i < dim; ++i){
		A->bounds[i] = va_arg(ap,int);
		if (A->bounds[i] < 0){
			return UNDERFLOW;
		}
		elemtotal += A->bounds[i];
	}
	va_end(ap);
	A->base = (ElemType*)malloc(elemtotal * sizeof(ElemType));
	if (!A->base){
		exit(OVERFLOW);
	}
	/* 求映像函数的常数c,并存入A.constants[i-1],i=1,...dim */
	A->constants = (int *)malloc(dim * sizeof(int));
	if(!A->constants){
		exit(OVERFLOW);
	}
	/*数组最后一维肯定是1,数组的增减以元素大小为单位*/
	A->constants[dim - 1] = 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*/
	int i;
	int ind;
	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,...)
{
	Status result;
	int off;
	va_list ap;
	va_start(ap,e);
	if ((result = Locate(*A,ap,off)) <= 0){
		return result;
	}
	*e = *(A->base + off);
	return OK;
}
Status Assign(Array *A, ElemType e,...)
{/*A是n维数组,e为元素变量,随后是n个下标值*/
 /*若下标不超界,则将e的值赋给所指定的A的元素,并返回OK*/
	Status result;
	int off;
	va_list ap;
	va_start(ap,e);
	if ((result = Locate(*A,ap,off)) <= 0){
		return result;
	}
	*(A->base + off) = e;
	return OK;
}
int _tmain(int argc, _TCHAR* argv[])
{
   Array A;
   int i,j,k,*p,dim = 3,bound1 = 3,bound2 = 4,bound3 = 2; /* a[3][4][2]数组 */
   ElemType e,*p1;
   InitArray(&A,dim,bound1,bound2,bound3); /* 构造3*4*2的3维数组A */
   p=A.bounds;
   printf("A.bounds=");
   for(i=0;i<dim;i++) /* 顺序输出A.bounds */
     printf("%d ",*(p+i));
   p=A.constants;
   printf("\nA.constants=");
   for(i=0;i<dim;i++) /* 顺序输出A.constants */
     printf("%d ",*(p+i));
   printf("\n%d页%d行%d列矩阵元素如下:\n",bound1,bound2,bound3);
   for(i=0;i<bound1;i++)
   {
     for(j=0;j<bound2;j++)
     {
       for(k=0;k<bound3;k++)
       {
         Assign(&A,i*100+j*10+k,i,j,k); /* 将i*100+j*10+k赋值给A[i][j][k] */
         Value(&A,&e,i,j,k); /* 将A[i][j][k]的值赋给e */
         printf("A[%d][%d][%d]=%2d ",i,j,k,e); /* 输出A[i][j][k] */
       }
       printf("\n");
     }
     printf("\n");
   }
   p1=A.base;
   printf("A.base=\n");
   for(i=0;i<bound1*bound2*bound3;i++) /* 顺序输出A.base */
   {
     printf("%4d",*(p1+i));
     if(i%(bound2*bound3)==bound2*bound3-1)
       printf("\n");
   }
   DestroyArray(&A);
	return 0;
}

5.3 矩阵的压缩存储

矩阵的压缩存储:为多个值相同的元只分配一个存储空间,对零元不分配空间。假若值相同的元素或者零元素在矩阵中的分布有一定规律,则我们称此类矩阵为特殊矩阵;反之称为稀疏矩阵。

5.3.1 特殊矩阵
对于对称矩阵,我们可以为每一对对称元分配一个存储空间,则可将n2个元压缩存储到n(n+1)/2个元的空间中。
所谓下(上)三角矩阵是指矩阵的上(下)三角(不包括对角线)中的元均为常数c或零的n阶矩阵。
对这类矩阵,我们也可按某个原则(或以行为主,或以对角线的顺序)将其压缩存储到一维数组上。
5.3.2 稀疏矩阵
其非零元较零元少,且分布没有一定规律,我们称之为稀疏矩阵。按照压缩存储的概念,只存储稀疏矩阵的非零元。因此除了存储非零元的值之外,还必须同时记下它所在行和列的位置(i,j)。

typedef int ElemType;
#define MAXSIZE 100 /* 非零元个数的最大值 */
/* 三元组顺序表:稀疏矩阵的一种压缩存储算法 */
typedef struct {
	int i,j;/* 行下标,列下标 */
	ElemType e;/* 非零元素值 */
}Triple;

typedef struct {
	Triple data[MAXSIZE + 1];	/* 非零元三元组表,data[0]未用 */
	int mu,nu,tu;				/* 矩阵的行数、列数和非零元个数 */
}TSMatrix;

Status CreateSMatrix(TSMatrix *M)
{ /* 创建稀疏矩阵M */
	int i;
	int m,n,e;
	Status k;
	
	printf("请输入矩阵的行数,列数,非零元素数:");	
	scanf("%d,%d,%d",&(*M).mu,&(*M).nu,&(*M).tu);
	(*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", &m, &n, &e);
			k = 0;
			if(m < 1 || m > (*M).mu || n < 1 || n > (*M).nu){ /* 行或列超出范围 */
				k = 1;
			}
			if(m <= (*M).data[i-1].i && n <= (*M).data[i-1].j){ /* 行或列的顺序有错 */
				k = 1;
			}
		}while(k);
		(*M).data[i].i = m;
		(*M).data[i].j = n;
		(*M).data[i].e = e;
	}
	return OK;
}

void DestroySMatrix(TSMatrix *M)
{ /* 销毁稀疏矩阵M */
	(*M).mu = 0;
	(*M).nu = 0;
	(*M).tu = 0;
}
void PrintSMatrix(TSMatrix M)
{ /* 输出稀疏矩阵M */
	int i;
	printf("%d行%d列%d个非零元素。\n", M.mu, M.nu, M.tu);
	printf("行  列  元素值\n");
	for(i = 1; i <= M.tu; i++){
		printf("%2d%4d%8d\n", M.data[i].i, M.data[i].j, M.data[i].e);
	}
}
Status CopySMatrix(TSMatrix M,TSMatrix *T)
{ /* 由稀疏矩阵M复制得到T */
	(*T) = M;
	return OK;
}
/*
 1)将矩阵的行列值相互交换
 2)将每个三元组中的i和j相互调换
 3)重排三元组之间的次序便可实现矩阵的转置
*/
Status TransposeSMatrix(TSMatrix M, TSMatrix *T)
{ /* 求稀疏矩阵M的转置矩阵T。算法5.1 */
	int q;
	int col,p;
	(*T).mu = M.mu;/*矩阵的行*/
	(*T).nu = M.nu;/*矩阵的列*/
	(*T).tu = M.tu;/*非零元个数*/
	/*算法的时间复杂度为O(nu*tu),即和M的列数及非零元的个数的乘积成正比*/
	if ((*T).tu != 0){
		q = 1;
		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;
					++q;
 				}
			}		
		}
	}
	return OK;
}
int comp(int c1,int c2) /* 另加 */
{ /* AddSMatrix函数要用到 */
	int i;
	if(c1 < c2){
		i = 1;
	}
	else if(c1 == c2){
		i = 0;
	}
	else{
		i = -1;
	}
	return i;
}
Status AddSMatrix(TSMatrix M, TSMatrix N, TSMatrix *Q)
{ /* 求稀疏矩阵的和Q=M+N */
	Triple *Mp,*Me,*Np,*Ne,*Qh,*Qe;
	if(M.mu != N.mu || M.nu != N.nu){
		return ERROR;
	}
	(*Q).mu = M.mu;
	(*Q).nu = M.nu;
	Mp = &M.data[1]; /* Mp的初值指向矩阵M的非零元素首地址 */
	Np = &N.data[1]; /* Np的初值指向矩阵N的非零元素首地址 */
	Me = &M.data[M.tu]; /* Me指向矩阵M的非零元素尾地址 */
	Ne = &N.data[N.tu]; /* Ne指向矩阵N的非零元素尾地址 */
	Qh = Qe = (*Q).data; /* Qh、Qe的初值指向矩阵Q的非零元素首地址的前一地址 */
	while( Mp <= Me && Np <= Ne ){
		Qe++;
		switch(comp(Mp->i, Np->i)){
			case  1: 
				*Qe = *Mp;
				Mp++;
				break;
			case  0: 
				switch(comp(Mp->j,Np->j)){ /* M、N矩阵当前非零元素的行相等,继续比较列 */
				case  1: 
					*Qe = *Mp;
					Mp++;
					break;
				case  0: 
					*Qe = *Mp;
					Qe->e += Np->e;
					if(!Qe->e){ /* 元素值为0,不存入压缩矩阵 */
						Qe--;
					}
					Mp++;
					Np++;
					break;
				case -1: 
					*Qe = *Np;
					Np++;
					break;
                }//switch
                break;
		case -1: 
			*Qe = *Np;
			Np++;
			break;
		}//switch
	}
	if(Mp > Me){ /* 矩阵M的元素全部处理完毕 */
		while(Np <= Ne){
			Qe++;
			*Qe = *Np;
			Np++;
		}
	}
	if(Np > Ne){ /* 矩阵N的元素全部处理完毕 */
		while(Mp <= Me){
			Qe++;
			*Qe = *Mp;
			Mp++;
		}
	}
	(*Q).tu = Qe - Qh; /* 矩阵Q的非零元素个数 */
	return OK;
}

Status SubtSMatrix(TSMatrix M, TSMatrix N, TSMatrix *Q)
{ /* 求稀疏矩阵的差Q=M-N */
   int i;
   for(i = 1; i <= N.tu; i++){
	   N.data[i].e *= -1;
   }
   AddSMatrix(M,N,Q);
   return OK;
}

Status MultSMatrix(TSMatrix M, TSMatrix N, TSMatrix *Q)
{ /* 求稀疏矩阵的乘积Q=M*N */
	int i,j,h=M.mu,l=N.nu,Qn=0;
	/* h,l分别为矩阵Q的行、列值,Qn为矩阵Q的非零元素个数,初值为0 */
	ElemType *Qe;
	if(M.nu != N.mu){
		return ERROR;
	}
	(*Q).mu = M.mu;	/*行数*/
	(*Q).nu = N.nu;	/*列数*/	
	Qe = (ElemType *)malloc(h * l * sizeof(ElemType)); /* Qe为矩阵Q的临时数组 */
	/* 矩阵Q的第i行j列的元素值存于*(Qe+(i-1)*l+j-1)中,初值为0 */
	for(i = 0; i < h * l; i++){
		*(Qe + i) = 0; /* 赋初值0 */
	}
	for(i = 1; i <= M.tu; i++){ /* 矩阵元素相乘,结果累加到Qe */
		for(j = 1; j <= N.tu; j++){
			if(M.data[i].j == N.data[j].i){
				*(Qe + (M.data[i].i - 1) * l + N.data[j].j - 1) += M.data[i].e * N.data[j].e;
			}
		}
	}
	for(i = 1; i <= M.mu; i++){
		for(j = 1;j <= N.nu; j++){
			if(*(Qe+(i-1)*l+j-1)!=0){
				Qn++;
			}
			(*Q).data[Qn].e = *(Qe + (i - 1) * l + j - 1);
			(*Q).data[Qn].i = i;
			(*Q).data[Qn].j = j;
		}
	}
	free(Qe);
	(*Q).tu = Qn;
	return OK;
}
int _tmain(int argc, _TCHAR* argv[])
{
	TSMatrix A,B,C;
	printf("创建矩阵A: ");
	CreateSMatrix(&A);
	PrintSMatrix(A);
	printf("由矩阵A复制矩阵B: ");
	CopySMatrix(A,&B);
	PrintSMatrix(B);
	DestroySMatrix(&B);
	printf("销毁矩阵B后:\n");
	PrintSMatrix(B);
	printf("创建矩阵B2:(与矩阵A的行、列数相同,行、列分别为%d,%d)\n",A.mu,A.nu);
	CreateSMatrix(&B);
	PrintSMatrix(B);
	printf("矩阵C1(A+B): ");
	AddSMatrix(A,B,&C);
	PrintSMatrix(C);
	DestroySMatrix(&C);
	printf("矩阵C2(A-B): ");
	SubtSMatrix(A,B,&C);
	PrintSMatrix(C);
	DestroySMatrix(&C);
	printf("矩阵C3(A的转置): ");
	TransposeSMatrix(A,&C);
	PrintSMatrix(C);
	DestroySMatrix(&A);
	DestroySMatrix(&B);
	DestroySMatrix(&C);
	printf("创建矩阵A2: ");
	CreateSMatrix(&A);
	PrintSMatrix(A);
	printf("创建矩阵B3:(行数应与矩阵A2的列数相同=%d)\n",A.nu);
	CreateSMatrix(&B);
	PrintSMatrix(B);
	printf("矩阵C5(A*B): ");
	MultSMatrix(A,B,&C);
	PrintSMatrix(C);
	DestroySMatrix(&A);
	DestroySMatrix(&B);
	DestroySMatrix(&C);
	return 0;
}


  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

进击的横打

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值