学习的过程中遇到的稀疏矩阵的快速转制的一个小结,贴在这里。
1.稀疏矩阵?http://baike.baidu.com/view/891721.htm 百度百科的链接。
2.稀疏矩阵的存储和数据结构的具体代码如下:
用三元组的形式存储稀疏矩阵:每个元素的描述需要三方面的信息,(1)所在列col;(2)所在行row;(3)值value
typedef struct{
int col;
int row;
int value;
}term;
注:对于每个定义的term数组,第一个数组元素的值分别代表整个矩阵的列数,行数和元素数,后面的例子会更加清楚这点。
3.稀疏矩阵的转置。
对于稀疏矩阵的三元组表示形式的转置,相比标准表示形式,会有一些特别。需要找到第n列所有元素,并把他们存储在转置矩阵的第n行……
第一个版本的稀疏矩阵转置算法如下:
void transport1(term a[], term b[])
{
int n, i, j, currentb;
n = a[0].value;
b[0].row = a[0].col;
b[0].value = n;
if( n > 0 ){
currentb = 1;
for( i = 0; i < a[0].col; i++)
for( j = 1; j <= n; j++){
if( a[j].col == i){
b[currentb].row = a[j].col;
b[currentb].col = a[j].row;
b[currentb].value = a[j].value;
currentb++;
}
}
}
}
但是这个版本的算法运行效率是比较低的。可以看出,两个for循环的次数分别为col和n,也就是列数和总共的元素数量。所以时间复杂度是O(列数*元素数量)。当元素数量是col*row的时候,也就是说这个矩阵不是稀疏的了,没有非零元素了(貌似说成没有非零元素不对)。这时候花费的时间就太多了。这里有一个更好的算法,但是需要多一些的存储空间。
void transport2(term a[], term b[])
{
int row_terms[MAX_COL], starting_pos[MAX_COL];
int i, j, col = a[0].col;
int num_terms = a[0].value;
b[0].col = a[0].row;
b[0].row = a[0].col;
b[0].value = num_terms;
if( num_terms > 0 ){
for( i = 0; i < col; i++ ){
row_terms[i] = 0;
}
for( i = 1; i <= num_terms; i++ ){
row_terms[a[i].col]++;
}
starting_pos[0] = 1;
for( i = 1; i < col; i++ ){
starting_pos[i] = starting_pos[i-1] + row_terms[i-1];
}
for( i = 1; i <= num_terms; i++){
j = starting_pos[a[i].col]++;/*b的下标的计算*/
b[j].col = a[i].row;
b[j].row = a[i].col;
b[j].value = a[i].value;
}
}
}
函数分析:第一个for循环将所有的row_terms置零,因为有的列本身就没有非零元素;第二个for循环计算有非零元素的列的非零元素的个数(为了在转置之后的term数组中,是按原矩阵的列递增来存储的);第三个for循环计算起始位置,是前一行非零元素个数的和加上前一个起始位置;第四个for循环转置的矩阵逐一生成。
四个for循环,这个函数的时间复杂度是O(col+元素数量),当元素数量是col*row时,时间变为O(col*row)。