經典演算法題15-稀疏矩陣及三元組
一. 引入
我們知道矩陣是一個非常強大的資料結構,在動態規劃以及各種圖論演算法上都有廣泛的應用。
當然矩陣有著不足的地方就是空間和時間複雜度都維持在N²上,比如1w個數字建立一個矩陣,在記憶體中會佔用1w*1w=1億的型別空間,這時就會遇到outofmemory。。。
那麼面臨的一個問題就是如何來壓縮矩陣,當然壓縮的方式有很多種,這裡就介紹一個順序表的壓縮方式:三元組。
二. 介紹三元組
有時候我們的矩陣中只有零星的一些非零元素,其餘的都是零元素,那麼我們稱之為稀疏矩陣,當然沒有絕對的說有多少個零元素才算稀疏。簡單說,稀疏矩陣就是非零元素個數遠遠小於元素個數的矩陣。相對於稀疏矩陣來說,一個不稀疏的矩陣也稱作稠密矩陣。
針對上面的這個無規律的存放非零元素,三元組提出了一種方法,就是僅僅記錄矩陣中的非零元素以及**它的行,列以及值**N(x,y,v)構成的一個三元組,標識一個稀疏矩陣的話,還要記錄該矩陣的階數,這樣我們就將一個二維的變成了一個一維,極大的壓縮的儲存空間。
這裡要注意的就是,三元組的構建採用“行”是從上到下,“列”也是從左到右的方式構建的順序表。
package xm.math.matrix;
/**
* 三元組處理稀疏矩陣
*
* @author xuming
*/
public class Node {
public int x;
public int y;
public double value;
public Node(int r, int c, double v) {
this.x = r;
this.y = c;
this.value = v;
}
public Node() {
this(0, 0, 0.0);
}
}
其實說到這裡也就差不多了,我們只要知道三元組是用來做矩陣壓縮的一個順序儲存方式即可,然後知道怎麼用三元組表來做一些常規的矩陣運算,好了,既然說已經做成線性儲存了,那就做個轉置(“行列置換”)試試。
三. 矩陣轉置
做行列置換很容易,也就是交換”非零元素”的(x,y)座標,要注意的就是,原先我們的三元組採用的是”行優先“,所以在做轉置的時候需要遵循”列優先“。
public Matrix convertMatrix(Matrix node) {
Matrix matrix = new Matrix();
matrix.rows = node.rows;
matrix.cols = node.cols;
matrix.count = node.count;
for (int col = 0; col < node.cols; col++) {
for (int triple = 0; triple < node.count; triple++) {
Node t = node.nodes.get(triple);
if (col == t.y) {
matrix.nodes.add(new Node(t.y, t.x, t.value));
}
}
}
return matrix;
}
結果
四.矩陣乘法
已知稀疏矩陣A(m1× n1)和B(m2× n2),求乘積C(m1× n2)。
稀疏矩陣A、B、C 及它們對應的三元組表A.data、B.data、C.data如下圖:
計算方法相比大家都知道,線性代數的簡單運算,口訣是:A的第一行跟B的第一列分別對應相乘,然後相加;往後依次A的第一行與B的第二列;等等。
/**
* 兩稀疏矩陣相乘。
* 前提:1.矩陣元素能夠相乘
* 2.一個矩陣的列等於另一個矩陣的行
* 原理:假設兩矩陣M與N相乘,前提M的列M.col要等於N的行N.row(反之亦可)
* 得到結果矩陣Q, Q.row=M.row, Q.col = N.col
* 而且Q[i][j] += M[i][k] * N[k][j] 0<i<M.row,0<j<N.col,0<k<M.col或N.row
*/
public Integer[][] multiMatrix(Integer[][] m, Integer[][] n){
Integer[][] q = new Integer[m.length][n[0].length];
for(int i=0;i<m.length;i++){
for(int j=0;j<n[0].length;j++){
int num = 0;
for(int k=0;k<n.length;k++){
num += (m[i][k]==null?0:m[i][k]) * (n[k][j]==null?0:n[k][j]);
}
q[i][j] = num;
}
}
//列印結果
for(int i=0;i<q.length;i++){
for(int j=0;j<q[0].length;j++){
System.out.print(q[i][j]+" ");
}
System.out.println();
}
return q;
}