我已经为c#over http://www.blackbeltcoder.com/Articles/algorithms/creating-a-sparse-matrix-in-net找到了一个非常好的稀疏矩阵实现。
但是当我在三维坐标系中工作时,我需要一个稀疏矩阵实现,我可以使用它来映射三维坐标系。
详细信息:我将大量原始形状数据存储在内存中,就像立方体一样。我确实有大量的(大约3000万)我周围有很多空(零)条目。鉴于我的每个条目花费1个字节的条目,我想实现稀疏矩阵,以便我可以相当节省内存空间。
注意:快速访问矩阵单元对我来说是一个相当重要的因素,所以我的交易速度超过内存消耗。
答案 0 :(得分:1)
我刚才提出的一个非常简单的解决方案是:
public class Sparse3DMatrix<T>
{
Dictionary<Tuple<int,int,int>, T> values = new Dictionary<Tuple<int, int, int>, T>();
public T this[int x, int y, int z]
{
get { return values[new Tuple<int, int, int>(x, y, z)]; }
set { values[new Tuple<int, int, int>(x, y, z)] = value; }
}
public bool ContainsKey(int x, int y, int z)
{
return values.ContainsKey(new Tuple<int, int, int>(x, y, z));
}
}
用法:
var test = new Sparse3DMatrix<float>();
test[1, 1, 1] = 1f;
Console.WriteLine(test[1, 1, 1]);
可以使用他的版本所具有的方法进行扩展,并检查x, y, z
值等。
我确信有人会对其表现有所说明。除非你真的需要高性能的东西,否则这将是一个不错的实现。这取决于Tuple
的哈希码实现以及您的具体用法。如果我们假设哈希值很好,我们将有O(1)
个查找时间。如果您知道自己将拥有大量元素,则可以使用new Dictionary<...>(initial capacity)
来避免在添加项目时不必要的大小调整。
与他的不同,这只有一个Dictionary
包含所有项目。他的版本有字典词典。他的好处是,如果你必须扫描整行,你可以只迭代二级字典(这不会帮助你想要扫描列),这比单独查找项目更快。但是使用单个字典意味着更少的内存使用量 - 特别是当你每行的项目很少时。
答案 1 :(得分:1)
Lasse Espeholt的解决方案很实用,但可以通过删除“归零”或无效的元素来改进。如果你不做这个矩阵或数组可能会失去稀疏性。这是一个替代解决方案,假设某个类型的元素尚未插入,它是该类型的默认值。例如,double
表示0.0,而string
表示null
。
public class Sparse3DArray<T>
{
private Dictionary<Tuple<int, int, int>, T> data = new Dictionary<Tuple<int, int, int>, T>();
public int Nnz { get { return data.Count; } }
public T this[int x, int y, int z]
{
get
{
var key = new Tuple<int, int, int>(x, y, z);
T value;
data.TryGetValue(key, out value);
return value;
}
set
{
var key = new Tuple<int, int, int>(x, y, z);
if (null == value)
data.Remove(key);
else if (value.Equals(default(T)))
data.Remove(key);
else
data[key] = value;
}
}
}
答案 2 :(得分:0)
您在3D坐标系中工作的事实不会改变您是否可以使用此数据结构。可以使用与2D矩阵相同的稀疏矩阵来包含3D空间的矩阵;它只是改变的条目。
对于包含大量零条目的大型matricies,您使用稀疏矩阵。这在物理学问题的离散表示中是典型的,这些问题来自有限差分和有限元方法。它们在对角线周围聚集了非零条目带;对角线带外的条目通常为零。稀疏矩阵不会存储这些;必须编写像LU和QR这样的分解来知道如何处理稀疏性。
这些基质可以描述2D或3D空间中的问题。
如果您认为自己需要其他数据结构,我认为您是错误的。
答案 3 :(得分:0)
答案 4 :(得分:0)
我将使用字典,但是可以使用单个long作为键并使用它来存储坐标(如果它们是短键),而不是使用Tuple<int, int, int>
作为键。这样可以减少内存占用,甚至可以提高性能。
private Dictionary<long, T> data = new Dictionary<long, T>();
private long GetKey(short x, short y, short z)
{
return (x * 10000 + y) * 10000 + z;
}