Multidimensional Array

Store values indexed by two or more dimensions using a linear memory layout.

Multidimensional Array

A multidimensional array stores values using two or more indices. Although it is written as a grid, matrix, or tensor, memory is still linear. The indexing formula maps each logical position to one physical offset.

You use it when data has natural row, column, plane, or tensor structure.

Problem

Given a two-dimensional array $A$ with $r$ rows and $c$ columns, support reading and writing an element at position $(i, j)$ where

$$ 0 \le i < r $$

and

$$ 0 \le j < c $$

Structure

In row-major layout, rows are stored one after another:

$$ A = \begin{bmatrix} a_{0,0} & a_{0,1} & a_{0,2}
a_{1,0} & a_{1,1} & a_{1,2} \end{bmatrix} $$

The linear offset for position $(i, j)$ is:

$$ offset = i \cdot c + j $$

Algorithm

Read an element from a row-major two-dimensional array:

get(A, r, c, i, j):
    if i < 0 or i >= r:
        error "row index out of bounds"
    if j < 0 or j >= c:
        error "column index out of bounds"

    offset = i * c + j
    return A[offset]

Write an element:

set(A, r, c, i, j, x):
    if i < 0 or i >= r:
        error "row index out of bounds"
    if j < 0 or j >= c:
        error "column index out of bounds"

    offset = i * c + j
    A[offset] = x

Example

Let

$$ A = \begin{bmatrix} 8 & 3 & 5
1 & 9 & 4 \end{bmatrix} $$

Here $r = 2$ and $c = 3$.

To read position $(1, 1)$:

$$ offset = 1 \cdot 3 + 1 = 4 $$

The flat storage is:

$$ [8, 3, 5, 1, 9, 4] $$

step action result
1 check row $0 \le 1 < 2$
2 check column $0 \le 1 < 3$
3 compute offset $4$
4 read flat index $4$ $9$

Return $9$.

Correctness

Row-major layout stores each row contiguously. Every full row before row $i$ contributes $c$ elements, so those rows contribute $i \cdot c$ positions. Column $j$ then adds $j$ more positions inside row $i$. Therefore, the offset $i \cdot c + j$ identifies exactly $A[i][j]$.

The bounds checks ensure that only valid row and column positions are accessed.

Complexity

operation time
get $O(1)$
set $O(1)$
scan all elements $O(rc)$

Space usage:

$$ O(rc) $$

When to Use

Multidimensional arrays are appropriate when:

  • data is naturally tabular or grid-shaped
  • dimensions are known or change rarely
  • fast indexed access is required
  • row-wise or block-wise traversal is common

They are less suitable when the data is very sparse. In that case, use a sparse matrix or coordinate representation.

Implementation

class Matrix:
    def __init__(self, rows, cols):
        self.rows = rows
        self.cols = cols
        self.a = [None] * (rows * cols)

    def index(self, i, j):
        if i < 0 or i >= self.rows:
            raise IndexError("row index out of bounds")
        if j < 0 or j >= self.cols:
            raise IndexError("column index out of bounds")
        return i * self.cols + j

    def get(self, i, j):
        return self.a[self.index(i, j)]

    def set(self, i, j, x):
        self.a[self.index(i, j)] = x
type Matrix[T any] struct {
    data []T
    rows int
    cols int
}

func NewMatrix[T any](rows, cols int) *Matrix[T] {
    return &Matrix[T]{
        data: make([]T, rows*cols),
        rows: rows,
        cols: cols,
    }
}

func (m *Matrix[T]) index(i, j int) (int, bool) {
    if i < 0 || i >= m.rows {
        return 0, false
    }
    if j < 0 || j >= m.cols {
        return 0, false
    }
    return i*m.cols + j, true
}

func (m *Matrix[T]) Get(i, j int) (T, bool) {
    var zero T
    k, ok := m.index(i, j)
    if !ok {
        return zero, false
    }
    return m.data[k], true
}

func (m *Matrix[T]) Set(i, j int, x T) bool {
    k, ok := m.index(i, j)
    if !ok {
        return false
    }
    m.data[k] = x
    return true
}