You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
Zero/ZeroLevel/DataStructures/SparseMatrix.cs

258 lines
9.2 KiB

using System.Collections.Generic;
using System.Linq;
namespace ZeroLevel.DataStructures
{
/// <summary>
/// Represents a Sparse matrix.
/// </summary>
/// <typeparam name="T">The type of the stored value.</typeparam>
public class SparseMatrix<T>
{
/// <summary>
/// Dictionary containing the row index as a key and as a value another dictionary
/// containing the column index as a key and the stored value as a value.
/// </summary>
internal Dictionary<int, Dictionary<int, T>> rows;
/// <summary>
/// Dictionary containing the column index as a key and as a value another dictionary
/// containing the row index as a key and the stored value as a value.
/// </summary>
internal Dictionary<int, Dictionary<int, T>> cols;
/// <summary>
/// Gets the maximum reached height of the sparse matrix.
/// </summary>
public int Height { get; internal set; }
/// <summary>
/// Gets the maximum reached width of the sparse matrix.
/// </summary>
public int Width { get; internal set; }
/// <summary>
/// Gets the number of items in the <see cref="SparseMatrix{T}"/>.
/// </summary>
public int Count { get; internal set; }
/// <summary>
/// Gets or sets an item in the sparse matrix. If there is no item on the given position
/// on get the default value of T is returned and on set the item is added to the matrix.
/// </summary>
/// <param name="row">The zero-based row index of the item.</param>
/// <param name="col">The zero-based column index of the item.</param>
/// <returns>Returns the item in the sparse matrix. If there is no item on the given position the default value of T is returned instead.</returns>
public T this[int row, int col]
{
get
{
if (rows.ContainsKey(row))
{
if (rows[row].ContainsKey(col))
{
return rows[row][col];
}
}
//If there is no item on the given position return defaault value
return default(T)!;
}
set
{
if (row >= Height) Height = row + 1;
if (col >= Width) Width = col + 1;
//If no items on the current row we have to create a new dictionary
if (!rows.ContainsKey(row))
rows.Add(row, new Dictionary<int, T>());
//If no items on the current col we have to create a new dictionary
if (!cols.ContainsKey(col))
cols.Add(col, new Dictionary<int, T>());
rows[row][col] = value;
cols[col][row] = value;
Count++;
}
}
/// <summary>
/// Creates a new instance of the <see cref="SparseMatrix{T}"/> class.
/// </summary>
public SparseMatrix()
{
rows = new Dictionary<int, Dictionary<int, T>>();
cols = new Dictionary<int, Dictionary<int, T>>();
}
/// <summary>
/// Creates a new instance of the <see cref="SparseMatrix{T}"/> class from the given two dimensional array.
/// </summary>
/// <param name="array">The two dimensional array of items to add.</param>
/// <param name="zeroItem">The item considered a zero item. All items from the array equal to the zero item won't be added to the matrix.</param>
public SparseMatrix(T[,] array, T zeroItem)
{
rows = new Dictionary<int, Dictionary<int, T>>();
cols = new Dictionary<int, Dictionary<int, T>>();
for (int row = 0; row < array.GetLength(0); row++)
{
for (int col = 0; col < array.GetLength(1); col++)
{
if (!object.Equals(array[row, col], zeroItem))
this[row, col] = array[row, col];
}
}
}
/// <summary>
/// Determines if there is an item on the given position.
/// </summary>
/// <param name="row">The zero-based row index of the item.</param>
/// <param name="col">The zero-based column index of the item.</param>
/// <returns>Returns true if there is an item on the given position; otherwise false.</returns>
public bool IsCellEmpty(int row, int col)
{
if (rows.ContainsKey(row))
{
if (rows[row].ContainsKey(col))
{
return false;
}
}
return true;
}
/// <summary>
/// Gets the items in the given row sorted by the column index as an <see cref="IEnumerable{T}"/>
/// of <see cref="KeyValuePair{TKey, TValue}"/> with the key being the column index and the value being the item.
/// </summary>
/// <param name="row">The zero-based row index.</param>
/// <returns>Returns an <see cref="IEnumerable{T}"/> of <see cref="KeyValuePair{TKey, TValue}"/>
/// with the key being the column index and the value being the item.</returns>
public IEnumerable<KeyValuePair<int, T>> GetRowItems(int row)
{
if (rows.ContainsKey(row))
{
var sortedDict = new SortedDictionary<int, T>(rows[row]);
foreach (var item in sortedDict)
{
yield return item;
}
}
}
/// <summary>
/// Gets the items in the given column sorted by the row index as an <see cref="IEnumerable{T}"/>
/// of <see cref="KeyValuePair{TKey, TValue}"/> with the key being the row index and the value being the item.
/// </summary>
/// <param name="col">The zero-based column index.</param>
/// <returns>Returns an <see cref="IEnumerable{T}"/> of <see cref="KeyValuePair{TKey, TValue}"/>
/// with the key being the row index and the value being the item.</returns>
public IEnumerable<KeyValuePair<int, T>> GetColumnItems(int col)
{
if (cols.ContainsKey(col))
{
var sortedDict = new SortedDictionary<int, T>(cols[col]);
foreach (var item in sortedDict)
{
yield return item;
}
}
}
/// <summary>
/// Gets non empty rows indexes sorted in ascending order.
/// </summary>
/// <returns>Returns an <see cref="IEnumerable{T}"/> of integers being row indexes sorted in ascending order.</returns>
public IEnumerable<int> GetNonEmptyRows()
{
var sortedRows = new SortedSet<int>(rows.Keys);
foreach (var row in sortedRows)
{
yield return row;
}
}
/// <summary>
/// Gets non empty columns indexes sorted in ascending order.
/// </summary>
/// <returns>Returns an <see cref="IEnumerable{T}"/> of integers being column indexes sorted in ascending order.</returns>
public IEnumerable<int> GetNonEmptyColumns()
{
var sortedCols = new SortedSet<int>(cols.Keys);
foreach (var col in sortedCols)
{
yield return col;
}
}
/// <summary>
/// Removes the item on the given position.
/// </summary>
/// <param name="row">The zero-based row index.</param>
/// <param name="col">The zero-based column index.</param>
/// <returns>Returns true if item is removed successfully; otherwise false. Also returns false if the item is not found.</returns>
public bool Remove(int row, int col)
{
if (rows.ContainsKey(row))
{
if (rows[row].ContainsKey(col))
{
bool removedSuccessfully = true;
if (!rows[row].Remove(col) || !cols[col].Remove(row)) removedSuccessfully = false;
if (rows[row].Count == 0)
{
rows.Remove(row);
}
if (cols[col].Count == 0)
{
cols.Remove(col);
}
if (removedSuccessfully)
Count--;
return removedSuccessfully;
}
}
return false;
}
/// <summary>
/// Removes all elements from the sparse matrix.
/// </summary>
public void Clear()
{
rows.Clear();
cols.Clear();
Count = 0;
Height = 0;
Width = 0;
}
/// <summary>
/// Updates the height and the width of the matrix. If no items were removed from the matrix the dimensions will be correct.
/// </summary>
public void UpdateDimensions()
{
if (rows.Count == 0)
{
Height = 0;
Width = 0;
return;
}
Height = rows.Keys.Max() + 1;
Width = cols.Keys.Max() + 1;
}
}
}

Powered by TurnKey Linux.