要考研了,今天刚把这两块给弄懂了。也写了一些程序,希望能帮到一些刚入门数据结构的同学吧
三元组的快速转置
我们知道对于朴素转置方法,假如是M矩阵转置为N矩阵,那么我们会对于M中的每一行,遍历M中的每个元素,按行优先的顺序进行转置
for (int col = 0; col < M.nu; col++)
{
//p为M中元素的索引
//M.tu为M中非零元素的总数
//i为元素的行、j为元素的列
for (int p = 0; 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++;
}
}
}
但这样做时间复杂度为
O
(
n
u
⋅
t
u
)
O(nu·tu)
O(nu⋅tu),那么我们就要对其进行优化。分析上述代码发现,耗时的部分就是寻找每一个元素对应列的元素,如果我们能知道每一个元素其对应列的元素位置,我们就可以降低时间复杂度。所以我们引出了两个辅助数组
n
u
m
[
c
o
l
]
:
表
示
矩
阵
M
中
第
c
o
l
列
中
非
零
元
的
个
数
c
p
o
t
[
c
o
l
]
:
表
示
M
中
第
c
o
l
列
的
第
一
个
非
零
元
在
M
.
d
a
t
a
中
的
位
置
num[col]:表示矩阵M中第col列中非零元的个数 \\ cpot[col]:表示M中第col列的第一个非零元在M.data中的位置
num[col]:表示矩阵M中第col列中非零元的个数cpot[col]:表示M中第col列的第一个非零元在M.data中的位置
并且有以下公式
c
p
o
t
[
1
]
=
1
c
p
o
t
[
c
o
l
]
=
c
p
o
t
[
c
o
l
−
1
]
+
n
u
m
[
c
o
l
−
1
]
\begin{aligned} &cpot[1] = 1\\ &cpot[col] = cpot[col-1]+num[col-1] \end{aligned}
cpot[1]=1cpot[col]=cpot[col−1]+num[col−1]
这样我们可以先求出num数组和cpot数组,先找到M的第p个元素,然后根据第p个元素的列就知道它对应元素的位置了。
void transpose(TSMatrix &M, TSMatrix &T)
{
T.mu = M.nu;
T.nu = M.mu;
T.tu = M.tu;
int num[T.mu];
int cpot[T.mu];
cpot[0] = 0;
int p = 0;
memset(num, 0, sizeof(num));
for (p = 0; p < M.tu; p++)
{
num[M.data[p].j]++;
}
for (int col = 1; col < M.nu; col++)
{
cpot[col] = cpot[col - 1] + num[col - 1];
}
for (p = 0; p < M.tu; p++)
{
int acol = M.data[p].j;
int q = cpot[acol];
T.data[q].e = M.data[p].e;
T.data[q].i = M.data[p].j;
T.data[q].j = M.data[p].i;
cpot[acol]++;
}
}
行逻辑连接的顺序表
这个稍微有点复杂,因为稀疏矩阵有非常多的0,所以我们在计算矩阵乘法时很多含0的计算不需要计算。这样我们只需要计算M中非零元素与N中非零元素的对应乘积的累计和。
对于M中确定的p,找到N中所有满足
M
.
d
a
t
a
[
p
]
.
j
=
N
.
d
a
t
a
[
q
]
.
i
M.data[p].j = N.data[q].i
M.data[p].j=N.data[q].i式的q,然后将该对应乘积之和保存到一个ctemp累加器的数组中。ctemp保存第
M
.
d
a
t
a
[
p
]
.
i
M.data[p].i
M.data[p].i行对Q的每一列数值的部分和。
这里我们还用到了一个rpos数组,rpos[row]表示第row行中第一个非零元在M.data中的索引。
void get_rpos(RLSMatrix &M)
{
int num[MAXSIZE + 1];
if (M.tu)
{
for (int row = 0; row < M.mu; ++row)
num[row] = 0; ///清零
for (int t = 0; t < M.tu; ++t)
num[M.data[t].i]++; ///求M中每一列含非零个数
M.rpos[0] = 0;//默认第一行第一个非零元素的位置为0
/// 求第col列中第一个非零元在b.data中的序号
for (int row = 1; row < M.mu; ++row)
M.rpos[row] = M.rpos[row - 1] + num[row - 1];
}
}
void matrix_multiple(RLSMatrix &M, RLSMatrix &T, RLSMatrix &Q)
{
Q.mu = M.mu;
Q.nu = T.nu;
Q.tu = 0;
int ctemp[Q.nu]; //
int arow;
for (arow = 0; arow < M.mu; arow++)
{
//初始化累加器数组
memset(ctemp, 0, sizeof(ctemp));
//设置Q.rpos
Q.rpos[arow] = Q.tu;
int tp;
//tp表示M中第arow行的非零元的位置上限
if (arow != M.mu - 1)
tp = M.rpos[arow + 1];
else
tp = M.tu;
//根据M的每一行元素来计算乘积
for (int p = M.rpos[arow]; p < tp; p++)
{
//brow用来对应T中元素的行
int brow = M.data[p].j;
int t;
//t表示T中第brow行的非零元的位置上限
if (brow != T.mu - 1)
t = T.rpos[brow + 1];
else
t = T.tu;
//这里开始计算每一个对应的乘积
for (int q = T.rpos[brow]; q < t; q++)
{
int ccol = T.data[q].j;
ctemp[ccol] += M.data[p].e * T.data[q].e;
}
}
//保存第arow对Q每一行的贡献
for (int ccol = 0; ccol < Q.nu; ccol++)
{
if (ctemp[ccol] != 0)
{
Q.data[Q.tu].i = arow;
Q.data[Q.tu].j = ccol;
Q.data[Q.tu].e = ctemp[ccol];
Q.tu++;
}
}
}
}
下面给出完整代码
三元组快速转置
#include <bits/stdc++.h>
using namespace std;
#define MAXSIZE 12500
typedef struct
{
int i, j, e;
} Triple;
typedef struct
{
Triple data[MAXSIZE];
int mu, nu, tu;
} TSMatrix;
void transpose(TSMatrix &M, TSMatrix &T)
{
T.mu = M.nu;
T.nu = M.mu;
T.tu = M.tu;
int num[T.mu];
int cpot[T.mu];
cpot[0] = 0;
int p = 0;
memset(num, 0, sizeof(num));
for (p = 0; p < M.tu; p++)
{
num[M.data[p].j]++;
}
for (int col = 1; col < M.nu; col++)
{
cpot[col] = cpot[col - 1] + num[col - 1];
}
for (p = 0; p < M.tu; p++)
{
int acol = M.data[p].j;
int q = cpot[acol];
T.data[q].e = M.data[p].e;
T.data[q].i = M.data[p].j;
T.data[q].j = M.data[p].i;
cpot[acol]++;
}
}
int main()
{
int n, m;
cin >> n >> m;
TSMatrix M;
M.nu = m;
M.mu = n;
M.tu = 0;
for (int i = 0; i < n; i++)
{
for (int j = 0; j < m; j++)
{
int k;
cin >> k;
if (k != 0)
{
M.data[M.tu].e = k;
M.data[M.tu].i = i;
M.data[M.tu].j = j;
M.tu++;
}
}
}
TSMatrix T;
transpose(M, T);
int p = 0;
for (int i = 0; i < T.mu; i++)
{
for (int j = 0; j < T.nu; j++)
{
if (T.data[p].i == i && T.data[p].j == j)
{
cout << T.data[p].e << " ";
p++;
}
else
cout << 0 << " ";
}
cout << endl;
}
}
行逻辑连接的矩阵乘法
#include <bits/stdc++.h>
using namespace std;
#define MAXSIZE 12500
#define MAXRS 200
typedef struct
{
int i, j, e;
} Triple;
typedef struct
{
Triple data[MAXSIZE + 1];
int rpos[MAXRS + 1];
int mu, nu, tu;
} RLSMatrix;
void get_rpos(RLSMatrix &M)
{
int num[MAXSIZE + 1];
if (M.tu)
{
for (int row = 0; row < M.mu; ++row)
num[row] = 0;
for (int t = 0; t < M.tu; ++t)
num[M.data[t].i]++;
M.rpos[0] = 0;
for (int row = 1; row < M.mu; ++row)
M.rpos[row] = M.rpos[row - 1] + num[row - 1];
}
}
void matrix_multiple(RLSMatrix &M, RLSMatrix &T, RLSMatrix &Q)
{
Q.mu = M.mu;
Q.nu = T.nu;
Q.tu = 0;
int ctemp[Q.nu];
int arow;
for (arow = 0; arow < M.mu; arow++)
{
memset(ctemp, 0, sizeof(ctemp));
Q.rpos[arow] = Q.tu;
int tp;
if (arow != M.mu - 1)
tp = M.rpos[arow + 1];
else
tp = M.tu;
for (int p = M.rpos[arow]; p < tp; p++)
{
int brow = M.data[p].j;
int t;
if (brow != T.mu - 1)
t = T.rpos[brow + 1];
else
t = T.tu;
for (int q = T.rpos[brow]; q < t; q++)
{
int ccol = T.data[q].j;
ctemp[ccol] += M.data[p].e * T.data[q].e;
}
}
for (int ccol = 0; ccol < Q.nu; ccol++)
{
if (ctemp[ccol] != 0)
{
Q.data[Q.tu].i = arow;
Q.data[Q.tu].j = ccol;
Q.data[Q.tu].e = ctemp[ccol];
Q.tu++;
}
}
}
}
int main()
{
int n, m;
RLSMatrix M;
cin >> m >> n;
M.mu = m;
M.nu = n;
M.tu = 0;
for (int i = 0; i < M.mu; i++)
{
for (int j = 0; j < M.nu; j++)
{
int k = 0;
cin >> k;
if (k != 0)
{
M.data[M.tu].e = k;
M.data[M.tu].i = i;
M.data[M.tu].j = j;
M.tu++;
}
}
}
RLSMatrix T;
cin >> m >> n;
T.mu = m;
T.nu = n;
T.tu = 0;
for (int i = 0; i < T.mu; i++)
{
for (int j = 0; j < T.nu; j++)
{
int k = 0;
cin >> k;
if (k != 0)
{
T.data[T.tu].e = k;
T.data[T.tu].i = i;
T.data[T.tu].j = j;
T.tu++;
}
}
}
RLSMatrix Q;
get_rpos(M);
get_rpos(T);
matrix_multiple(M, T, Q);
int p = 0;
for (int i = 0; i < Q.mu; i++)
{
for (int j = 0; j < Q.nu; j++)
{
if (Q.data[p].i == i && Q.data[p].j == j)
{
cout << Q.data[p].e << " ";
p++;
}
else
cout << 0 << " ";
}
cout << endl;
}
}
1729

被折叠的 条评论
为什么被折叠?



