密集和稀疏矩阵

时间:2016-01-04 13:04:45

标签: c++ algorithm matrix vector

我必须阅读一个文件,其中存有一个带汽车的矩阵( 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

但是,在下一个位置找到什么的问题仍然存在。

可能这不是最好的方法,所以如何以有效的方式实现稀疏案例呢? (也使用稀疏的独特结构)

2 个答案:

答案 0 :(得分:2)

为什么不直接在文件上创建memory mapping? (假设您的数据0,1,2存储在文件中的连续字节(或位)中,并且这些字节的位置也表示汽车的坐标)

这样您就不需要分配额外的内存并读入所有数据,并且可以使用M[i][j]简单有效地访问数据。

遍历行将是L1缓存友好的。

如果数据非常稀疏,您可以扫描数据一次,并在内存中保留空区域/块的列表(只需要存储初始值和大小),然后您可以跳过(并在需要时调整)在进一步的运行。

使用内存映射时,只有经常访问的页面才会保留在内存中。这意味着一旦扫描了空区域,就只会为频繁访问的非空区域分配内存(所有这些都将由内核自动完成 - 无需自己跟踪它)。

另一个好处是您直接访问操作系统磁盘缓存。因此,无需在内核空间和用户空间之间继续复制和移动数据。

为了进一步优化空间和内存使用,汽车可以在文件中以2位存储。

<强>更新

  

我将不得不使用openMP和MPI移动汽车...将内存映射   还可以使用并发线程吗?

您当然可以使用多线程,但不确定openMP是否是最佳解决方案,因为如果您同时处理数据的不同部分,您可能需要检查一些重叠区域(即汽车可以移动)从一个街区到另一个街区。)

或者你可以让线程在块的中间部分工作,然后启动其他线程来做边界(红色汽车是一个字节,蓝色汽车是一整行)。

您还需要一个锁定机制来调整稀疏区域的列表。我认为最好的方法是启动单独的线程(当然,取决于数据的大小)。

答案 1 :(得分:1)

在一个类似的任务中,我只是使用了Compressed Row Storage

  

压缩行和列(在下一节中)存储格式   是最普遍的:他们完全没有假设   矩阵的稀疏结构,它们不存储任何不必要的东西   元素。另一方面,他们不是很有效率,需要一个   每个标量操作的间接寻址步骤   矩阵向量积或预处理器求解。

您需要更加具体地了解时间和空间复杂性要求。 CSR需要额外的索引步骤才能进行简单的操作,但如果您只是进行简单的矩阵操作,那么这只是一小部分开销。

There's already an existing C++ implementation available online as well.