Implementing quick sort in JavaScript

Learn how to create an implementation of quick sort in JavaScript.

Posted on March 26, 2021


Quick sort is another sorting algorithm that allows you to sort values using a divide and conquer strategy, similar to the implementation of merge sort. Just like its name implies, quick sort is relatively more efficient and faster than merge sort for small array size, but gradually lose its efficiency and speed on large array size.

To understand the implementation of quick sort, let’s start with a small example array as follows:

               [6, 7, 3, 1, 5]

First, you need to pick one element as the pivot element. This element is usually the first or the last element of the array.

This example will pick the last element, which is 5. The elements of the array will then be sorted according to this pivot element. Elements smaller than 5 will be placed to the left, while larger elements will be placed to the right:

               [6, 7, 3, 1, 5]
               [3, 1, 5, 6, 7]

Next, you will have to sort the elements on the left side and the right side of the pivot element, with each taking a new pivot value from the sub-arrays. From the example above, this means sorting two sub-arrays: [3, 1] and [6, 7]. During the third iteration, the position of 3 and 1 will be swapped so that the array is completely sorted:

               [6, 7, 3, 1, 5]
               [3, 1, 5, 6, 7]
               [1, 3, 5, 6, 7]

Quick sort algorithm can be implemented recursively or iteratively. Let’s look at the recursive implementation first.

Quick sort using recursive approach

To implement quick sort using the recursive approach, you need to first create a partitioning() function that accepts the array (arr) you wish to sort, the startIndex, and the endIndex of the array. The function will start by grabbing the pivot element and compare the array elements with itself:

function partition(arr, startIndex, endIndex) {
  const pivotVal = arr[endIndex]; // the pivot element
}

Then, you need to keep track of the array index, which will take its value from the startIndex. Each time a swap happens, the index will move until it reaches the middle:

function partition(arr, startIndex, endIndex) {
  const pivotVal = arr[endIndex]; // the pivot element
  let index = startIndex;
}

It’s time to create the swapping algorithm. Let’s use a for loop to iterate through the array from the startIndex to the endIndex. Each time an element is smaller than the pivotVal element, you swap that element with the index, then move the index up by one:

function partition(arr, startIndex, endIndex) {
  const pivotVal = arr[endIndex]; // the pivot element
  let index = startIndex;
  // begin iterate and swap
  for (let i = index; i < endIndex; i++) {
    if (arr[i] < pivotVal) {
      [arr[i], arr[index]] = [arr[index], arr[i]];
      index += 1;
    }
  }
}

The swapping code above uses destructuring assignment to swap the elements. The logic happens as follows:

let a = 3;
let b = 10;
[a, b] = [b, a];
console.log(a, b); // a=10 b=3

The final step is to move the pivotVal element to the current index, because you need to place the pivot element in the middle of the array. After you move the pivotVal, return the middle index, so that the sorting process can use the middle index to split the array to the left side and the right side:

function partition(arr, startIndex, endIndex) {
  const pivotVal = arr[endIndex]; // the pivot element
  let index = startIndex;
  // begin iterate and swap
  for (let i = index; i < endIndex; i++) {
    if (arr[i] < pivotVal) {
      [arr[i], arr[index]] = [arr[index], arr[i]];
      index += 1;
    }
  }

  // move `pivotVal` to the middle index and return middle index
  [arr[index], arr[endIndex]] = [arr[endIndex], arr[index]];
  return index;
}

With the partition() function done, now you need to create the quickSort() function. This function will simply call the partition() function, passing along the startIndex and endIndex

function quickSort(arr, startIndex, endIndex) {
  // Base case or terminating case
  if (startIndex >= endIndex) {
    return;
  }

  // Returns midIndex / pivot index
  let midIndex = partition(arr, startIndex, endIndex);

  // Recursively apply the same logic to the left and right subarrays
  quickSort(arr, startIndex, midIndex - 1);
  quickSort(arr, midIndex + 1, endIndex);
}

And just like that, the quickSort() function is done. You can test the function by sending an array along with the startIndex and endIndex, which starts from 0 and array.length - 1:

let arr = [-2, 4, 6, 3, 7, 2];
quickSort(arr, 0, arr.length - 1);
console.log(arr); // [-2, 2, 3, 4, 6, 7]

Here’s the full code:

function partition(arr, startIndex, endIndex) {
  const pivotVal = arr[endIndex]; // the pivot element
  let index = startIndex;
  // begin iterate and swap
  for (let i = index; i < endIndex; i++) {
    if (arr[i] < pivotVal) {
      [arr[i], arr[index]] = [arr[index], arr[i]];
      index += 1;
    }
  }

  // move `pivotVal` to the middle index and return middle index
  [arr[index], arr[endIndex]] = [arr[endIndex], arr[index]];
  return index;
}

function quickSort(arr, startIndex, endIndex) {
  // Base case or terminating case
  if (startIndex >= endIndex) {
    return;
  }

  // Returns midIndex / pivot index
  let midIndex = partition(arr, startIndex, endIndex);

  // Recursively apply the same logic to the left and right subarrays
  quickSort(arr, startIndex, midIndex - 1);
  quickSort(arr, midIndex + 1, endIndex);
}

let arr = [-2, 4, 6, 3, 7, 2];
quickSort(arr, 0, arr.length - 1);
console.log(arr); // [-2, 2, 3, 4, 6, 7]

Now that you know how to implement quick sort using JavaScript, it’s time to understand the time and space complexity of quick sort in Big O Notation.

The efficiency of quick sort

The quick sort time complexity for the best-case is O(logN) while the worst-case end up at O(n²). The Big O Notation always selects the worst-case as the measurement, so quick sort is not faster than merge sort in terms of time complexity.

Still, the quick sort used in-place algorithm to swap the elements, resulting in O(N) in space complexity. Quick sort only needs extra space for storing the recursive calls.

Related articles:

Grab the free JavaScript book today 👍

Learn the building blocks of JavaScript programming language like data types, functions, objects, arrays and classes.

Use the knowledge from the book to build a small but solid program.

Learn more