假设在 mn 的矩阵中,又t个元素不为零。δ = t/mn ,称δ为矩阵的稀疏因子,通常定义δ小于等于0.05时称为稀疏矩阵。
矩阵中每个元素用三个量存储,位置i,j 以及值e
typedef struct {
int i, j; //三元组的行列值
ElemType e;
}Triple;
typedef struct {
Triple data[MAXSIZE + 1]; //非零三元组表,data0未用
int mu, nu, tu; //三元组行数,列数,非零元素值
}TSMatrix ;
1.创建稀疏矩阵 M
Status CreateSMatrix(TSMatrix &M) {
cout << "输入矩阵行数,列数,非零元素个数:" << endl;
cin >> M.mu >> M.nu >> M.tu;
cout << "依次输入" << M.tu << "个元素的行数,列数,元素值:" << endl;
for (int i = 1; i <= M.tu; i++)
{
cin >> M.data[i].i >> M.data[i].j >> M.data[i].e;
}
cout << "矩阵构造完成" << endl;
return OK;
}
2.输出稀疏矩阵M
Status PrintSMatrix(TSMatrix M) {
//打印稀疏矩阵M
cout << "矩阵的函数行数,列数,非零元素个数为: " << M.mu << " " << M.nu << " " << M.tu << endl;
cout << "矩阵中非零元素为:"<<endl;
for (int i = 1; i <= M.tu; i++)
{
cout << "(" << M.data[i].i << "," << M.data[i].j<< ',' << M.data[i].e << ')' << endl;
}
return OK;
}
3.稀疏矩阵求和
算法思路:
依次取两个矩阵中的元素,首先比较行数mu,mu不一致则直接存入mu小的元素,并取下一个元素。若mu一致则比较列数nu,进行同样操作。
当两个元素的mu与nu都相等时,将元素值求和,若不为零,则存入元素,并取下两个元素比较。若和为零,直接取下两个元素比较,不进行存储。
进过while循环后,两个矩阵中会有一个矩阵元素有剩余,将其复制到新矩阵,便完成了矩阵加法。
Status AddSMatrix(TSMatrix M, TSMatrix N, TSMatrix &Q) {
if (M.mu != N.mu || M.nu != N.nu)return ERROR;
Q.mu = M.mu;
Q.nu = M.nu;
Q.tu = 0;
int mtu=1, ntu=1;
while (mtu<=M.tu && ntu<=N.tu)
{
if (M.data[mtu].i < N.data[ntu].i) {
Q.data[++Q.tu] = M.data[mtu++];
}
else if (M.data[mtu].i > N.data[ntu].i) {
Q.data[++Q.tu] = N.data[ntu++];
}
else {
if (M.data[mtu].j < N.data[ntu].j) {
Q.data[++Q.tu] = M.data[mtu++];
}
else if (M.data[mtu].j > N.data[ntu].j) {
Q.data[++Q.tu] = N.data[ntu++];
}
else
{
if (M.data[mtu].e + N.data[ntu].e == 0) { ++mtu; ++ntu; }
else
{
Q.data[++Q.tu] = M.data[mtu++];
Q.data[Q.tu].e += N.data[ntu++].e;
}
}
}
}
for ( ; mtu<= M.tu; mtu++)
{
Q.data[++Q.tu] = M.data[mtu];
}
for (; ntu <= M.tu; ntu++)
{
Q.data[++Q.tu] = N.data[ntu];
}
return OK;
}
4.稀疏矩阵减法
减法相对于 M+(-N),与加法思路一致。
Status SubMatrix(TSMatrix M,TSMatrix N, TSMatrix &Q) {
// M - N = M+(-N)
for (int i = 1; i <= N.tu; i++)
{
N.data[i].e *= -1;
}
AddSMatrix(M, N, Q);
return OK;
}
5.稀疏矩阵转置
一般转置方法:
基本思路:
依次找到M中每一列的所有元素,进行转置,这样得到的转置矩阵就是以行为主序进行排列
Status TransposeSMatrix(TSMatrix M, TSMatrix &T) {
//三元组组存储表示,求系数矩阵M的转置矩阵T
T.mu = M.mu; T.nu = M.mu; T.tu = M.tu;
if (T.tu) {
int q = 1;
for(int col = 1;col<=M.nu;++col)
for(int 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;
}
//算法分析:第一层循环是对矩阵M的列进行,第二层循环对所有元素进行,目的是使转置
//后的矩阵按照行为主序进行排列;算法时间复杂度为O(nu*tu),一般矩阵转置操作
//算法时间复杂度为O(nu*mu)
快速转置方法:
//新增两个向量,num,cpot
//num[col]表示矩阵M中第col列中非零元素个数
//cpot[col]指示M中第col列第一个非零元在b.data 中的位置。
//cpot[1]=1;
//cpot[col] = cpot[col-1] + num[col-1] 这一列第一个非零元位置等于上一列位置+元素个数
Status FastTransposeSMatrix(TSMatrix M, TSMatrix &T) {
T.mu = M.mu; T.nu = M.nu; T.tu = M.tu;
int* num=(int*)malloc(M.nu*sizeof(int));
int* cpot=(int*)malloc(M.nu * sizeof(int));
int col;
int q;
if (T.tu) {
for (int col = 1; col <= M.nu; ++col) num[col] = 0;
for (int t = 1; t <= M.tu; ++t) ++num[M.data[t].j];//求M中每一列含非零元个数
cpot[1] = 1;
//求第col列中第一个非零元在b.data 中的序号
for ( col = 2; col <= M.nu; ++col)cpot[col] = cpot[col - 1] + num[col - 1];
for (int 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];
}
}
return OK;
}
//代码分析:首先对矩阵M进行遍历,得到 num 向量
//通过cpot与num之间关系,得到 cpot 向量
//再次对M所有元素遍历,通过cpot向量找到该元素在 矩阵T中的位置
//++cpot[col];该列的第一个非零元素已经转换完毕,该列下一个元素位置应该在该元素之后
测试部分:
int main() {
TSMatrix M, N, Q, T;
CreateSMatrix(M);
PrintSMatrix(M);
CreateSMatrix(N);
AddSMatrix(M, N, Q);
cout << "加法运算完成:" << endl;
PrintSMatrix(Q);
TransposeSMatrix(Q, T);
cout << "矩阵转置完成:" << endl;
PrintSMatrix(T);
}