簡體   English   中英

密集和稀疏矩陣的高效(時間和空間復雜度)數據結構

[英]Efficient (time and space complexity) data structure for dense and sparse matrix

我必須讀取一個文件,其中存儲了一個帶有汽車的矩陣( 1 = BlueCar,2 = RedCar,0 = Empty )。

我需要編寫一個算法來以這種方式移動矩陣的汽車

  • 藍色向下移動;
  • 紅色向右移動 ;
  • 有一個轉彎 ,其中所有藍色的移動和轉向移動所有的紅色。

在讀取文件之前,我不知道矩陣大小,如果它是密集的或稀疏的,所以我必須實現兩個數據結構 (一個用於密集,一個用於稀疏)和兩個算法。

我需要盡可能達到最佳的時間和空間復雜性

由於未知的矩陣大小,我認為將數據存儲在堆上。

如果矩陣密集 ,我想使用類似的東西:

short int** M = new short int*[m];
short int*  M_data = new short int[m*n];

for(int i=0; i< m; ++i) 
{
    M[i] = M_data + i * n;
}

通過這種結構,我可以分配一個連續的存儲空間,並且使用M[i][j]訪問它也很簡單。

現在問題是為稀疏情況選擇的結構,我還必須考慮如何以最簡單的方式將汽車移動通過算法:例如,當我評估汽車時,我需要輕松找到,如果在下一個位置(向下或向右)有另一輛車或如果它是空的。

最初我想要定義繼承自一般Car對象的BlueCar和RedCar對象。 在這個對象中,我可以保存矩陣坐標,然后將它們放入:

std::vector<BluCar> sparseBlu;
std::vector<RedCar> sparseRed;

否則我可以這樣做:

vector< tuple< row, column, value >> sparseMatrix

但是仍然存在找到下一個位置的問題。

可能這不是最好的方法,所以如何以有效的方式實現稀疏案例呢? (也使用稀疏的獨特結構)

為什么不直接在文件上創建內存映射 (假設您的數據0,1,2存儲在文件中的連續字節(或位)中,並且這些字節的位置也表示汽車的坐標)

這樣您就不需要分配額外的內存並讀入所有數據,並且可以使用M[i][j]簡單有效地訪問數據。

遍歷行將是L1緩存友好的。

如果數據非常稀疏,您可以掃描一次數據,並在內存中保留一個空區域/塊的列表(只需要存儲初始值和大小),然后您可以在進一步運行中跳過(並在需要時調整) 。

使用內存映射,只有經常訪問的頁面才會保留在內存中。 這意味着一旦掃描了空區域,就只會為經常訪問的非空區域分配內存(所有這些都將由內核自動完成 - 無需自己跟蹤它)。

另一個好處是您直接訪問操作系統磁盤緩存。 因此,無需在內核空間和用戶空間之間保持復制和移動數據。

為了進一步優化空間和內存使用,汽車可以在文件中以2位存儲。

更新

我將不得不使用openMP和MPI移動汽車......內存映射是否也可以與並發線程一起工作?

您當然可以使用多線程,但不確定openMP是否是最佳解決方案,因為如果您同時處理數據的不同部分,您可能需要檢查一些重疊區域(即汽車可以從一個塊移動)到另一個)。

或者你可以讓線程在塊的中間部分工作,然后啟動其他線程來做邊界(紅色汽車是一個字節,藍色汽車是一整行)。

您還需要一個鎖定機制來調整稀疏區域的列表。 我認為最好的方法是啟動單獨的線程(當然,取決於數據的大小)。

在一個類似的任務中,我只是使用了壓縮行存儲

壓縮行和列(在下一節中)存儲格式是最通用的:它們絕對不對矩陣的稀疏性結構進行假設,並且它們不存儲任何不必要的元素。 另一方面,它們效率不高,需要對矩陣向量積或預處理器求解中的每個標量運算進行間接尋址步驟。

您需要更加具體地了解時間和空間復雜性要求。 CSR需要額外的索引步驟才能進行簡單的操作,但如果您只是進行簡單的矩陣運算,那么這是一個很小的開銷。

現在已經有了在線提供的C ++實現。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM