Arrays and Special Matrices

Arrays are the most fundamental storage structure in programming, and almost every other data structure is built on top of them. For special matrices and sparse matrices that contain many repeated elements or many zero elements, compressed storage saves a great deal of space, which is why it is a frequent topic in the postgraduate entrance exam. This chapter revolves around one core question, namely how to store a matrix in less space, and develops the address computation of multidimensional arrays, the compressed storage schemes for special matrices, and the two classic representations of sparse matrices. After reading this chapter you will be able to master the storage structure of one-dimensional and two-dimensional arrays, compute the address of any element, understand the address formulas for row-major and column-major storage together with the difference between them, apply the compressed storage formulas for symmetric, lower-triangular and tridiagonal matrices, master the triple representation and the orthogonal list representation of sparse matrices, and use compressed storage to solve problems of matrix access and matrix operations.

Questions This Chapter Answers

A 10×10 matrix needs 100 storage units, yet a symmetric matrix really needs only half of them, and a sparse matrix may need only a few dozen non-zero elements. How can a matrix be compressed to the smallest possible space while still allowing any element to be accessed? Answering that question requires the row-major and column-major address formulas of multidimensional arrays, the compression patterns of symmetric, triangular and tridiagonal matrices, and the triple and orthogonal list representations of sparse matrices.

Basic route: storage of multidimensional arrays → compressed storage of special matrices; master the address computation formulas first.

Advanced route: sparse matrices → typical applications → summary; understand when the triple representation and the orthogonal list are the right choice.

Storage of Multidimensional Arrays

Array

An array is an ordered collection of data elements of the same type, laid out linearly in memory by index. A multidimensional array is expanded into a single linear storage layout in memory in either row-major or column-major order.

One-Dimensional Arrays

Let the base address of the one-dimensional array A[0..n−1]A[0..n-1] be LOC(a0)LOC(a_0) and let every element occupy LL storage units. Then:

LOC(ai)=LOC(a0)+i×LLOC(a_i) = LOC(a_0) + i \times L

Two-Dimensional Arrays (Row-Major)

Let the two-dimensional array A[m][n]A[m][n] have mm rows and nn columns. In row-major storage the address of the element A[i][j]A[i][j] is:

LOC(A[i][j])=LOC(A[0][0])+(i×n+j)×LLOC(A[i][j]) = LOC(A[0][0]) + (i \times n + j) \times L

Derivation: in row-major order there are i×ni \times n elements before row ii, and there are jj further elements before column jj of row ii, so the offset is i×n+ji \times n + j.

Two-Dimensional Arrays (Column-Major)

In column-major storage the address of the element A[i][j]A[i][j] is:

LOC(A[i][j])=LOC(A[0][0])+(j×m+i)×LLOC(A[i][j]) = LOC(A[0][0]) + (j \times m + i) \times L

Derivation: there are j×mj \times m elements before column jj, and there are ii further elements before row ii of column jj, so the offset is j×m+ij \times m + i.

Exercises

Exercise 1

A two-dimensional array A[0..4][0..5] is stored in row-major order. If every element occupies 2 storage units and the address of A[0][0] is 1000, what is the address of A[3][4]? ( )

A. 1034 B. 1040 C. 1044 D. 1048

multidimensional arrayrow-major orderaddress computation

Approach:

This question tests the computation of an element address in a two-dimensional array stored in row-major order. First determine the number of rows and columns from the index ranges, then write down the row-major offset formula, and finally substitute the base address together with the element size to obtain the target address.

Steps:

  1. From A[0..4][0..5]A[0..4][0..5] the array has 5 rows and 6 columns, so the column count is n=6n = 6.
  2. In row-major storage the offset of A[i][j]A[i][j] is i×n+ji \times n + j; substituting i=3i = 3, j=4j = 4 and n=6n = 6 gives an offset of 3×6+4=223 \times 6 + 4 = 22.
  3. Every element occupies 2 storage units, so the address is LOC(A[0][0])+22×2=1000+44=1044LOC(A[0][0]) + 22 \times 2 = 1000 + 44 = 1044.

Answer:

C (1044).

Exercise 2

How are multidimensional arrays stored in memory, and how is the address of an element computed?

multidimensional arrayrow-major ordercolumn-major orderaddress computation

Approach:

This question tests the two linear storage layouts of a multidimensional array together with their address formulas. In the answer, first explain that a multidimensional array can only be flattened into a one-dimensional sequence in memory, then write the row-major and the column-major address formulas in turn, and explain the meaning of every symbol in the formulas.

Steps:

  1. Explain that a multidimensional array is stored linearly in memory in either row-major or column-major order.
  2. Write the row-major formula LOC(A[i][j])=LOC(A[0][0])+(i×n+j)×LLOC(A[i][j]) = LOC(A[0][0]) + (i \times n + j) \times L: there are i×ni \times n elements before row ii, and jj further elements before column jj of row ii.
  3. Write the column-major formula LOC(A[i][j])=LOC(A[0][0])+(j×m+i)×LLOC(A[i][j]) = LOC(A[0][0]) + (j \times m + i) \times L: there are j×mj \times m elements before column jj, and ii further elements before row ii of column jj.
  4. Explain that mm and nn are the number of rows and the number of columns, while LL is the length in storage units occupied by one element.

Answer:

A multidimensional array is expanded linearly in memory in either row-major or column-major order. In row-major order LOC(A[i][j])=LOC(A[0][0])+(i×n+j)×LLOC(A[i][j]) = LOC(A[0][0]) + (i \times n + j) \times L; in column-major order LOC(A[i][j])=LOC(A[0][0])+(j×m+i)×LLOC(A[i][j]) = LOC(A[0][0]) + (j \times m + i) \times L. Here mm and nn are the row count and the column count, and LL is the size of one element.

Compressed Storage of Special Matrices

A special matrix is a matrix that contains many identical elements or many zero elements. It can be stored in compressed form in a one-dimensional array, which saves space.

Symmetric Matrices

A symmetric matrix satisfies A[i][j]=A[j][i]A[i][j] = A[j][i], so only the lower triangle including the diagonal has to be stored, which takes n(n+1)2\frac{n(n+1)}{2} elements.

The index of the lower-triangular element A[i][j]A[i][j] (with i≥ji \ge j) in the one-dimensional array B[0..n(n+1)/2−1]B[0..n(n+1)/2-1] is:

k=i(i+1)2+jk = \frac{i(i+1)}{2} + j

Derivation: there are 0+1+2+⋯+i=i(i+1)20+1+2+\cdots+i = \frac{i(i+1)}{2} elements before row ii, and there are jj further elements before column jj of row ii.

Lower-Triangular Matrices

The storage scheme is the same as for a symmetric matrix, except that the upper triangle is represented by a single constant, so n(n+1)2+1\frac{n(n+1)}{2} + 1 storage units are needed.

Tridiagonal Matrices (Banded Matrices)

A tridiagonal matrix has non-zero elements only on the main diagonal and the two diagonals next to it, that is, 3n−23n-2 non-zero elements in total. Stored in row-major order, the index of A[i][j]A[i][j] (with ∣i−j∣≤1|i-j| \le 1) is:

k=2i+jk = 2i + j

Derivation: there are 3(i)−13(i) - 1 elements before row ii (each of the first ii rows contributes 3 elements, except that the first row contributes only 2), and within row ii the element in column jj is the j−(i−1)j-(i-1)-th one.

Exercises

Exercise 1

Suppose a 10×10 symmetric matrix A is stored in compressed form, with its lower triangle kept in a one-dimensional array B. What is the index of A[5][3] (indices counted from 0) in B? ( )

A. 13 B. 14 C. 15 D. 16

symmetric matrixcompressed storagelower-triangular storageindex computation

Approach:

This question tests the computation of an element index for a symmetric matrix that is compressed into its lower triangle. First confirm that the element in question lies in the lower-triangular region, then apply the index formula of lower-triangular compressed storage, and finally substitute ii and jj to locate it in the one-dimensional array B.

Steps:

  1. A symmetric matrix satisfies A[i][j]=A[j][i]A[i][j] = A[j][i], and compressed storage keeps only the lower triangle including the diagonal, so A[5][3]A[5][3] can be located directly inside the lower triangle.
  2. The index of the lower-triangular element A[i][j]A[i][j] (with i≥ji \ge j) is k=i(i+1)2+jk = \frac{i(i+1)}{2} + j, where i(i+1)2\frac{i(i+1)}{2} is the total number of elements in all rows before row ii, and jj is the number of elements before column jj within row ii.
  3. Substituting i=5i = 5 and j=3j = 3 gives k=5×62+3=15+3=15k = \frac{5\times6}{2} + 3 = 15 + 3 = 15, so the correct option is C.

Answer:

C (15).

Exercise 2

Briefly describe how the compressed storage formula for a symmetric matrix is derived.

symmetric matrixcompressed storagelower-triangular storageindex computation

Approach:

This question tests the derivation of the compressed storage formula for a symmetric matrix. In the answer, first use the symmetry to show that only the lower triangle has to be kept, then count the total number of elements in that triangle, and finally split the index into the elements of all preceding rows and the offset inside the current row to derive the formula.

Steps:

  1. By the symmetry A[i][j]=A[j][i]A[i][j] = A[j][i] only the lower triangle including the diagonal has to be stored, and this triangle contains 1+2+⋯+n=n(n+1)21+2+\cdots+n = \frac{n(n+1)}{2} elements.
  2. Split the index into two parts: the total number of elements in all rows before row ii is i(i+1)2\frac{i(i+1)}{2}, and the number of elements before column jj within row ii is jj.
  3. Adding the two parts gives the index formula k=i(i+1)2+jk = \frac{i(i+1)}{2} + j (valid for i≥ji \ge j).

Answer:

A symmetric matrix satisfies A[i][j]=A[j][i]A[i][j] = A[j][i], so only the lower triangle including the diagonal has to be stored. That triangle contains 1+2+⋯+n=n(n+1)21+2+\cdots+n = \frac{n(n+1)}{2} elements. The index of the element A[i][j]A[i][j] (with i≥ji \ge j) is k=i(i+1)2+jk = \frac{i(i+1)}{2} + j, where i(i+1)2\frac{i(i+1)}{2} is the total number of elements in all rows before row ii, and jj is the number of elements before column jj within row ii.

Sparse Matrices

A sparse matrix is a matrix in which the number of non-zero elements is far smaller than the number of zero elements, typically with fewer than 5 percent non-zero elements.

Triple Representation

Only the row number, the column number and the value of each non-zero element are stored, represented by a table of triples:

#define MAXSIZE 100
typedef struct {
    int row;   // row number
    int col;   // column number
    int value; // element value
} Triple;

typedef struct {
    Triple data[MAXSIZE];
    int rows, cols, nums;  // number of rows, columns and non-zero elements
} TSMatrix;

Advantages: it saves an enormous amount of storage space. Disadvantages: accessing an arbitrary element requires a traversal and a search, so the efficiency is low.

Orthogonal List Representation

The non-zero elements are stored as linked list nodes, and every non-zero element node is attached simultaneously to a row list and a column list, which makes matrix addition, multiplication and similar operations convenient.

typedef struct OLNode {
    int row, col, value;
    struct OLNode *right;  // points to the next non-zero element in the same row
    struct OLNode *down;   // points to the next non-zero element in the same column
} OLNode, *OLink;

Exercises

Exercise 1

How is a sparse matrix stored in compressed form, and which methods are available?

sparse matrixcompressed storagetriple representationorthogonal list

Approach:

This question tests the compressed storage methods for a sparse matrix. In the answer, first state the core idea that a sparse matrix stores only its non-zero elements and their positions, then list the three mainstream representations one by one together with the situations in which each of them applies, and finally summarize the common advantages and disadvantages of such compressed storage.

Steps:

  1. Non-zero elements occupy only a very small proportion of a sparse matrix, so the core of compressed storage is to keep only the non-zero elements and their positions, which reduces the space cost from O(n2)O(n^2) to a quantity proportional to the number of non-zero elements.
  2. Triple representation: an array of (row number, column number, value) records holds the non-zero elements; it saves space but slows down random access.
  3. Orthogonal list representation: every non-zero element node is attached to a row list and to a column list at the same time, which makes matrix operations convenient.
  4. Compressed row and column storage (CSR and CSC): three arrays store the values, the column numbers and the row offsets respectively, which suits large-scale sparse matrix computation.
  5. Overall comparison: the advantages are the saved storage space and the reduced number of useless operations; the disadvantages are the low efficiency of random access and the considerable complexity of the algorithms.

Answer:

A sparse matrix stores only its non-zero elements and their positions, and the three common methods are the triple representation, the orthogonal list representation and compressed row and column storage. The advantages are the saved storage space and the reduced number of useless operations; the disadvantages are the low efficiency of random access and the complexity of the algorithm implementation.

Typical Applications

The compressed storage of arrays and matrices is not pure theory: from image processing to the solution of large-scale systems of equations, the storage layout of the data often decides how fast a program can run. This section puts the sequential storage, the address computation and the compressed storage formulas described above back into real scenarios, and explains when an ordinary two-dimensional array is good enough and when it is worth paying the extra cost of index conversion for a special matrix.

Typical Applications of Arrays

  • Data storage: putting data of the same type into a contiguous block of memory and locating an element directly by base address plus index times element length is the basis of almost every program.
  • Searching and sorting: binary search relies on the orderedness of an array and on its random access capability; classic sorting algorithms such as insertion sort, merge sort and quicksort are all built on top of arrays.
  • Matrix operations: image processing, linear algebra and state space computation all perform matrix multiplication, and the contiguous storage of an array directly determines the memory access pattern and the cache hit rate.

Typical Applications of Sparse Matrices

  • Adjacency matrices of graphs: when a sparse graph is stored as an adjacency matrix, almost every position is 0; switching to the triple representation or the orthogonal list keeps only the non-zero elements and reduces the storage from O(n2)O(n^2) to a quantity proportional to the number of non-zero elements.
  • Scientific computing: the matrices produced by the numerical solution of partial differential equations or by the finite element method are often non-zero only near the main diagonal, so compressed storage is the standard practice.
  • Solving large-scale systems of equations: sparse matrix factorizations such as LU and Cholesky exploit the structure of the zero elements to skip useless computation, which is the key to solver performance.

Trade-offs in Choosing a Representation

ScenarioRecommended approachReason
Dense elements with frequent access by indexAn ordinary two-dimensional arrayThe address computation is simple and the access is O(1)O(1)
Special structure such as symmetric, triangular or tridiagonalStorage by the compressed formulaThe storage can be halved or reduced even further, at the cost of index conversion
Very few non-zero elementsTriples or an orthogonal listThe storage is proportional to the real information content, but random access becomes slower

Common Misconceptions

What compressed storage saves is space, and what it costs is that locating an element by index is no longer a single multiplication and addition but may become a table lookup or even a full traversal. Compressed storage therefore only pays off when the structure of the matrix is genuinely special and the access pattern is dominated by whole-block traversal; if the code frequently accesses a compressed matrix at random by index, the trade-off is usually a bad one.

Returning to the formulas of this chapter: the index conversion of a symmetric matrix is k=i(i+1)2+jk = \frac{i(i+1)}{2} + j (for i≥ji \ge j), the tridiagonal matrix uses k=2i+jk = 2i + j, and a triple of a sparse matrix is the combination of three numbers, namely (row, column, value). Memorize these three expressions and combine them with the selection table above, and you will be able to decide which storage scheme a concrete question calls for.

Summary

The conclusion of this chapter can be compressed into one sentence: the price of an array is paid in random access by index, and the price of a matrix is paid in storing it more compactly according to its structure. The terminology table aligns terms such as row-major order, symmetric matrix, triple and orthogonal list with their English names, while the key takeaways gather the address formulas and the compressed index formulas that have to be remembered, so that one quick pass before the exam connects all the formulas of this chapter.

Terminology Reference

TermAbbreviationExplanation
Row-major-Stored row by row
Column-major-Stored column by column
Symmetric matrix-Satisfies A[i][j] = A[j][i]
Compressed storage-Keeps only the meaningful elements
Sparse matrix-A matrix with very few non-zero elements
Triple-A non-zero element represented as (row, column, value)
Orthogonal list-Row and column doubly linked storage

Key Takeaways

  • Row-major address formula: LOC=LOC00+(i×n+j)×LLOC = LOC_{00} + (i \times n + j) \times L
  • Compressed index of a symmetric matrix: k=i(i+1)2+jk = \frac{i(i+1)}{2} + j (for i≥ji \ge j)
  • Compressed index of a tridiagonal matrix: k=2i+jk = 2i + j
  • A sparse matrix is stored with triples or an orthogonal list, which saves space but slows down random access

Found an issue with this content?

Tell us what could be improved.