我必须读取一个文件,其中存储有汽车矩阵( 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]。
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缓存友好的。
如果数据非常稀疏,您可以扫描一次数据并在内存中保留一个空区域/块的列表(仅需要存储startpos和大小),然后可以跳过(并在需要的地方进行调整)以进一步运行。
使用内存映射,仅将经常访问的页面保留在内存中。这意味着一旦您扫描了空白区域,内存将仅分配给经常访问的非空白区域(所有这些操作将由内核自动完成- 无需自己进行跟踪)。
另一个好处是您可以直接访问OS磁盘缓存。因此,无需在内核空间和用户空间之间继续复制和移动数据。
为了进一步优化空间和内存使用率,可以将汽车以2位存储在文件中。
更新 :
我将不得不使用openMP和MPI来移动汽车…内存映射是否也可以用于并发线程?
您当然可以使用多线程,但是不确定openMP是否是此处的最佳解决方案,因为如果您同时处理数据的不同部分,则可能需要检查一些重叠区域(即,一辆汽车可能从一个街区驶出)到另一个)。
或者,您可以让线程在块的中间部分工作,然后启动其他线程来做边界(红色小车为一个字节,蓝色小车为整行)。
您还需要一种锁定机制来调整稀疏区域的列表。我认为最好的方法是启动单独的线程(当然取决于数据的大小)。