數組
數組是將相同數據類型的元素按照一定順序排列而成的集合。由於存儲單元是一維結構,而數據是多維的結構,則用一組連續存儲單元存放數組元素就有個次序約定問題,這也就是數組結構產生的原因。
下面我們看下簡單的數組是如何實現的:
#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<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)
return ERROR;
A.constants = (int*)malloc(dim*sizeof(int));
if(!A.constants)
return ERROR;
A.constants[dim-1] = 1;
for(i=dim-2;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.dim ;i++){
idx = va_arg(ap,int);
if(idx<0 || idx >=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.dim ;i++){
idx = va_arg(ap,int);
if(idx<0 || idx >=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.i<M.data[i-1].i || T.i==M.data[i-1].i &&T.j<=M.data[i-1].j)
k=1;
}while(k);
M.data[i]=T;
}
return OK;
}
int comp(int c1,int c2)
{
if(c1<c2)
return -1;
if(c1==c2)
return 0 ;
return 1;
}
Status add_matrix(TSMatrix M,TSMatrix N,TSMatrix &Q)
{
int m=1,n=1,q=0;
if(M.mu!=N.mu || M.nu!=N.nu)
return ERROR;
Q.mu=M.mu;
Q.nu=M.nu;
while(m<=M.tu && n<=N.tu){
switch(comp(M.data[m].i,N.data[n].i)){
case -1:
Q.data[++q]=M.data[m++];
break;
case 0:
switch(comp(M.data[m].j,N.data[n].j)){
case -1:
Q.data[++q]=M.data[m++];
break;
case 0 :
Q.data[++q]=M.data[m++];
Q.data[q].e +=N.data[n++].e;
if(Q.data[q].e==0)
q--;
break;
case 1:Q.data[++q]=N.data[n++];
break;
}
break;
case 1:
Q.data[++q]=N.data[n++];
break;
}
}
while(m<=M.tu)
Q.data[++q]=M.data[m++];
while(n<=N.tu)
Q.data[++q]=N.data[n++];
if(q>MAX_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].i<i)
p++;
while(T.data[q].i<j)
q++;
while(p<=M.tu && q<=T.tu&&M.data[p].i==i && T.data[q].i==j){
switch(comp(M.data[p].j,T.data[q].j)){
case -1:
p++;
break;
case 0:
Qs+=M.data[p++].e*T.data[q++].e;
break;
case 1:
q++;
break;
}
if(Qs){
if(++Q.tu>MAX_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<M.nu;i++):
do
對於每個非零元素e
if e的列號爲當前矩陣的行號
將e的轉置爲X中的非零元素
end
這個算法由於每次都要遍歷每個非零元素,算法複雜度爲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