抽象数据类型的数组的顺序表示和实现
n维数组的数据元素存储位置的计算公式
#include<stdio.h>
#include<stdlib.h>
#include<stdarg.h> //提取宏va_start,va_arg,va_end;用于存储变长参数表
#define MAX_ARRAY_DIM 8 //假设数组维数最大为8
#define ElemType int
#define Status int
typedef struct {
ElemType * base; //数组元素基址,由InitArray分配一个大小为所有元素的空间。
int dim; //数组维数
int * bounds; //数组维界基址,由InitArray分配。存储各维长度即变长参数内容
int * constants; //数组映像函数常量基址,由InitArray分配,计算得出。存储Ci(1<=i<=n)
}Array;
Status InitArray(Array &A, int dim,...);//若维数dim和随后的各维长度合法,构造相应的数组A,并返回1
Status DextoryArray(Array &A);
Status Value(Array A, ElemType &e,...);//A是n维数组,e为元素变量,随后是n个下标值。若下标不越界,则将指定的A的元素的值赋值给e。就是取数函数
Status Assign(Array &A, ElemType e,...);//A是n维数组,e为元素变量,随后是n个下标值。若下标不越界,则将e的值赋值给所指定的A的元素。就是给数组赋值函数。
Status InitArray(Array &A, int dim,...){
if(dim<1 || dim>MAX_ARRAY_DIM) return 0;
A.dim = dim;
A.bounds = (int *)malloc(dim*sizeof(int));
int elemtotal = 1; //A的元素总数
va_list ap; //存放变长参数表信息的数组
va_start(ap,dim);
for(int i=0;i<dim;i++){
A.bounds[i] = va_arg(ap,int); //存放各维长度即变长参数的内容
if(A.bounds[i]<0) return 0;
elemtotal *= A.bounds[i];
}
va_end(ap);
A.base = (ElemType *)malloc(elemtotal*sizeof(ElemType));
A.constants = (int *)malloc(dim*sizeof(int));//存放映像函数的常数Ci
A.constants[dim-1] = 1; //Cn = L = 1;指针的增减以元素大小为单位
for(int i=dim-2;i>=0;--i)
A.constants[i] = A.bounds[i+1] * A.constants[i+1]; //C(i-1) = Bi * Ci 1<i<=n
return 1;
}
Status DestroyArray(Array &A){
if(!A.base || !A.bounds || !A.constants) return 0;
free(A.base); A.base = NULL;
free(A.bounds); A.bounds = NULL;
free(A.constants); A.constants = NULL;
return 1;
}
Status Locate(Array A, va_list ap, int &off){
//若ap指示的下标合法,求出该元素在A中的相对位置
off = 0;
for(int i=0;i<A.dim;i++){
int ind = va_arg(ap,int);
if(ind<0 || ind>=A.bounds[i]) return 0;
off += ind*A.constants[i]; // Ji*Ci(0<=i<dim)
}
return 1;
}
Status Value(Array A, ElemType &e, ...){
//取数
va_list ap;
va_start(ap,e);
int result,off;
if( (result=Locate(A,ap,off))<0 ) return result;
e = A.base[off];
return 1;
}
Status Assign(Array &A, ElemType e, ...){
//赋值给数组
va_list ap;
va_start(ap,e);
int result,off;
if( (result=Locate(A,ap,off))<0 ) return result;
A.base[off] = e;
return 1;
}
int main(){
Array A;
int dim1=2,dim2=3,dim3=2,e;
InitArray(A,3,dim1,dim2,dim3);
for(int i=0;i<dim1;i++)
for(int j=0;j<dim2;j++)
for(int k=0;k<dim3;k++){
scanf("%d",&e);
Assign(A,e,i,j,k);
}
for(int i=0;i<dim1;i++)
for(int j=0;j<dim2;j++)
for(int k=0;k<dim3;k++){
Value(A,e,i,j,k);
printf("%d ",e);
}
return 1;
}
矩阵的压缩存储
对称矩阵、下(上)三角矩阵、三对角矩阵;稀疏矩阵
三元组顺序表:矩阵转置,快速转置
行逻辑链接的顺序表:稀疏矩阵相乘
#include<stdio.h>
#define MAXSIZE 50 //非零元个数的最大值#
#define MAXRC 20 //行数的最大值
typedef int ElemType;
typedef struct{
int i,j; //1<=i<=mu;1<=j<=nu
ElemType e;
}Triple;
typedef struct {
Triple data[MAXSIZE+1]; //0号位置弃用.以行序为主序顺序存储
int mu,nu,tu; //行数,列数,非零元个数
}TSMatrix;
/*
* 矩阵转置
* 待转置矩阵M,转置后矩阵T
* 为了得到T的每一行的非零元素,需要对M按列进行搜索。即扫描M的稀疏矩阵n遍,每一遍可以找到M的某一列的非零元素即T的某一行的非零元素。
* 复杂度是O(tu*nu)
* 如果矩阵不够稀疏,tu和mu*nu同等数量级,复杂度就变成了O(mu*nu*nu)
* 所以只适用于tu<<mu*nu
*/
int TransposeSMatrix(TSMatrix M, TSMatrix &T){
T.mu = M.nu; T.nu = M.mu; T.tu = M.tu;
if(!T.tu) return 0;
int q=1;
for(int col=1;col<=M.nu;col++)
for(int j=1;j<=M.tu;j++)
if(M.data[j].j==col){
T.data[q].i = M.data[j].j;
T.data[q].j = M.data[j].i;
T.data[q].e = M.data[j].e;
q++;
}
return 1;
}
/*
* 另一种转置方法:快速转置
* 设置num[col]表示M的第col列的非零元的个数
* 设置cpot[col]表示M的第col列的第一个非零元在T.Number[]中的位置
* 时间复杂度为O(tu+nu).如果tu和mu*nu同等数量级,复杂度就变成了O(mu*nu),和经典算法的复杂度相同
*/
int FastTransposeSMatrix(TSMatrix M, TSMatrix &T){
T.mu = M.nu; T.nu = M.mu; T.tu = M.tu;
if(!T.tu) return 0;
int num[MAXSIZE]={0},cpot[MAXSIZE];
for(int i=1;i<=M.tu;i++) num[M.data[i].j]++;
cpot[1]=1;
for(int col=2;col<=M.nu;col++) cpot[col] = cpot[col-1]+num[col-1];
for(int t=1;t<=M.tu;t++){
int col = M.data[t].j;
T.data[cpot[col]].i = M.data[t].j;
T.data[cpot[col]].j = M.data[t].i;
T.data[cpot[col]].e = M.data[t].e;
cpot[col]++;
}
return 1;
}
void InitMatrix(TSMatrix &M, int a, int b){
M.mu = a; M.nu = b;
ElemType e;
int p=0;
printf("Init(%d*%d):\n",a,b);
for(int i=1;i<=M.mu;i++)
for(int j=1;j<=M.nu;j++){
scanf("%d",&e);
if(!e) continue;
p++;
M.data[p].i = i;
M.data[p].j = j;
M.data[p].e = e;
}
M.tu = p;
printf("\n");
}
void print(TSMatrix M){
for(int i=1;i<=M.tu;i++)
printf("%d %d %d\n",M.data[i].i,M.data[i].j,M.data[i].e);
printf("\n");
}
/* 行逻辑链接的顺序表
*
* 三元组顺序表又称有序的双下标法,它的特点是,非零元在表中按行有序存储,这样便于进行依行顺序处理的矩阵运算。
* 但是,若是按行号存取某一行的非零元,则需从头开始查找。
* 所以,可以可将快速转置中的辅助数组cpot固定在稀疏矩阵的存储结构中。
* 称这种“带行链信息”的三元组表为 行逻辑链接的顺序表
* 描述如下
*/
typedef struct {
Triple data[MAXSIZE+1]; //0号位置弃用.以行序为主序顺序存储
int mu,nu,tu; //行数,列数,非零元个数
int rpos[MAXRC+1]; //各行第一个非零元的位置表
}RLSMatrix;
/*
* 矩阵相乘
* 1经典思路:笨办法.M是m1*n1,N是m2*n2,且n1=m2.复杂度O(m1*n1*n2)
* 2矩阵是行逻辑链接存储表示,借用辅助数组rpos
* 时间复杂度( O(M.tu*N.tu/N.mu+M.nu*N.nu) )
*/
//使用三元组相乘
int MultSMatrix(RLSMatrix M, RLSMatrix N, RLSMatrix &Q){
if(M.nu != N.mu) return 0;
Q.mu = M.mu; Q.nu = N.nu; Q.tu=0;
if(M.tu * N.tu == 0) return 0; //M和N存在零矩阵
for(int arow=1; arow<=M.mu; arow++){
int ctemp[MAXRC]={0}; //临时存储Q当前行的元素,最后压缩存储成三元组
Q.rpos[arow] = Q.tu+1; //Q的辅助数组
int tp=0,t=0; //分别记录M和N的当前行的最后一个非零元的位置+1
tp=(arow<M.mu)?M.rpos[arow+1]:M.tu+1;
for(int p=M.rpos[arow];p<tp;p++){ //找出当前行所有元素在三元组中的位置
int brow=M.data[p].j; //对于M当前行的每一个非零元,找出所在列brow,依据此列找N中的该行所有数
t = brow < N.mu ? N.rpos[brow + 1] : N.tu + 1; //找出N的brow行的数在三元组中的末尾位置
for(int q=N.rpos[brow];q<t;q++){ //循环N的brow行的元素
int col = N.data[q].j;
ctemp[col] += M.data[p].e * N.data[q].e;
}
}//求出了Q的arow行的元素
//压缩存储Q当前行
for(int col=1;col<=Q.nu;col++)
if(ctemp[col]){
if(++Q.tu>MAXSIZE) return 0;
Q.data[Q.tu] = {arow,col,ctemp[col]};
}
}
return 1;
}
void InitRLSMatrix(RLSMatrix &M, int a, int b){
M.mu = a; M.nu = b;
ElemType e;
int p=0;
M.rpos[0]=1;
int sign,num[MAXRC+1]={0};
printf("Init(%d*%d):\n",a,b);
for(int i=1;i<=M.mu;i++){
num[i]=0;
sign=0;
for(int j=1;j<=M.nu;j++){
scanf("%d",&e);
if(!e) continue;
p++;
M.data[p].i = i;
M.data[p].j = j;
M.data[p].e = e;
if(sign==0){
M.rpos[i]=p;
sign=1;
}
num[i]++;
}
if(sign==0) M.rpos[i] = M.rpos[i-1]+num[i-1]; //防止某一行没有非零元
}
M.tu = p;
printf("\n");
}
void print(RLSMatrix M){
for(int i=1;i<=M.tu;i++)
printf("%d %d %d\n",M.data[i].i,M.data[i].j,M.data[i].e);
printf("\n");
}
int main(){
// TSMatrix M,T;
// InitMatrix(M,6,7);
// print(M);
// TransposeSMatrix(M,T);
// print(T);
//
// FastTransposeSMatrix(T,M);
// print(M);
RLSMatrix M,T,Q;
InitRLSMatrix(M,3,4);
InitRLSMatrix(T,4,2);
MultSMatrix(M,T,Q);
print(Q);
return 1;
}
/*
0 12 9 0 0 0 0
0 0 0 0 0 0 0
-3 0 0 0 0 14 0
0 0 24 0 0 0 0
0 18 0 0 0 0 0
15 0 0 -7 0 0 0
*/
/*
3 0 0 5
0 -1 0 0
2 0 0 0
0 2
1 0
-2 4
0 0
*/
十字链表
广义表
暂时不写,先写后面的树、图