您可以使用基于单元格的 [row,col] 的索引。由于数据在对角线上,将行索引和相关列索引与数据一起存储的典型方法不是最佳的。这是一些您可以用来执行此操作的代码:
public class SparseMatrix<T>
{
public int Width { get; private set; }
public int Height { get; private set; }
public long Size { get; private set; }
private Dictionary<long, T> _cells = new Dictionary<long, T>();
public SparseMatrix(int w, int h)
{
this.Width = w;
this.Height = h;
this.Size = w * h;
}
public bool IsCellEmpty(int row, int col)
{
long index = row * Width + col;
return _cells.ContainsKey(index);
}
public T this[int row, int col]
{
get
{
long index = row * Width + col;
T result;
_cells.TryGetValue(index, out result);
return result;
}
set
{
long index = row * Width + col;
_cells[index] = value;
}
}
}
static void Main()
{
var sm = new SparseMatrix<int>(512, 512);
sm[42, 42] = 42;
int val1 = sm[13, 13];
int val2 = sm[42, 42];
Console.WriteLine("VAL1 = " + val1); // prints out 0
Console.WriteLine("VAL2 = " + val2); // prints out 42
Console.ReadLine();
}
请注意,当 T 是结构时,您可能必须调用 IsCellEmpty,因为获取单元格的内容不会为空,并且将具有该类型的默认值。您还可以扩展代码以根据Size
属性和_cells.Count
.
编辑:
好吧,如果您对速度感兴趣,您可以权衡空间与速度。与其只有一本字典,不如拥有三本!它使您的空间增加了三倍,但它使以您想要的任何方式进行枚举变得非常容易。这是一些新的代码,表明:
public class SparseMatrix<T>
{
public int Width { get; private set; }
public int Height { get; private set; }
public long MaxSize { get; private set; }
public long Count { get { return _cells.Count; } }
private Dictionary<long, T> _cells = new Dictionary<long, T>();
private Dictionary<int, Dictionary<int, T>> _rows =
new Dictionary<int, Dictionary<int, T>>();
private Dictionary<int, Dictionary<int, T>> _columns =
new Dictionary<int, Dictionary<int, T>>();
public SparseMatrix(int w, int h)
{
this.Width = w;
this.Height = h;
this.MaxSize = w * h;
}
public bool IsCellEmpty(int row, int col)
{
long index = row * Width + col;
return _cells.ContainsKey(index);
}
public T this[int row, int col]
{
get
{
long index = row * Width + col;
T result;
_cells.TryGetValue(index, out result);
return result;
}
set
{
long index = row * Width + col;
_cells[index] = value;
UpdateValue(col, row, _columns, value);
UpdateValue(row, col, _rows, value);
}
}
private void UpdateValue(int index1, int index2,
Dictionary<int, Dictionary<int, T>> parent, T value)
{
Dictionary<int, T> dict;
if (!parent.TryGetValue(index1, out dict))
{
parent[index2] = dict = new Dictionary<int, T>();
}
dict[index2] = value;
}
}
如果要遍历所有条目,请使用_cells
. 如果您想要给定列的所有行,请使用_columns
. 如果您想要给定行中的所有列,请使用_rows
.
如果您想按排序顺序进行迭代,您可以开始将 LINQ 添加到组合中和/或使用带有封装条目的内部类的排序列表(它必须存储行或列并实现IComparable<T>
排序才能工作) .