Data Structure:Matrix Compression Storage
1 Introduction
In data structures, a compressed storage structure for some specific matrices is provided.
The special matrix we mentioned can be generally divided into the following two types:
- A matrix containing a large number of identical data elements, such as a symmetric matrix;
- Matrix containing a large number of 0, such as sparse matrix, upper or lower triangular matrix;
For the two types of matrices above, the compressed storage idea of the data structure is: only one of the same data elements (including element 0) in the matrix is stored.
2 Storage of symmetric matrix and upper/lower triangular matrix
With the idea of data structure compression storage, we can use one dimensional array to store symmetric matrix. Since the data on both sides of the diagonal in the matrix are equal, we only need to store one side of the diagonal (including the diagonal) in the array.
For example, to store the elements in the lower triangle of symmetric matrix, we need to substitute the row number i and column number j of each element into the following formula (i,j≥1):
If we need to store the elements in the upper triangle, the formula should be:
An example:
The matrix above will be stored as:
3 Storage of sparse matrix
The method of compressing and storing the sparse matrix is to store the non-zero elements in the matrix only. Unlike the previous storage method, the storage of the non-zero elements of the sparse matrix needs to store the row and column labels in the matrix in which the element is located. Also we need to store the size of matrix.
Here are three ways to store a sparse matrix:
- Triple sequence table
- Logical-linked sequence table
- Cross link list
3.1 Triple sequence table
First we will construct the basic structure:
// Structure of triad
typedef struct{
int i,j; // Index number
int data; // value
}triple;
// Structure of matrix
typedef struct{
triple data[number]; // Store all the non-zero triple
int n,m,num; // n*m: size of the matrix, num: number of non-zero elements
}TSMatrix;
Then try the output:
void display(TSMatrix M){
for(int i=1;i<=M.n;i++){
for(int j=1;j<=M.m;j++){
int value =0;
for(int k=0;k<M.num;k++){
if(i == M.data[k].i && j == M.data[k].j){
printf("%d ",M.data[k].data);
value =1;
break;
}
}
if(value == 0)
printf("0 ");
}
printf("\n");
}
}
int main() {
TSMatrix M;
// Initialize the matrix
M.m=3;
M.n=3;
M.num=3;
// All the non-zero elements here
M.data[0].i=1;
M.data[0].j=1;
M.data[0].data=1;
M.data[1].i=2;
M.data[1].j=3;
M.data[1].data=5;
M.data[2].i=3;
M.data[2].j=1;
M.data[2].data=3;
display(M);
return 0;
}
Output:
3.2 Logical-linked sequence table
This storage method is similar with triple sequence table but it improve the efficiency of extracting data.
This method also record the first non-zero element in each row.
Storage:
Code implementation:
/* Sparse matrix storage(Logical-linked sequence table) */
#include <stdio.h>
#define MAXSIZE 12500
#define MAXRC 100
#define ElemType int
typedef struct
{
int i,j;
ElemType e;
}Triple;
typedef struct
{
Triple data[MAXSIZE+1];
int rpos[MAXRC+1]; // First position of non-zero elements in every row
int mu,nu,tu; // row,column,number of elements
}RLSMatrix;
void display(RLSMatrix M){
for(int i=1;i<=M.mu;i++){
for(int j=1;j<=M.nu;j++){
int value=0;
if(i+1 <=M.mu){
for(int k=M.rpos[i];k<M.rpos[i+1];k++){
if(i == M.data[k].i && j == M.data[k].j){
printf("%d ",M.data[k].e);
value=1;
break;
}
}
if(value==0){
printf("0 ");
}
}else{
for(int k=M.rpos[i];k<=M.tu;k++){
if(i == M.data[k].i && j == M.data[k].j){
printf("%d ",M.data[k].e);
value=1;
break;
}
}
if(value==0){
printf("0 ");
}
}
}
printf("\n");
}
}
int main(int argc, char* argv[])
{
RLSMatrix M;
M.tu = 4;
M.mu = 3;
M.nu = 4;
M.rpos[1] = 1;
M.rpos[2] = 3;
M.rpos[3] = 4;
M.data[1].e = 3;
M.data[1].i = 1;
M.data[1].j = 2;
M.data[2].e = 5;
M.data[2].i = 1;
M.data[2].j = 4;
M.data[3].e = 1;
M.data[3].i = 2;
M.data[3].j = 3;
M.data[4].e = 2;
M.data[4].i = 3;
M.data[4].j = 1;
display(M);
return 0;
}
Output:
3.3 Cross link list
If we want to add or delete non-zero elements, the two storage methods above will not be suitable, so we introduce a new idea: Cross link list. It combines link list and array:
Code implementation:
/* Sparse matrix storage(Cross link list) */
#include<stdio.h>
#include<stdlib.h>
typedef struct OLNode
{
int i,j,e; // i:row;j:column;e:value
struct OLNode *right,*down; // right pointer and down pointer
}OLNode,*OLink;
typedef struct
{
OLink *rhead,*chead; // Head pointer for row and column
int mu,nu,tu; // Size of matrix and the number of non-zero elements
}CrossList;
CrossList CreateMatrix_OL(CrossList M)
{
int m,n,t;
int i,j,e;
OLNode *p,*q;
printf("Row column and non-zero elements:");
scanf("%d %d %d",&m,&n,&t);
M.mu=m;
M.nu=n;
M.tu=t;
if(!(M.rhead=(OLink*)malloc((m+1)*sizeof(OLink)))||!(M.chead=(OLink*)malloc((n+1)*sizeof(OLink))))
{
printf("Failed to initalize the matrix");
exit(0);
}
for(i=1;i<=m;i++)
{
M.rhead[i]=NULL;
}
for(j=1;j<=n;j++)
{
M.chead[j]=NULL;
}
for(scanf("%d %d %d",&i,&j,&e);0!=i;scanf("%d %d %d",&i,&j,&e)) {
if(!(p=(OLNode*)malloc(sizeof(OLNode))))
{
printf("Failed to initalize the triple");
exit(0);
}
p->i=i;
p->j=j;
p->e=e;
// Link to row
if(NULL==M.rhead[i]||M.rhead[i]->j>j)
{
p->right=M.rhead[i];
M.rhead[i]=p;
}
else
{
for(q=M.rhead[i];(q->right)&&q->right->j<j;q=q->right);
p->right=q->right;
q->right=p;
}
// link to column
if(NULL==M.chead[j]||M.chead[j]->i>i)
{
p->down=M.chead[j];
M.chead[j]=p;
}
else
{
for (q=M.chead[j];(q->down)&& q->down->i<i;q=q->down);
p->down=q->down;
q->down=p;
}
}
return M;
}
void display(CrossList M){
for (int i=1;i<=M.nu;i++)
{
if (NULL!=M.chead[i])
{
OLink p=M.chead[i];
while (NULL!=p)
{
printf("Col:%d\tRolL%d\tVal:%d\n",p->i,p->j,p->e);
p=p->down;
}
}
}
}
int main()
{
CrossList M,N;
M=CreateMatrix_OL(M);
printf("M:\n");
display(M);
return 0;
}
Output: