Some algorithms solve a problem by building a fresh result somewhere else in memory. In-place algorithms take a more frugal approach: they transform the existing data structure directly, using little or no extra storage. This idea sounds simple, but it influences performance, scalability, and even how safely your code behaves in real applications.
TLDR: An in-place algorithm modifies input data directly instead of creating a separate copy. For example, reversing an array by swapping the first and last elements uses only a few variables, while creating a second reversed array doubles memory use. In a user case such as sorting 10 million integers, an in-place approach can save roughly 40 MB of extra memory if each integer takes 4 bytes. That difference can be critical on mobile devices, embedded systems, or high-traffic servers.
What Does “In-Place” Really Mean?
An algorithm is usually called in-place if it uses only a small, fixed amount of additional memory beyond the input itself. That extra memory is often described as O(1) space, meaning it does not grow as the input grows.
For example, if an algorithm processes an array of 10 items or 10 million items and still only needs three temporary variables, it is considered in-place. However, if it creates another array of the same size, its extra memory usage is O(n), and it is not in-place.
It is important to note that in-place does not always mean “no extra memory at all.” A few loop counters, temporary variables, or pointers are allowed. The key idea is that the additional memory remains small and predictable.
A Simple Example: Reversing an Array
Suppose you want to reverse an array. A non-in-place solution might create a new array and copy items into it in reverse order. That is easy to understand, but it costs extra memory.
function reverseWithCopy(arr) {
const result = [];
for (let i = arr.length - 1; i >= 0; i--) {
result.push(arr[i]);
}
return result;
}
This works, but it creates a second array. If the original array has one million elements, the new array also has one million elements. An in-place version swaps elements from both ends and moves toward the center:
function reverseInPlace(arr) {
let left = 0;
let right = arr.length - 1;
while (left < right) {
const temp = arr[left];
arr[left] = arr[right];
arr[right] = temp;
left++;
right--;
}
return arr;
}
This algorithm uses only three extra variables: left, right, and temp. Whether the array has 5 elements or 5 million, the extra memory stays essentially the same.
Why In-Place Algorithms Matter
Memory can be just as important as speed. In modern programming, it is easy to assume memory is abundant, but that assumption breaks down quickly in certain environments. Consider these situations:
- Mobile apps: Excess memory usage can slow the app or cause crashes on older devices.
- Embedded systems: Sensors, routers, and small devices may have only a few kilobytes of usable memory.
- Large data processing: Copying massive datasets can waste time and increase infrastructure costs.
- Real-time systems: Predictable memory usage helps avoid delays caused by allocation and garbage collection.
In-place algorithms are often attractive because they reduce memory allocation. Fewer allocations can also mean fewer cache misses and less pressure on garbage collectors in languages such as JavaScript, Java, Python, and C#.
Example: Removing Duplicates from a Sorted Array
Here is a common interview and production-style problem: remove duplicates from a sorted array in-place. Since the array is sorted, duplicate values appear next to each other. We can use one pointer to scan the array and another to place the next unique value.
function removeDuplicates(nums) {
if (nums.length === 0) return 0;
let writeIndex = 1;
for (let readIndex = 1; readIndex < nums.length; readIndex++) {
if (nums[readIndex] !== nums[readIndex - 1]) {
nums[writeIndex] = nums[readIndex];
writeIndex++;
}
}
return writeIndex;
}
const data = [1, 1, 2, 2, 3, 4, 4];
const length = removeDuplicates(data);
console.log(length); // 4
console.log(data.slice(0, length)); // [1, 2, 3, 4]
The function does not create a new array to store unique values. Instead, it overwrites the early part of the original array. The returned length tells us how many positions now contain valid unique elements.
This is a classic in-place pattern: read from one location, write to another location, and avoid unnecessary copying.
In-Place Sorting Algorithms
Sorting is one of the most common areas where in-place techniques appear. Some sorting algorithms require extra arrays, while others mostly rearrange the input directly.
Examples of commonly in-place sorting algorithms include:
- Selection sort: Finds the smallest remaining item and swaps it into position.
- Insertion sort: Builds a sorted section by shifting elements inside the original array.
- Heap sort: Converts the array into a heap and repeatedly extracts the maximum.
- Quick sort: Often implemented in-place by partitioning the array around a pivot.
Here is a simple in-place selection sort in JavaScript:
function selectionSort(arr) {
for (let i = 0; i < arr.length - 1; i++) {
let minIndex = i;
for (let j = i + 1; j < arr.length; j++) {
if (arr[j] < arr[minIndex]) {
minIndex = j;
}
}
if (minIndex !== i) {
const temp = arr[i];
arr[i] = arr[minIndex];
arr[minIndex] = temp;
}
}
return arr;
}
Selection sort is not fast for large lists because it has O(n²) time complexity, but it demonstrates the in-place idea clearly. It sorts by swapping elements within the same array, not by creating another array.
The Trade-Offs of In-Place Algorithms
In-place algorithms are powerful, but they are not automatically better in every situation. The biggest trade-off is that they mutate the original data. If other parts of your program still need the original version, changing it can introduce bugs.
For example, imagine a dashboard that displays both “original sales order” and “optimized sales order.” If you sort the original array in-place, you may accidentally lose the original sequence. In that case, making a copy first may be the safer choice.
There can also be readability concerns. Some in-place algorithms use clever pointer manipulation, swapping, or partitioning logic. These techniques save memory, but they may be harder for new developers to understand and maintain.
In-Place Matrix Rotation
A more visual example is rotating a square matrix 90 degrees clockwise. Instead of creating a new matrix, you can rotate it layer by layer, moving four values at a time.
function rotateMatrix(matrix) {
const n = matrix.length;
for (let layer = 0; layer < Math.floor(n / 2); layer++) {
const first = layer;
const last = n - 1 - layer;
for (let i = first; i < last; i++) {
const offset = i - first;
const top = matrix[first][i];
matrix[first][i] = matrix[last - offset][first];
matrix[last - offset][first] = matrix[last][last - offset];
matrix[last][last - offset] = matrix[i][last];
matrix[i][last] = top;
}
}
return matrix;
}
This example shows how in-place algorithms can be more complex than copy-based alternatives. A copy-based rotation may be easier to write, but it requires another matrix of the same size. For a 5,000 by 5,000 matrix, that can mean allocating 25 million additional cells.
Image not found in postmetaHow to Recognize an In-Place Algorithm
When deciding whether an algorithm is in-place, ask these questions:
- Does it modify the original input? In-place algorithms usually do.
- Does extra memory grow with input size? If yes, it is probably not in-place.
- Does it only use a few temporary variables? If yes, it may be in-place.
- Does recursion use stack space? Recursive algorithms may use extra call stack memory, even if they do not create new arrays.
The recursion point is worth noting. Quick sort is often described as in-place, but recursive implementations still use stack space. On average, that stack space is usually O(log n), although poor pivot choices can make it worse.
When Should You Use In-Place Algorithms?
Use in-place algorithms when memory efficiency matters, when data copying is expensive, or when mutation is acceptable. They are especially useful for large arrays, streams of numerical data, image processing, and performance-sensitive systems.
However, avoid them when preserving the original data is important, when code clarity matters more than memory savings, or when your application follows an immutable programming style. In frameworks and state-management systems, mutation can make changes harder to track.
Final Thoughts
In-place algorithms are a core programming concept because they teach you to think carefully about memory, not just speed. By rearranging data directly, they can reduce overhead and make programs more efficient, especially at scale. The best developers know when to use them and when to choose a simpler copy-based approach. In practice, the right choice depends on your constraints: memory, performance, readability, and whether the original data must remain unchanged.