稀疏矩陣快速轉置
題目來自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;
}