02 Arrays and Dynamic Arrays
Learn how arrays store ordered data, how indexing and shifting affect performance, and how dynamic, multidimensional, and array-based structures support different workloads.
The model and indexed access
An stores an ordered sequence of elements, and each element is identified by an integer index. In zero-based indexing, the first element is at index , the second is at index , and an of length ends at index .
For an , the value at is . The index identifies a position; it is not the same thing as the value stored there. Index is outside the valid range of this four-element .
In a conventional , elements of the same type occupy adjacent memory locations. If the first element begins at address , each element uses bytes, and the requested index is , then the address is:
Because this calculation does not depend on the 's length, reading or updating a known index typically takes time. Searching for an unknown value is different: the program may need to inspect up to elements, so a linear search can take time.
Takeaway: Arrays provide fast positional access because an index can be converted directly into a memory address.
and basic algorithms
visits elements one after another, commonly from index through index . It supports tasks such as printing values, computing a total, finding a maximum, validating data, or applying the same operation to every element.
A running-total can be described as follows:
Set a total to .
For each valid index , add to the total.
Return the total after the final element.
A of elements takes time. If the algorithm stores only a running total and a loop index, its additional space usage is .
Takeaway: Visiting every element is linear in the number of elements, even though accessing each individual element is constant time.
Insertion, deletion, and shifting
Insertion preserves the order of existing elements by making room for a new value. To insert at index , elements from the end toward index must move one position to the right. Moving from right to left prevents a value from being overwritten before it is copied.
For example, inserting at index changes to . The values and shift right. Inserting at the beginning or middle can require moving elements, so the worst-case time is . Appending at the end is when unused is available.
Deletion removes an element and closes the gap by shifting later elements one position to the left. Deleting index from produces . Deleting from the beginning or middle can take , while deleting the final element takes because no other element must move.
Takeaway: Arrays are efficient for access and end operations, but insertions and deletions near the beginning or middle are expensive because of shifting.
Fixed storage and dynamic growth
A has storage determined at creation time. It is appropriate when the required number of elements is known and stable, such as a fixed- lookup table. Its predictable storage can be useful when memory requirements must remain stable.
A uses an ordinary as backing storage while tracking two quantities. is the number of elements currently stored. is the number of elements that fit in the allocated storage. For example, a can have and : four slots contain logical elements and four slots remain available for future appends.
When a becomes full, it generally allocates a larger backing , copies the existing elements, replaces the old backing , and then inserts the new element. A common policy multiplies by a constant factor, such as , but the exact growth policy depends on the implementation.
Takeaway: Fixed-length arrays prioritize stable, predetermined storage; dynamic arrays trade some extra for the ability to grow.
Amortized cost of appending
An append to a normally takes time when is available. During a resize, copying the existing elements takes time, so one particular append can be expensive.
explains why the long-run cost remains small. If grows geometrically, resizes occur less frequently as the structure becomes larger. Across many appends, the total copying work is proportional to the total number of inserted elements, so the average cost per append is amortized .
The main trade-off is memory: unused improves future append performance but can occupy more storage than the current . Implementations may offer operations such as ensureCapacity to reserve space or trimToSize to reduce unused .
For the broader operation profile:
Indexed access and indexed update are typically .
takes .
Insertion or deletion at the beginning or middle takes .
Appending is amortized , but worst-case during a resize.
Takeaway: Amortized performance describes the sequence-level cost, not the cost of every individual append.
Multidimensional arrays and matrix layout
A uses more than one index. A two-dimensional can represent rows and columns, for example:
With zero-based indexing, : row , column . Traversing a rectangular matrix uses nested loops. If the matrix has rows and columns, visiting every element takes time.
A rectangular matrix can also be flattened into one one-dimensional . With columns, the row-major mapping is:
For row , column in a matrix with columns, the flat index is . Nested arrays can be easier to read and can support rows of different lengths, sometimes called a jagged . Flat storage makes the layout explicit and can improve memory locality.
Takeaway: Choose nested or flat multidimensional storage according to whether readability, variable row lengths, or a compact layout matters most.
Choosing an -based structure
Arrays are a strong choice when data is ordered, frequently accessed by position, or repeatedly traversed. Common uses include scores, measurements, sensor readings, character sequences, table rows, pixels, grids, matrices, lookup tables, and precomputed values. Arrays also provide a foundation for structures such as stacks, queues, and heaps.
Choose a when the is known in advance, the number of elements will not change, and predictable memory use is important. Choose a when the collection grows or shrinks and fast indexed access remains important. Dynamic arrays are particularly suitable when appending is more common than inserting or deleting near the beginning or middle.
Consider another data structure when frequent middle operations dominate the workload, because shifting can make those operations . The central design question is whether the workload benefits more from fast indexed access and compact or from efficient changes to the collection's interior.
Final takeaway: Use an -based structure when ordered storage, fast access by index, and efficient are central requirements; select fixed or dynamic storage based on whether the collection's is stable or changing.