除了用三元组顺序表来存储压缩矩阵,我们还可以用链表结构来存储,实际上后者应用更广泛,因为当非零元素的数目较大时,三元组的时间复杂度实在太高。链表结构中最常见的是十字链表,在十字链表中,稀疏矩阵每一行用一个带头结点的循环链表表示,每一列也用一个带头结点的循环链表表示。在这个结构中,除头结点外,每个结点都代表矩阵中的一个非零元素,它由5个域组成:行域(row),列域(col),数据域(data),向下域(down)
和向右域(right)。
为了使所有结点的存储结构一致,规定表头结点的结构与非零元素的结点完全一致,只是将其行域和列域设置为0,由于每一行链表的表头(行头)和每一列链表的表头(列头)的行域和列域的值均为0,故这两组表头结点可以共用,即同行号,同列号的行头和列头共同存储在一个结点中,只是将其逻辑分开(实际上行头使用该结点的向右域,而列头使用该结点的向下域),起到资源共享的效果。由此可知,稀疏矩阵的十字链表存储表示的结点总数等于非零元素的个数加上行头和列头(两者共用标号相同的结点,实际上只要提供其中的较大者的个数就可以了),再加上总表头Head[0],其中总表头Head[0]的行域和列域分别存储矩阵的总行数和总列数,为节省空间,把矩阵非零元素的个数存储在Head[1]的行域。
//------稀疏矩阵的十字链表存储表示-------------------
#define MAXRC 100 //假设矩阵的行(列)数最多为100
typedef struct matnode
{
int row, col; //结点的行域和列域
struct matnode *right, *down;//结点的向下域(down)和向右域(right)
union //结点的数据域,若为表头结点则无数值,而用指向其后继的指针代替
{
ElemType data;
struct matnode *next;
} tag;
} CrossNode, *CrossList;
//---------------------------------------------------------------------------------
创建一个十字链表
void CreateHead(CrossList Head[], int len) //创建十字链表的表头结点
{
CrossList p;
int i;
p = (CrossList)malloc(sizeof(CrossNode));
if(!p)
{
puts("Error");
exit(1);
}
Head[0] = p; //生成总表头结点
for(i=1; i<=len; i++)//先初始化所有的行头(列头)
{
p = (CrossList)malloc(sizeof(CrossNode));
if(!p)
{
puts("Error");
exit(1);
}
Head[i] = p;
Head[i-1]->tag.next = p;//把表头结点按顺序连接起来
p->row = p->col = 0; //表头结点的行域和列域设置为0
p->down = p->rigth = p;//先将表头结点的行域和列域指向自身,以构成循环链表
} //for(i=1; i<=s; i++)
Head[s]->tag.next = Head[0];//最后一个表头结点的后继为总表头,即构成循环链表
}
void Insert(CrossList Head[], int r, int c, int v) //插入新的结点
{
CrossList q;
p = (CrossList)malloc(sizeof(CrossNode));
if(!p)
{
puts("Error");
exit(1);
}
p->row = r;
p->col = c;
p->tag.data = v;
q = Head[r]; //完成行插入
while(q->right != Head[r] && q->right->col < c)
q = q->right;
p->right = q->right;
q->right = p;
q = Head[c]; //完成列插入
while(q->down != Head[c] && q->down->row < r)
q = q->down;
p->down = q->down;
q->down = p;
}
CrossList CreateSMatrix_OL(int m, int n) //创建一个十字链表
{
int s; //非零元素个数t
int r, c, v;//分别表示元素的行号r,列号c,值v
int t = 0;
CrossList Head[MAXRC], p, q;
s = m>n ? m:n;//因为序号相同行头和列头共用一个结点,故只要分配s个表头结点就好了
CreateHead(Head, s);//创建十字链表的表头结点
puts("请按行序为主序依次输入矩阵的非零元素的行号,列号和元素值,每行输入一个元素的信息:");
printf("注意行号不能超过%d,列号不能超过%d,否则结束输入\n", m, n); //生成结点
do
{
scanf("%d%d%d", &r, &c, &v);
fflush(stdin);
if(r > 0 && r <= m && c > 0 && c <= n)
{
Insert(Head, r, c, v);
t++;
}
} while(r > 0 && r <= m && c > 0 && c <= n) ;
Head[0]->row = m; //总表头Head[0]的行域存储矩阵的总行数
Head[0]->col = n; //总表头Head[0]的列域存储矩阵的总列数
Head[1]->row = t; //非零元素的个数存储在Head[1]的行域
return Head[0]; //返回总表头结点
}
void PrintCrossList(CrossList T)//输出十字链表存储矩阵
{
int k = 0;
CrossList p, q; //p指向行头,q指向非零元素结点
printf("\n");
p = T->tag.next;
if(p == T) //如果非零元素个数不为零,存储其总行数和总列数
{
puts("非零元素个数为零");
exit(1);
}
while(p != T) //按行表顺序,把十字链表中的元素写入二维数组
{
q = p->right;
while(q != p) //注意二维数组的下标从0开始,而十字链表的行,列号从1开始
{
printf("T%d (%d,%d,%d)\t", ++k, q->row, q->col, q->tag.data);
q = q->right;
}
p = p->tag.next;
}
printf("\n");
}
二维数组存储稀疏矩阵和十字链表的相互转换
CrossList ArrayToCrossList(const int A[][N], int m, int n)//二维数组转换为十字链表
{
int s;
int i, j, k=0;
CrossList Head[MAXRC], p, q;
s = m>n ? m:n;//因为序号相同行头和列头共用一个结点,故只要分配s个表头结点就好了
CreateHead(Head, s);
for(i=0; i
{
k++;
Insert(Head, i+1, j+1, A[i][j]);
}//if(A[i][j] != 0)
Head[0]->row = m; //总表头Head[0]的行域存储矩阵的总行数
Head[0]->col = n; //总表头Head[0]的列域存储矩阵的总列数
Head[1]->row = k; //非零元素的个数存储在Head[1]的行域
return Head[0]; //返回总表头结点
}
void CrossListToArray(CrossList T, int A[][N], int *m, int *n)//十字链表转换为二维数组
{
int i, j, k;
CrossList p, q; //p指向行头,q指向非零元素结点
p = T->tag.next;
if(p != T) //如果非零元素个数不为零,存储其总行数和总列数
{
*m = T->row;
*n = T->col;
}
for(i=0; i<*m; i++) //先设所有元素均为0
for(j=0; j<*n; j++)
A[i][j] = 0;
while(p != T) //按行表顺序,把十字链表中的元素写入二维数组
{
q = p->right;
while(q != p) //注意二维数组的下标从0开始,而十字链表的行,列号从1开始
{
A[q->row-1][q->col-1] = q->tag.data;
q = q->right;
}
p = p->tag.next;
}
}
三元组顺序表存储稀疏矩阵和十字链表的相互转换
TSMatrix CrossListToTriple(CrossList T)//十字链表转换为三元组顺序表
{
CrossList p, q; //p指向行头,q指向非零元素结点
TSMatrix T;
int k;
p = T->tag.next;
if(p != T) //如果非零元素个数不为零,存储其总行数和总列数
{
T.mu = T->row;
T.nu = T->col;
}
k = 1;
while(p != T) //按行表顺序,把十字链表中的元素写入三元组顺序表
{
q = p->rigth;
while(q != p)
{
T.data[k].x = q->row;
T.data[k].y = q->col;
T.data[k].e = q->tag.data;
k++;
q = q->right;
}
p = p->tag.next;
}
T.tu = k-1;
return T;
}
CrossList TripleToCrossList(TSMatrix T)//三元组顺序表转换为十字链表
{
int i, s;
CrossList Head[MAXRC], p, q;
s = m>n ? m:n;//因为序号相同行头和列头共用一个结点,故只要分配s个表头结点就好了
CreateHead(Head, s);
for(i=0; i
Head[0]->row = T.mu; //总表头Head[0]的行域存储矩阵的总行数
Head[0]->col = T.nu; //总表头Head[0]的列域存储矩阵的总列数
Head[1]->row = T.tu; //非零元素的个数存储在Head[1]的行域
return Head[0]; //返回总表头结点
}
//-------------------------------------------------------------------------
1。转置矩阵
算法很简单,只要使新矩阵与原矩阵的行列值互换就好了。我们以行序为主序进行转置。
其函数如下;
bool TransposeCrossList(const CrossList M, CrossList *T) //十字链表存储转置矩阵
{
int i, s;
CrossList Head[MAXRC], p, q;
s = M->row > M->col ? M->row : M->col;//因为序号相同行头和列头共用一个结点,故只要分配s个表头结点就好了
CreateHead(Head, s);
p = M->tag.next;
while(p != M) //按行表顺序,进行转置
{
q = p->right;
while(q != p)
{
Insert(Head, q->col, q->row, q->tag.data);
q = q->right;
}
p = p->tag.next;
} //while(pm != T)
Head[0]->row = M->col;
Head[0]->col = M->row;
Head[1]->row = M->tag.next->row;
*T = Head[0]; //使新矩阵指向总表头
return 1;
}
2。矩阵相加
基本算法,依次扫描A和B的行列值,并且以行序为主序。当行列相同时,将两个元素值相加产生的结果插入结果链表中;不相同时,将A或B的结点直接插入结果链表中。
这种算法的时间复杂度为O(A.tu+B.tu),速度非常快。其函数如下;
CrossList AddSMatrix(const CrossList A, const CrossList B)//十字链表存储矩阵矩阵相加
{
int i, s, k=0;//k用来累积非零元素的个数
CrossList Head[MAXRC], pa, pb, qa, qb;
if(A->row != B->row || A->col != B->col)
{
puts("两个矩阵不是同类型的,不能相加");
exit(1);
}
else
{
s = A->row > A->col ? A->row : A->col;//因为序号相同行头和列头共用一个结点,故只要分配s个表头结点就好了
CreateHead(Head, s);
pa = A->tag.next;
pb = B->tag.next;
while(pa != A) //按行序处理
{
qa = pa->right;
qb = pb->right;
while(qa != pa && qb != pb)//从左到右处理该行非零结点,直到A,B 中有一个结束
{
if(qa->col < qb->col) //A的列号小于B的列号,将A的结点直接放入C中
{
Insert(Head, qa->row, qa->col, qa->tag.data);
k++;
qa = qa->right;
}
else if(qa->col > qb->col)//B的列小于A的列,将B的结点直接放入C中
{
Insert(Head, qb->row, qb->col, qb->tag.data);
k++;
qb = qb->right;
}
else //列号相等 ,当结果值不为0时放入C中
if(qa->tag.data + qb->tag.data != 0)
{
Insert(Head, qa->row, qa->col, qa->tag.data + qb->tag.data);
k++;
qa = qa->right;
qb = qb->right;
}//if(qa->tag.data + qb->tag.data != 0)
} //while(qa != pa && qb != pb)
if(qa = pa) //该行A结束,若B还有元素,则将B的元素直接放入C中
{
while(qb != pb)
{
Insert(Head, qb->row, qb->col, qb->tag.data);
k++;
qb = qb->right;
}
}
else //该行B结束,若A还有元素,则将A的元素直接放入C中
{
while(qa != pa)
{
Insert(Head, qa->row, qa->col, qa->tag.data);
k++;
qa = qa->right;
}
}
pa = pa->tag.next;
pb = pb->tag.next;
} //while(pa != A )
} // else
Head[0]->row = A[0].row; //总表头Head[0]的行域存储矩阵的总行数
Head[0]->col = A[0].col; //总表头Head[0]的列域存储矩阵的总列数
Head[1]->row = k; //非零元素的个数存储在Head[1]的行域
return Head[0]; //返回总表头结点
}
3。矩阵相乘
由于C中元素的行号和A中元素的行号一致,又都是以行序为主序排列的,因此可以对A(即对C)进行逐行处理。对A中第i行的每一个结点,我们在B中寻找相对应的结点,即A中第k列对应B中第k行。
因为C中元素的列号和B中元素的列号一致,所以每处理一行C结点,就要对B的每一列进行处理,根据矩阵乘法的特点,对每个C元素设置一个累计乘积值的变量,使其初值为0,每处理一行A,都要按列序扫描B一次,求得相应元素的乘积值并累积到相应的累计乘积值的变量中。
这种算法的时间复杂度为O(A.tu*B.mu)或O(A.nu*B.tu),速度非常快。其函数如下;
bool MultCrossList(const CrossList A, const CrossList B, CrossList *C)//十字链表存储矩阵矩阵相乘
{
int s, k=0;//k用来累积非零元素的个数
int value; //累积乘积值,作为C在对应的行列号处的结点的值
CrossList Head[MAXRC], pa, pb, qa, qb;
if(A->col != B->row)
return 0;
if(A->tag.next->row * B->tag.next->row != 0)//若C是非零矩阵
{
s = A->row > B->col ? A->row : B->col;//因为序号相同行头和列头共用一个结点,故只要分配s个表头结点就好了
CreateHead(Head, s);
pa = A->tag.next;
while(pa != A) //按行序处理
{
pb = B->tag.next;
while(pb != B) //按列序处理
{
qa = pa->right;
qb = pb->down;
value = 0;
while(qa != pa && qb != pb)//A从左到右处理该行非零结点,B从上到下处理该列非零结点,
{ //直到A,B 中有一个结束
if(qa->col < qb->row) //如果qa的列号小于qb的行号,qa右移一位
qa = qa->right;
else if(qa->col > qb->row) //如果qa的列号大于qb的行号,qb下移一位
qb = qb->down;
else //如果qa的列号等于qb的行号,二者相乘,乘积值累积在value中,
{
value += qa->tag.data * qb->tag.data;
qa = qa->right;
qb = qb->down;
}
} //while(qa != pa && qb != pb)
if(value != 0) //如果value不为0,把它放入C中
{
Insert(Head, pa->right->row, pb->down->col, value);
k++;
}
pb = pb->tag.next;
} // while(pb != B) //按列序处理
pa = pa->tag.next;
} //while(pa != A) //按行序处理
}// if(A[1].row * B[1].row != 0)//若C是非零矩阵
Head[0]->row = A[0].row; //总表头Head[0]的行域存储矩阵的总行数
Head[0]->col = B[0].col; //总表头Head[0]的列域存储矩阵的总列数
Head[1]->row = k; //非零元素的个数存储在Head[1]的行域
*C = Head[0]; //使新矩阵指向总表头
return 1;
} // MultCrossList
//-------------------------------------------------------------------------------
/*创建方形矩阵的行列式(人工输入数据),输出该矩阵的逆矩阵*/
/*2006-1-10 梁见斌*/
#include
#include
#define N 10
#define MAXRC 100 //假设矩阵的行(列)数最多为100
typedef struct matnode
{
int row, col; //结点的行域和列域
struct matnode *right, *down;//结点的向下域(down)和向右域(right)
union //结点的数据域,若为表头结点则无数值,而用指向其后继的指针代替
{
int data;
struct matnode *next;
} tag;
} CrossNode, *CrossList;
typedef struct node
{
int data; //存储元素的值
int x; //存储元素的横坐标
int y; //存储元素的纵坐标
} array;
int sum; //全局变量,存储行列式的值
void CreateArray(int H[][N], int m, int n); //构造一个二维数组存储矩阵
void PrintArray(const int H[][N], int m, int n) ; //输出二维数组存储矩阵
void trsmat(const int A[][N], int B[][N], int m, int n); //二维数组存储转置矩阵
void CreateHead(CrossList Head[], int len); //创建十字链表的表头结点
void Insert(CrossList Head[], int r, int c, int v); //插入新的结点
CrossList ArrayToCrossList(const int A[][N], int m, int n);//二维数组转换为十字链表
void CrossListToArray(CrossList T, int A[][N], int *m, int *n);//十字链表转换为二维数组
void PrintCrossList(CrossList T);//输出十字链表存储矩阵
void SolveHC(CrossList T, array S[], CrossList HeadRow, int top, int NiXu);//采用递归方式求行列式的值
bool Judge(const array S[], int line, int len); //判断行列式的元素的纵坐标是否重复
CrossList CreateYH(const CrossList T, int s, int x, int y);//求代数余子式矩阵
int main(void)
{
CrossList CrossList1=NULL, CrossList2=NULL; // 十字链表
array SL[N]; //栈,存储行列式的每一个乘积项的元素(因子)
int H[N][N], YH[N][N]; //存储原矩阵的行列式和代数余子式
int Y[N][N], YZ[N][N];//存储代数余子式的值,其转置矩阵即原矩阵的伴随矩阵
int D; // 存储原矩阵的行列式的值
int x, y, row, col;
int i, j, k;
int m, ym; //分别存储原矩阵的行列式和代数余子式的阶次
m = 3;
CreateArray(H, m, m); //构造一个矩阵行列式
PrintArray(H, m, m); //输出矩阵行列式
CrossList1 = ArrayToCrossList(H, m, m);//二维数组转换为十字链表
PrintCrossList(CrossList1);//输出十字链表存储矩阵
sum = 0; //设原矩阵的行列式的初值为0
SolveHC(CrossList1, SL, CrossList1->tag.next, 0, 0); //采用递归方式求矩阵行列式的值
D = sum;
printf("D = %d\n", D); //输出原矩阵的行列式的值
for(x=1; x<=m; x++) //构造各元素的代数余子式
for(y=1; y<=m; y++)
{
CrossList2 = CreateYH(CrossList1, m-1, x, y); //求代数余子式矩阵
// PrintCrossList(CrossList2); //输出十字链表存储矩阵
// CrossListToArray(CrossList2, YH, &ym, &ym); //十字链表转换为二维数组
// PrintArray(YH, ym, ym); //输出二维数组存储矩阵
sum = 0; //设代数余子式的初值为0
SolveHC(CrossList2, SL, CrossList2->tag.next, 0, 0);//采用递归方式求代数余子式的值
if((x+y)%2==0)
Y[x-1][y-1] = sum;
else
Y[x-1][y-1] = sum*(-1);
}
trsmat(Y, YZ, m, m);//求转置矩阵
//PrintArray(YZ, m, m); //输出伴随矩阵
puts("逆矩阵:");
printf("(1/%d)*\n", D);
PrintArray(YZ, m, m); //输出伴随矩阵
system("pause");
return 0;
}
CrossList CreateYH(const CrossList T, int s, int x, int y)//求代数余子式矩阵
{
CrossList Head[MAXRC], p, q;
int k, row, col;
CreateHead(Head, s);
k = 1;
p = T->tag.next;
while(p != T) //按行表顺序,把十字链表中的元素写入二维数组
{
q = p->right;
while(q != p)
{
if(x != q->row && y != q->col)
{
if(x > q->row) //若该非零元素的行号比x小,其代数余子式对应的元素行号不变
row = q->row;
else //若该非零元素的行号比x大,其代数余子式对应的元素行号减1
row = q->row-1;
if(y > q->col) //列号的处理方法与行号相同
col = q->col;
else
col = q->col-1;
Insert(Head, row, col, q->tag.data);
k++;
} //if
q = q->right;
} // while(q != p)
p = p->tag.next;
} //while(p != CrossList1)
Head[0]->row = s; //总表头Head[0]的行域存储矩阵的总行数
Head[0]->col = s; //总表头Head[0]的列域存储矩阵的总列数
Head[1]->row = k-1; //非零元素的个数存储在Head[1]的行域
return Head[0];
}
void SolveHC(CrossList T, array S[], CrossList HeadRow, int top, int NiXu)//采用递归方式求行列式的值
{
CrossList q;
array CS[N]; //栈,存储S[]的拷贝
int k, ctop;
int mul; //存储每一个乘积项的值
int CNiXu; //累积每一个乘积项的逆序数
q = HeadRow->right;
while(q != HeadRow)
{
ctop = top;
if(Judge(S, q->col, ctop))//如果当前元素的纵坐标不与栈中存储的元素重复,将其入栈
{
S[ctop].x = q->row;
S[ctop].y = q->col;
S[ctop++].data = q->tag.data;
CNiXu = NiXu; //把逆序数复制到CNiXu
for(k=0; k
if(S[ctop-1].y < S[k].y) //累积逆序数
CNiXu++;
}
for(k=0; k
if(HeadRow->right->row < T->row) //如果未分析到该乘积项的最后一个元素,递归继续分析
SolveHC(T, CS, HeadRow->tag.next, ctop, CNiXu);
else //否则计算该乘积项的值,并存储到栈中
{
if(ctop == T->row)
{
for(mul=1, k=0; k
if(CNiXu%2==0) //如果逆序数为偶数,该乘积项为正
sum += mul;
else //否则为负
sum -= mul;
}
} //else
} //if(Judge(S, q->col, ctop))
q = q->right;
} //while(q != HeadRow)
}
bool Judge(const array S[], int line, int len) //判断行列式的元素的纵坐标是否重复
{
int i;
for(i=0; i
return 0;
return 1;
}
void PrintCrossList(CrossList T)//输出十字链表存储矩阵
{
int k = 0;
CrossList p, q; //p指向行头,q指向非零元素结点
printf("\n");
p = T->tag.next;
if(p == T) //如果非零元素个数不为零,存储其总行数和总列数
{
puts("非零元素个数为零");
exit(1);
}
while(p != T) //按行表顺序,把十字链表中的元素写入二维数组
{
q = p->right;
while(q != p) //注意二维数组的下标从0开始,而十字链表的行,列号从1开始
{
printf("T%d (%d,%d,%d)\t", ++k, q->row, q->col, q->tag.data);
q = q->right;
}
p = p->tag.next;
}
printf("\n");
}
CrossList ArrayToCrossList(const int A[][N], int m, int n)//二维数组转换为十字链表
{
int s;
int i, j, k=0;
CrossList Head[MAXRC], p, q;
s = m>n ? m:n;//因为序号相同行头和列头共用一个结点,故只要分配s个表头结点就好了
CreateHead(Head, s);
for(i=0; i
{
k++;
Insert(Head, i+1, j+1, A[i][j]);
}//if(A[i][j] != 0)
Head[0]->row = m; //总表头Head[0]的行域存储矩阵的总行数
Head[0]->col = n; //总表头Head[0]的列域存储矩阵的总列数
Head[1]->row = k; //非零元素的个数存储在Head[1]的行域
return Head[0]; //返回总表头结点
}
void CrossListToArray(CrossList T, int A[][N], int *m, int *n)//十字链表转换为二维数组
{
int i, j, k;
CrossList p, q; //p指向行头,q指向非零元素结点
p = T->tag.next;
if(p != T) //如果非零元素个数不为零,存储其总行数和总列数
{
*m = T->row;
*n = T->col;
}
for(i=0; i<*m; i++) //先设所有元素均为0
for(j=0; j<*n; j++)
A[i][j] = 0;
while(p != T) //按行表顺序,把十字链表中的元素写入二维数组
{
q = p->right;
while(q != p) //注意二维数组的下标从0开始,而十字链表的行,列号从1开始
{
A[q->row-1][q->col-1] = q->tag.data;
q = q->right;
}
p = p->tag.next;
}
}
void CreateHead(CrossList Head[], int len) //创建十字链表的表头结点
{
CrossList p;
int i;
p = (CrossList)malloc(sizeof(CrossNode));
if(!p)
{
puts("Error");
exit(1);
}
p->row = p->col = 0; //表头结点的行域和列域设置为0
p->down = p->right = p;//先将表头结点的行域和列域指向自身,以构成循环链表
Head[0] = p; //生成总表头结点
for(i=1; i<=len; i++)//先初始化所有的行头(列头)
{
p = (CrossList)malloc(sizeof(CrossNode));
if(!p)
{
puts("Error");
exit(1);
}
p->row = p->col = 0; //表头结点的行域和列域设置为0
p->down = p->right = p;//先将表头结点的行域和列域指向自身,以构成循环链表
Head[i] = p;
Head[i-1]->tag.next = p;//把表头结点按顺序连接起来
} //for(i=1; i<=s; i++)
Head[len]->tag.next = Head[0];//最后一个表头结点的后继为总表头,即构成循环链表
}
void Insert(CrossList Head[], int r, int c, int v) //插入新的结点
{
CrossList p, q;
p = (CrossList)malloc(sizeof(CrossNode));
if(!p)
{
puts("Error");
exit(1);
}
p->row = r;
p->col = c;
p->tag.data = v;
q = Head[r]; //完成行插入
while(q->right != Head[r] && q->right->col < c)
q = q->right;
p->right = q->right;
q->right = p;
// printf("222r=%d,c=%d,v=%d",r,c,v); system("pause");
q = Head[c]; //完成列插入
while(q->down != Head[c] && q->down->row < r)
q = q->down;
p->down = q->down;
q->down = p;
}
void CreateArray(int H[][N], int m, int n) //构造一个二维数组存储矩阵
{
int i, j;
for(i=0; i
for(j=0; j
fflush(stdin);
}
}
void PrintArray(const int H[][N], int m, int n) //输出二维数组存储矩阵
{
int i, j;
for(i=0; i
for(j=0; j
printf("\n");
}
}
void trsmat(const int A[][N], int B[][N], int m, int n) //二维数组存储转置矩阵
{
int i, j;
for(i=0; i
}
评论