首先,这个问题与特定语言无关 - 我使用Haxe来定位多个平台 - 所以伪代码就足够了。
这是我的问题:我在此表单中有sparse Matrix个描述:
edges =
[
1,1,2,1,3,1,4,1,
2,2,3,2,
3,3,4,3,5,3,
4,4,5,4,6,4,
5,5,6,5,7,5,25,5,27,5,28,5,29,5,30,5
];
这描述了边缘关联:
现在我需要在3D中渲染它并且这样做,我需要将数据“压缩”到没有“间隙”的索引缓冲区中。 用上面的例子说,我需要得到:
newEdges =
[
1,2, 1, 3, 1, 4,
2,3,
3,4, 3,5,
4,5, 4,6,
5,6, 5,7, 5,8, 5,9, 5,10, 5,11, 5,12
]
因此,必须删除连接自身(边缘1-1,2-2,3-3等)的边缘(简单)。
由于点顺序不重要(边1-2 =边2-1)我们也将删除重复的边(很容易)。
现在棘手的部分是删除“间隙”:因为7是最高的连续值,25是正确的,25必须变为8,27必须变为9,28必须变为10等等。
现在我正在使用BitmapData,其中我将所有值绘制为XY坐标。 然后我递归地将这个位图的非空垂直条纹(1像素宽矩形)彼此相邻地复制到临时位图中。 然后我对水平条纹做同样的事情,最后扫描我的位图并存储X&像素的Y值作为边的ID。
它有效!(至少它似乎:)) 但是开销太可怕了,根据输入矩阵,我可能无法生成位图(例如flash最大限制为4092像素,JS不支持copyPixels)。
所以问题是如何在没有位图和没有语言特定方法的情况下如何进行“间隙去除”?
希望这很明确, 谢谢你的关注。
尼古拉斯
答案 0 :(得分:1)
令E[m+1][m+1]
为与edges
对应的二维邻接矩阵,其中点索引的范围为[0..m]。
让f[n]
成为n
中访问过的edges
点的排序数组。
通过创建f[n]
数组,我们将在[0..m]范围内的非连续点索引和[0..n-1]中的连续点索引之间创建映射。
创建一个新的邻接矩阵G
,如下所示:
for i = 0..(n-1)
for j = 0..(n-1) // or, j = (i+1)..(n-1) for upper triangular portion
G[i][j] = E[f[i]][f[j]]
end
end
这只需要O(n ^ 2)而不是O(m ^ 2)时间。
编辑:删除了if
声明。如果E和G都被初始化为全0,则不需要。
答案 1 :(得分:1)
由于您的矩阵是稀疏的,我建议您使用排序列表数据结构从边缘列表构建稀疏结构。对于每行,您需要创建添加边的动态排序列表(升序)。例如,对于边(1,2)
,您将列2
插入到排序列表sorted_lists{1}
中。对于每行少量条目(几百个),最好使用排序列表中的线性搜索,然后将较大的元素移动到列表的末尾。对于每行的大量条目,您可以使用二分来查找正确的位置。我经常将此方法用于有限元方法中出现的稀疏矩阵。根据我的经验,最快的方法是和,它可以简单地并行化! (在线程之间拆分行范围)
以下是实现排序列表的示例MATLAB代码:
function list = sorted_list_insert(list, col)
% special case for empty list
if isempty(list)
list = col;
return;
end
% search for col position in the row
% can be done with bisection,
% but linear search is much faster for small number of entries per row
it = 1;
while it<length(list) && list(it)<col
it = it+1;
end
% duplicate entry - do not add
if list(it)==col
return;
end
% insert col in proper position, move other elements in the list
list = [list(1:it) col list(it+1:end)];
end
将一行中的所有条目添加到此排序列表的复杂性为O(number of entries per row ^ 2)
。
接下来要做的就是浏览边缘列表并添加列以更正行排序列表(sorted_lists{row}
)。在下面,edges
被假定为2D数组,其中edges(1,i)
是列,edges(2,i)
是行:
% find maximum row id
max_row = number of rows in the matrix
% initialize sorted list structures for all rows - max_row empty lists
sorted_lists = cell(max_row, 1);
% create sorted rows
nedges = total number of edges
for it=1:nedges
row = edges(2,it);
col = edges(1,it);
sorted_lists{row} = sorted_list_insert(sorted_lists{row}, col);
end
上述步骤的复杂性为O(number of rows * number of entries per row ^ 2)
。
最后一件事就是消除差距。通过排序列表,可以通过在排序列表中查找col
的位置来轻松完成。您还必须添加偏移量。从您的数据看起来您处理矩阵的上三角形部分(您说边缘中节点的顺序无关紧要)。因此,偏移量只是行数(在MATLAB中为-1,因为它具有从1开始的编号)
% the positions of col in every row (plus offset)
% are the new col id with removed gaps
for it=1:nedges
offset = edges(2,it)-1;
edges(1,it) = offset + find(sorted_lists{edges(2,it)}==edges(1,it));
end
这是edges
使用上述代码处理后的样子:
edges =
Columns 1 through 13
1 2 3 4 2 3 3 4 5 4 5 6 5
1 1 1 1 2 2 3 3 3 4 4 4 5
Columns 14 through 20
6 7 8 9 10 11 12
5 5 5 5 5 5 5
该过程适用于已排序和未排序的边。它只假设col >= row
。那你可以轻松实现。您还可以轻松添加对角线(i,i)
边缘的删除。