稀疏矩阵快速转置

题目来自online judge http://acm.hzau.edu.cn/problem.php?cid=1151&pid=2

Problem C: 算法5-2:稀疏矩阵快速转置

Time Limit: 1 Sec  Memory Limit: 32 MB
Submit: 73  Solved: 24
[Submit][Status][Web Board]

Description

稀疏矩阵的存储不宜用二维数组存储每个元素,那样的话会浪费很多的存储空间。所以可以使用一个一维数组存储其中的非零元素。这个一维数组的元素类型是一个三元组,由非零元素在该稀疏矩阵中的位置(行号和列号对)以及该元组的值构成。

而矩阵转置就是将矩阵行和列上的元素对换。参考算法5.1中的具体做法,令mu和nu分别代表稀疏矩阵的行数和列数,不难发现其时间复杂度为O(mu×nu)。而当非零元的个数tu与mu×nu同数量级时,算法5.1的时间复杂度将上升至O(mu×nu2)。因此,需要采用快速的稀疏矩阵转置算法。

现在就请你实现一个快速的对稀疏矩阵进行转置的算法。以下是稀疏矩阵快速转置的算法描述:

Input

输入的第一行是两个整数r和c(r<200, c<200, r*c <= 12500),分别表示一个包含很多0的稀疏矩阵的行数和列数。接下来有r行,每行有c个整数,用空格隔开,表示这个稀疏矩阵的各个元素。

Output

输出为读入的稀疏矩阵的转置矩阵。输出共有c行,每行有r个整数,每个整数后输出一个空格。请注意行尾输出换行。

Sample Input

6 7
0 12 9 0 0 0 0
0 0 0 0 0 0 0
-3 0 0 0 0 14 0
0 0 24 0 0 0 0
0 18 0 0 0 0 0
15 0 0 -7 0 0 0

Sample Output

0 0 -3 0 0 15 
12 0 0 0 18 0 
9 0 0 24 0 0 
0 0 0 0 0 -7 
0 0 0 0 0 0 
0 0 14 0 0 0 
0 0 0 0 0 0 

HINT

提示:

这个算法仅比算法5.1多用了两个辅助向量。对于这个算法的时间复杂度,不难发现算法中有4个并列的单循环,循环次数分别为nu和tu,因而总的时间复杂度为O(nu+tu)。而当稀疏矩阵的非零元个数tu和mu×nu的数量级相同时,其时间复杂度为O(mu×nu),与经典算法的时间复杂度相同。

请注意理解为什么转置算法中,以列从小到大来进行转置。实际上只需一个循环就能够完成转置而不需将列从小到大来处理,转置后的矩阵虽然内容正确,但元素的顺序却发生了变化,以至于在后续的各种处理操作中会增加复杂度。而在本题中,如果不按照列从小到大的顺序处理将导致输出困难,大大增加输出的复杂度。

总结:

稀疏矩阵是矩阵应用中很重要的一部分,由于其元素稀疏的特殊性质,我们可以得到比传统矩阵算法更快速的特殊算法。这也将会在本章后面的题目中得到体现。

思路:事先确定M中的每一列的第一个元素在N中的位子,就能在对M进行转置的时候,直接将元素放在N的恰当位子;

方法(1.确定元素在N中的正确位子:再转置前,先求得M的每一列中非零元素的个数,然后求出每一列非零元素在N中的正确位子。

(2.设两个数组,Num和pos;num[col]用来存放三元组顺序表M中第col列的非零元素个数,pos[col]用来存放M中的第col列的第一个非零元素在N的正确位子;

一次遍历M表,可以求出每一列非零元素的个数,即num[col].pos[col]的值根据num[col]得到;

pos[0]=0; pos[col]=pos[col-1]+num[col-1]

具体实现:col=M.data[i].j;//赋初值对col

postion[col]的初值是M的第col列的第一个非零元素的位置,当M中的col列有一个元素加到N中时,则pos[col]+1;

使pos[col]始终存放下一个要转置的非零元素。

#include <bits/stdc++.h>

using namespace std;
#define MAXSIZE 200
typedef struct//矩阵三元组类型定义
{
    int i,j;
    int e;
}Triple;
typedef struct
{
    Triple data[MAXSIZE];
    int m,n,len;
}TriSeqMatrix;
int CreateMatrix(TriSeqMatrix *M)
{
    int m,n,e,l=0;
    scanf("%d %d",&m,&n);
    for(int i=0;i<m;i++)
    {
        for(int j=0;j<n;j++)
        {
            scanf("%d",&e);
            if(e!=0)
            {
                M->data[l].i=i;
                M->data[l].j=j;
                M->data[l].e=e;
                l++;
            }
        }
    }
    M->len=l;
    M->m=m;
    M->n=n;
}
void DestroyMatrix(TriSeqMatrix *M)
{//销毁系数矩阵操作,因为是静态分配,所以只需要吧矩阵的行数列数置为0;
    M->m=M->n=M->len=0;
}
void FastTransposeMatrix(TriSeqMatrix M,TriSeqMatrix *N)
{
    int i,k,t,col,*num,*pos;
    num=(int*)malloc((M.n+1)*sizeof(int));//数组num用于存放数组中每一列非零元素个数
    pos=(int*)malloc((M.n+1)*sizeof(int));
    N->n=M.m;
    N->m=M.n;
    N->len=M.len;
    if(N->len)
    {
        for(col=0;col<M.n;++col)
        {
            num[col]=0;
        }
        for(t=0;t<M.len;t++)
        {
            num[M.data[t].j]++;//计算M中每一列非零元素的个数
        }
        pos[0]=0;
        for(col=1;col<M.n;col++)
        {
            pos[col]=pos[col-1]+num[col-1];
        }
        for(i=0;i<M.len;i++)
        {
            col=M.data[i].j;
            k=pos[col];
            N->data[k].i=M.data[i].j;
            N->data[k].j=M.data[i].i;
            N->data[k].e=M.data[i].e;
            pos[col]++;//修改下一个非零元素应该存放的位子
        }
    }
    free(num);
    free(pos);

}
void PrintMatrix(TriSeqMatrix M)
{
    int k=0;
    for(int i=0;i<M.m;i++)
    {
        for(int j=0;j<M.n;j++)
        {
            if(i==M.data[k].i&&j==M.data[k].j)
            {
                printf("%d ",M.data[k].e); k++;
            }
            else printf("0 ");
        }
        printf("\n");
    }
}
int main()
{
    TriSeqMatrix M,N;
    CreateMatrix(&M);
    FastTransposeMatrix(M,&N);
    PrintMatrix(N);

    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_41929516/article/details/83626920
今日推荐