设计用时间复杂度为O(n)的算法,完成对稀疏矩阵的转置
稀疏矩阵参考博客数据结构--稀疏矩阵
1.普通的稀疏矩阵的转置(也叫稀疏矩阵压缩)如下:
Status TransposeMatrix(M,TSMatrix &T){
T.mu=M.nu;T.nu=M.nu;T.tu=M.tu;//输出矩阵`T`的行数、列数以及非零元素的个数初始化为与输入矩阵`M`相同。
if(T.tu){//检查非零元素的个数是否大于0
q=1;
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].v=M.data[p].v;++q}
}
return OK;
}
注解:
1. `Status TransposeMatrix(M,TSMatrix &T){`: 这是函数的定义,它接受两个参数,`M`和`T`,其中`M`是输入矩阵,`T`是输出矩阵,函数返回一个名为`Status`的结果。
2. `T.mu=M.nu; T.nu=M.nu; T.tu=M.tu;`: 这三行代码用于将输出矩阵`T`的行数、列数以及非零元素的个数初始化为与输入矩阵`M`相同。这意味着输出矩阵的维度与输入矩阵相同。
3. `if(T.tu){`: 这是一个条件语句,检查非零元素的个数是否大于0。如果非零元素的个数大于0,就会执行以下代码块,否则函数将直接返回。
4. `q=1;`: 这一行代码初始化一个变量`q`为1,它用于跟踪输出矩阵中的非零元素。
5. `for(col=1; col<=M.nu; ++col)`: 这是一个外循环,它用于遍历输入矩阵`M`的列。`col`表示当前列的索引,从1开始,一直遍历到`M.nu`(输入矩阵的列数)。
6. `for(p=1; p<=M.tu; ++p)`: 这是一个内循环,用于遍历输入矩阵`M`的非零元素。`p`表示当前非零元素的索引,从1开始,一直遍历到`M.tu`(非零元素的个数)。
7. `if(M.data[p].j==col){`: 这是一个条件语句,检查当前非零元素的列索引是否等于当前外循环迭代的列索引`col`。
8. `T.data[q].i=M.data[p].j;`: 如果条件满足,这行代码将输入矩阵中的非零元素的行索引赋值给输出矩阵中的相应元素的行索引。
9. `T.data[q].j=M.data[p].i;`: 同样,这行代码将输入矩阵中的非零元素的列索引赋值给输出矩阵中的相应元素的列索引,实现了矩阵的转置。
10. `T.data[q].v=M.data[p].v;`: 最后,这行代码将输入矩阵中的非零元素的值赋值给输出矩阵中的相应元素的值。
11. `++q`: 这行代码递增`q`,以便下一个非零元素存储到输出矩阵中的下一个位置。
12. `return OK;`: 最后,函数返回一个名为`OK`的结果,表示转置操作已成功完成。
总的来说,这个函数的目的是将输入矩阵`M`转置,并将结果存储在输出矩阵`T`中。转置操作会重新排列矩阵中的行和列,以交换它们的位置。在输出矩阵中,原来在输入矩阵中的行索引会变成列索引,原来的列索引会变成行索引,同时保留原来的非零元素的值。
时间复杂度分析:
- `tu` 表示输入矩阵中的非零元素个数。
- `nu` 表示输入矩阵的列数(或输出矩阵的行数)。
函数中的两个嵌套循环是关键:
1. 外循环是针对列数的循环,迭代次数最多为 `nu` 次。
2. 内循环是针对非零元素的循环,迭代次数最多为 `tu` 次。
因此,函数的总时间复杂度可以表示为O(tu * nu)。在稀疏矩阵中,通常 `tu` 远小于 `n` 和 `m`,所以这个算法的时间复杂度可以看作是线性的,与矩阵的总元素数目无关,而与非零元素的个数和列数有关。
2.时间复杂度为O(n)级的算法设计:
Status FstTransposeSMatrix(TSMatris M,TsMatrix &T){
T.mu=M.nu;T.nu=M.nu;T.tu=M.tu;
if(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;
for(col=2;col<=M.nu;++col)//计算每一列中第一个元素在T中的序号
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].v=M.data[p].v;
++cpot[col];
}
}
return OK;
}
注解:
-
Status FstTransposeSMatrix(TSMatris M, TsMatrix &T)
: 这是函数的定义,接受两个参数,M
是输入矩阵,T
是输出矩阵,函数返回一个名为Status
的结果。 -
T.mu = M.nu; T.nu = M.nu; T.tu = M.tu;
: 这三行代码用于将输出矩阵T
的行数、列数以及非零元素的个数初始化为与输入矩阵M
相同。这意味着输出矩阵的维度与输入矩阵相同。 -
if (tu)
: 这是一个条件语句,检查非零元素的个数是否大于0。如果非零元素的个数大于0,就会执行以下代码块,否则函数将直接返回。 -
for (col = 1; col <= M.nu; ++col) num[col] = 0;
: 这个循环初始化一个名为num
的数组,用于存储每一列的非零元素个数。数组的大小与输入矩阵的列数相同,每个元素初始值为0。 -
for (t = 1; t <= M.tu; ++t) ++num[M.data[t].j];
: 这个循环用于计算每一列的非零元素个数。它遍历输入矩阵M
中的非零元素,根据元素的列索引M.data[t].j
增加对应列的非零元素个数。 -
cpot = 1;
: 这一行代码初始化一个名为cpot
的数组,用于存储每一列中第一个元素在输出矩阵T
中的序号。初始值为1。 -
for (col = 2; col <= M.nu; ++col) cpot[col] = cpot[col - 1] - num[col - 1];
: 这个循环计算每一列中第一个元素在输出矩阵T
中的序号。这是快速转置算法的核心部分,它通过利用每列非零元素个数的信息来计算每列的起始位置。 -
for (p = 1; p <= M.tu; ++p)
: 这是一个循环,用于遍历输入矩阵M
中的非零元素。 -
col = M.data[p].j; q = cpot[col];
: 这两行代码获取当前非零元素的列索引col
以及该列在输出矩阵T
中的起始位置q
。 -
T.data[q].i = M.data[p].j; T.data[q].j = M.data[p].i; T.data[q].v = M.data[p].v;
: 这三行代码将当前非零元素的行、列索引以及值复制到输出矩阵T
的对应位置。 -
++cpot[col];
: 这行代码递增cpot[col]
,以便下一个相同列索引的非零元素可以放在输出矩阵中的下一个位置。 -
return OK;
: 最后,函数返回一个名为OK
的结果,表示转置操作已成功完成。
总的来说,这个函数使用了一种快速转置算法,通过计算每一列的非零元素个数和起始位置,来高效地实现矩阵的转置。这个算法的时间复杂度是O(tu + nu),与非零元素的个数和列数有关,而不是与矩阵的总元素数目有关。这使得它在处理稀疏矩阵时具有更高的效率。