What Is a Dynamic Array?
A dynamic array is an array-based data structure that can automatically grow or shrink as elements are added or removed. Unlike a fixed-size array, a dynamic array does not require the programmer to know the final number of elements when the structure is created.
Dynamic arrays are commonly implemented using a regular array as their underlying storage. When the existing storage becomes full, a larger array is allocated and the existing elements are copied into it.
Why Are Dynamic Arrays Needed?
A traditional fixed-size array requires its capacity to be determined when the array is allocated. This can be inconvenient when the number of elements changes during program execution.
| Fixed Array | Dynamic Array |
|---|---|
| Capacity is generally fixed. | Capacity can grow when required. |
| Resizing requires creating another structure. | Resizing can be handled internally. |
| Useful when the required size is known. | Useful when the size changes during execution. |
Size vs Capacity
Two concepts are important when understanding dynamic arrays: size and capacity.
- Size is the number of elements currently stored.
- Capacity is the amount of storage currently available.
Values:
[10, 20, 30, 40, _, _, _, _]
Size = 4
Capacity = 8
The unused positions represent available capacity. New elements can be added without immediately allocating another array until that capacity has been exhausted.
How Dynamic Array Resizing Works
Suppose a dynamic array has a capacity of four and all four positions are occupied.
Before resizing:
[10, 20, 30, 40]
Size = 4
Capacity = 4
When another element is inserted, the implementation can allocate a larger array, copy the existing elements, and continue the insertion.
After resizing:
[10, 20, 30, 40, 50, _, _, _]
Size = 5
Capacity = 8
A common strategy is to increase capacity by a growth factor, such as doubling it. The exact strategy depends on the language and implementation.
Steps Performed During Resizing
- Detect that the current storage is full.
- Allocate a larger underlying array.
- Copy the existing elements into the new array.
- Replace the old storage with the new storage.
- Insert the new element.
The copying step is what makes an individual resize operation expensive. However, resizing does not happen on every insertion when capacity grows geometrically.
Implementing a Dynamic Array in JavaScript
JavaScript's built-in Array already provides dynamic array
behavior. However, implementing a simplified version helps demonstrate
how resizing works internally.
class DynamicArray {
constructor(capacity = 2) {
this.data = new Array(capacity);
this.size = 0;
}
push(value) {
if (this.size === this.data.length) {
this.resize();
}
this.data[this.size] = value;
this.size++;
}
resize() {
const newCapacity = this.data.length * 2;
const newData = new Array(newCapacity);
for (let i = 0; i < this.size; i++) {
newData[i] = this.data[i];
}
this.data = newData;
}
get(index) {
if (index < 0 || index >= this.size) {
throw new Error("Index out of bounds");
}
return this.data[index];
}
}
const numbers = new DynamicArray();
numbers.push(10);
numbers.push(20);
numbers.push(30);
numbers.push(40);
console.log(numbers.get(2));
// 30
console.log(numbers.data.length);
// 8
Appending Elements to a Dynamic Array
Adding an element to the end of a dynamic array is normally efficient. When unused capacity is available, the new value can be placed directly at the next available position.
const values = [10, 20, 30];
values.push(40);
console.log(values);
// [10, 20, 30, 40]
If the underlying storage needs to grow, the insertion may temporarily require copying existing elements into a larger storage area.
Dynamic Array Insertion at an Index
Inserting an element into the middle of a dynamic array still requires shifting the elements after the insertion position.
const values = [10, 20, 40, 50];
values.splice(2, 0, 30);
console.log(values);
// [10, 20, 30, 40, 50]
Dynamic resizing solves the capacity problem, but it does not eliminate the cost of shifting elements during insertion.
Removing Elements from a Dynamic Array
Elements can also be removed from a dynamic array. Removing an element from the end generally avoids shifting other elements, while removing from the beginning or middle can require elements to be moved.
const values = [10, 20, 30, 40];
values.pop();
console.log(values);
// [10, 20, 30]
Some dynamic-array implementations also reduce capacity when the array becomes sufficiently empty. Shrinking is normally done carefully to avoid repeatedly resizing the storage when elements are added and removed around the same size.
Amortized Time Complexity
One of the most important concepts associated with dynamic arrays is amortized complexity.
A resize operation can take O(n)
As a result, appending n elements has an overall
O(n) cost, giving an O(1) amortized
cost per append.
Operation
Typical Complexity
Access by index
O(1)
Append
O(1) amortized
Append during resize
O(n)
Insert at beginning
O(n)
Insert in middle
O(n)
Delete from end
O(1) typical
Delete from beginning
O(n)
Why Geometric Growth Is Useful
Consider a dynamic array that increases its capacity by one every time it
becomes full. Adding many elements would cause repeated allocations and
repeated copying of existing values.
Increasing capacity by a growth factor, such as doubling it, provides more
unused space after a resize. This reduces how frequently expensive resize
operations occur.
Capacity growth:
2 → 4 → 8 → 16 → 32 → 64
The exact growth policy is implementation-dependent, but geometric growth
is a common strategy for achieving efficient amortized insertion.
Dynamic Arrays in JavaScript
JavaScript arrays are designed to be flexible and can grow or shrink as
elements are added or removed. Developers normally use methods such as
push(), pop(), splice(), and
shift() instead of implementing resizing manually.
const users = [];
users.push("Asha");
users.push("Rahul");
users.push("Priya");
console.log(users);
// ["Asha", "Rahul", "Priya"]
users.push("Arun");
console.log(users.length);
// 4
Although JavaScript hides the underlying storage management, the dynamic
array concept remains important for understanding how array-backed
collections behave.
Dynamic Arrays vs Linked Lists
Both dynamic arrays and linked lists can represent collections whose size
changes during execution, but they use different storage strategies.
Feature
Dynamic Array
Linked List
Index access
O(1)
O(n)
Append
O(1) amortized
O(1) with tail reference
Middle insertion
O(n)
O(1) after reaching the position
Memory layout
Array-backed storage
Node-based storage
Memory overhead
Generally lower per element
Extra node references
Advantages of Dynamic Arrays
- Can grow as the number of elements increases.
- Provides constant-time indexed access.
- Supports efficient amortized appending.
- Uses a simple array-backed representation.
- Works well for collections where elements are frequently accessed by index.
- Usually provides good cache locality compared with pointer-heavy structures.
Limitations of Dynamic Arrays
- Resizing can temporarily require copying many elements.
- Insertion near the beginning or middle requires shifting elements.
- Unused capacity can consume additional memory.
- Frequent resizing can be expensive if the growth strategy is poorly designed.
- Removing elements does not always immediately reduce allocated capacity.
Common Dynamic Array Mistakes
- Confusing the number of stored elements with the allocated capacity.
- Resizing the array on every insertion.
- Forgetting to copy all existing elements during a resize.
- Using an inefficient growth strategy.
- Assuming every append operation has a strict worst-case O(1) cost.
- Ignoring the cost of shifting elements during middle insertion.
- Creating shared nested references when building arrays of arrays.
When Should You Use a Dynamic Array?
Dynamic arrays are a strong choice when the collection size changes over
time and the application frequently needs indexed access. They are
particularly useful for lists of users, products, messages, results,
records, and other sequential data.
If the application frequently inserts or removes elements from the middle
of a collection, another data structure may provide better characteristics
depending on the access pattern.
Key Takeaways
- A dynamic array can grow as more elements are added.
- Size represents the number of stored elements, while capacity represents available storage.
- When capacity is exhausted, a larger underlying array can be allocated.
- Existing elements must be copied during a resize.
- Appending is typically O(1) amortized when geometric growth is used.
- Insertion and deletion near the beginning or middle can require shifting elements.
- JavaScript arrays provide dynamic array behavior without requiring manual resizing.
- Dynamic arrays provide fast indexed access and are useful for many sequential collections.