1. 程式人生 > >稀疏矩陣快速轉置

稀疏矩陣快速轉置

題目來自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;
}