我已经给了很多想法,但实际上还没有想出一些东西。
假设我想要X列的元素集合可以按任何列和O(m * n)下的任何行进行排序,还能够插入或删除O(m + n)或更少的行...有可能吗?
我想到的是一个链接网格,其中节点被插入到一个向量中,所以我有它们的索引,并索引第一行和列,以消除在任何一个方向遍历列表的必要性。用我的方法我已经实现了上述复杂性,但我只是想知道是否有可能通过一个非常数因子进一步减少它。
可排序性示例:
1 100 25 34
2 20 15 16
3 165 1 27
按第3行排序:
25 1 34 100
15 2 16 20
1 3 27 165
按第1栏排序:
1 3 27 165
15 2 16 20
25 1 34 100
答案 0 :(得分:7)
我会创建两个索引数组,一个用于列,另一个用于行。所以对于你的数据
1 100 25 34
2 20 15 16
3 165 1 27
您创建了两个数组:
cols = [0, 1, 2, 3]
rows = [0, 1, 2]
然后,当您想要按第3行对矩阵进行排序时,保持原始矩阵不变,但只需相应地更改indices数组:
cols = [2, 0, 3, 1]
rows = [0, 1, 2]
现在的诀窍是通过一个间接访问您的矩阵。因此,您无法通过m[x][y]
访问它,而是通过m[cols[x]][rows[y]]
访问它。在执行rows / cols数组的重新排序时,还必须使用m[cols[x]][rows[y]]
。
这种排序方式为O(n*log(n))
,访问权限为O(1)
。
对于数据结构,我会使用一个包含指向另一个数组的链接的数组:
+-+
|0| -> [0 1 2 3 4]
|1| -> [0 1 2 3 4]
|2| -> [0 1 2 3 4]
+-+
要插入一行,只需将其插入最后一个位置,然后使用正确的位置相应地更新rows
索引数组。例如。当rows
为[0, 1, 2]
并且您想要将其插入前端时,行将变为[3, 0, 1, 2]
。这样,行的插入就是O(n)
。
要插入列,您还要将其添加为最后一个元素,并相应地更新cols。插入列为O(m)
,行为O(n)
。
删除也是O(n)
或O(m)
,在这里您只需用最后一个删除要删除的列/行,然后从索引数组中删除索引。
答案 1 :(得分:2)
只是添加到马丁努斯和迈克的答案:你需要的是,实质上是旋转,这是他们的建议,以及几乎任何涉及矩阵的数值算法中使用的一种众所周知的技术。例如,您可以快速搜索“使用部分旋转进行LU分解”和“使用完全旋转进行LU分解”。存储排列的附加向量称为“枢轴”。
答案 2 :(得分:1)
如果我遇到了这个问题,我会创建行和列重映射向量。例如。为了对行进行排序,我会将行顺序确定为正常,但不是复制行,而只是更改行重映射向量。
它看起来像这样:
// These need to be set up elsewhere.
size_t nRows, nCols;
std::vector<T> data;
// Remapping vectors. Initially a straight-through mapping.
std::vector<size_t> rowMapping(nRows), colMapping(nCols);
for(size_t y = 0; y < nRows; ++y)
rowMapping[y] = y;
for(size_t x = 0; x < nCols; ++x)
colMapping[x] = x;
// Then you read data(row, col) with
T value = data[rowMapping[row] * nCols + colMapping[col]];
P.S。一个小的优化是在rowMapping
而不是索引中存储指针。这样您就可以T value = rowMapping[row][colMapping[col]];
,但是,每次data
的维度发生变化时,您都必须重新计算指针,这可能容易出错。
答案 3 :(得分:0)
您可以使用哈希表并插入(i,j) - &gt;节点其中(i,j)是包含2个整数的2元组。您可以编写自己的自定义类来定义Equals方法和GetHash()方法......或者Python免费为您提供。
现在......究竟是什么意思 - 按行或列排序?请举例说明值!
答案 4 :(得分:-2)
也许是为它创建一个小型数据库?
数据库排序算法可能比重新发明轮子更好。 MySql会这样做。为了获得性能,可以在内存中创建表。然后,您可以将列索引为常规表,并让数据库引擎执行脏作业(排序等)。然后你就收获了结果。