I have a sparse matrix that is not symmetric I.E. the sparsity is somewhat random, and I can\'t count on all the values being a set distance away from the diagonal.
Derek, you mentioned in one of the comments that you want to use a single malloc. That means that you know how many nonempty elements you have. Given this, tt is possible to store the sparse matrix in an array which holds, per element, the value of the matrix element and the "location delta" to the next element. Something like:
struct melem {
int value; // value of data
int offset; // offset to next element
}
struct melem matrix[num_nonempty_elements];
...
// Note: this is pseudocode!
matrix[row*COLS + col].value = a[row][col];
matrix[row*COLS + col].offset = (row*COLS + col)_[i] - (row*COLS + col)_[i-1];
EDIT: Thinking about it, this is pretty similar to the linked list approach, but requires 1 allocation. OTOH, it may require more calculation to access the required cell.
I would implement this as a ragged array, with A[n][0] always returning the element on the diagonal. A[n][1] will return the item just to the right of the diagonal, A[n][2] will return the item to the left of the diagonal, and so. Then, you just need a function that maps matrix index [i,j] to ragged array index[r][s].
This has the advantage of sparsity, and if your values stay close to the diagonal the arrays are not very long.
Alternatively, you could have this definition:
struct Row
{
int InitialOffset;
int NumElements;
int[] Values;
}
Then you would have a Row[]. Retrieving a value based on matrix index would look like this:
//matrix is merely an array of rows...
int GetValue(*matrix this, int i, int j)
{
Row CurrentRow = (*this)[i];
if (CurrentRow.InitialOffset > j)
return 0;
else if (CurrentRow.InitialOffset + CurrentRow.NumElements < j)
return 0;
return CurrentRow.Values[j - CurrentRow.InitialOffset]
}
My C syntax is a little hazy, but you should get the idea.
Based on your demonstration, I would recommend this:
struct Matrix
{
int[,] Data
int[] StartOffset;
int[] NumberElements;
}
Used as follows...
int GetValue(*Matrix this, int i, int j)
{
if (this.StartOffset[i] > j)
return 0;
else if (this.StartOffset[i] + this.NumberElements[i] < j)
return 0;
return this.Data[i, j-this.StartOffset[i]];
}
Your initialization procedure would look something like this
//Data is a struct that holds row index, col index, and value
Matrix* InitMatrix (*Data values, int numVals)
{
//loop through values to find longest row and number of rows
//create new matrix, malloc matrix for longrow * numRows
//malloc numrows elements for StartOffset and NumItems
//foreach row, find min() and max()-min() of col indexs and
//store in StartOffset and NumItems
}
You need to do some processing, but data compression isn't cheap.
An alternate approach is to use a linked structure (very efficient if the matrix very sparse, not so good as it gets more filled). I hinted at the implementation in a earlier answer.
I you are going to go with the continuous run implementation, I'm not sure that you really want/need to use equal lengths rows. Why not use a ragged array?