Sorting is one of the most important operations in programming. It allows for the efficient storage and retrieval of data, in many cases ahead of what could be achieved in linear or sequential search. In this article, you will learn about the principles behind sorting in Javascript, as well as examples of different algorithms used to sort data in Javascript.
What is Sorting in Javascript?
Sorting is the process of rearranging a given set of data items in ascending or descending order according to a specific criterion. By using a suitable sorting algorithm, one can reduce the time complexity of a given process. In Javascript, there are various sorting algorithms such as bubble sort, insertion sort, merge sort, quick sort, and heap sort.
Types of Sorting Algorithms Used in Javascript
The following sorting algorithms are available for use in Javascript:
- Bubble Sort: Bubble sort is a simple sorting algorithm which works by repeatedly swapping adjacent elements which are not in their correct order. It is simple to understand and implement but has a time complexity of O(n2).
- Insertion Sort: Insertion sort works by repeatedly shifting elements which are not in their correct order. It is more efficient than bubble sort, with a time complexity of O(n log n).
- Merge Sort: Merge sort works by dividing the given array into two halves, recursively sorting the halves and then merging them together. It has a time complexity of O(n log n).
- Quick Sort: Quick sort works by picking a pivot element and then dividing the array into two parts according to the element’s value. It has a time complexity of O(n log n).
- Heap Sort: Heap sort works by sorting a binary max heap, which has a time complexity of O(n log n). It is more efficient than quick sort in practice.
Comparator Functions and How They Work
In Javascript, the native ‘sort’ function takes a comparator function as an argument. A comparator function is a function that takes two arguments and returns either a negative number (if the first argument is less than the second argument), zero (if both arguments are equal), or a positive number (if the first argument is greater than the second argument). The ‘sort’ function will the use this comparator function to order its elements.
Understanding Array Sorting in Javascript
In Javascript, an array is a data structure that stores related data in contiguous memory locations. It allows for efficient insertion and retrieval of data when used correctly. Array sorting refers to the process of sorting the elements of an array in ascending or descending order according to a specific criterion. In Javascript, there are various sorting algorithms that can be used to accomplish this task.
Using the Sort() Method in Javascript
In Javascript, sorting an array can be achieved by using the native ‘sort’ method. This method takes an optional argument that is a comparator function. By using this method and providing an appropriate comparator function, one can efficiently sort the elements of an array. For example:
let array = [5, 8, 1, 10]; //unsorted array array.sort((a, b) => a - b) //sorts the array in ascending order // [1, 5, 8, 10]
Utilizing the sort() Method with Custom Data Structures
The sort() method can also be used to sort custom data structures such as linked lists or trees. In this case, the comparator function must be implemented for the custom data structure. Additionally, the data structure in question must have efficient insert and remove methods (for inserting and removing elements from the structure) and an efficient search method (for finding elements within the structure). Once these methods are defined and implemented, they can be used together with the native sort() method to achieve an efficient sorting algorithm.
Implementing Bubble Sort in Javascript
Bubble sort is a simple sorting algorithm which works by repeatedly swapping adjacent elements which are not in their correct order. It has a time complexity of O(n2) and is not suitable for large datasets. However, it can be useful for small datasets and sorting tasks that require minimum modifications to existing code.
function bubbleSort(arr) { //sorts an array of numbers in ascending order let swapped; //boolean flag to indicate whether an element was swapped or not do { swapped = false; //set flag = false to indicate that no swaps were done //loop through each element and compare to adjacent element for (let i = 0; i < arr.length; i++) { //if current element > adjacent element, swap if (arr[i] > arr[i+1]) { let temp = arr[i]; //store current element in temporary variable arr[i] = arr[i+1]; //replace current element with adjacent element arr[i+1] = temp; //replace adjacent element with temporary variable swapped = true; //set flag = true to indicate that a swap was done } } } while (swapped); //repeat if swapped = true return arr; //return sorted array } bubbleSort([5, 8, 1, 10]); // returns [1, 5, 8, 10]
Implementing Insertion Sort in Javascript
Insertion sort works by repeatedly shifting elements which are not in their correct order. It has a time complexity of O(n log n) and is more efficient than bubble sort. This makes it suitable for large datasets. Additionally, insertion sort works well when elements are already sorted or nearly sorted.
function insertionSort(arr) { //sorts an array of numbers in ascending order for (let i = 1; i < arr.length; i++) { //loop through each element in array let currentValue = arr[i]; //initially set currentValue = element at index = i //compare currentValue to each preceding element while (arr[i - 1] > currentValue && i > 0) { arr[i] = arr[i - 1]; //swap preceding element with current value i--; //decrement loop arr[i] = currentValue; //replace preceding element with currentValue } } return arr; //return sorted array } insertionSort([5, 8, 1, 10]); // returns [1, 5, 8, 10]
Leveraging Merge Sort for Complex Data Structures in Javascript
Merge sort is an efficient sorting algorithm which works by dividing the given array into two halves, recursively sorting the halves and then merging them together. It has a time complexity of O(n log n) which makes it suitable for use with large datasets. Additionally, merge sort can efficiently be used to sort complex data structures such as linked lists.
//main mergeSort function function mergeSort(arr) { //sorts an array of numbers in ascending order if (arr.length <= 1) { //base case - return if array contains 1 or 0 elements return arr; } const midIndex = Math.floor(arr.length / 2); //index to split array in half const leftHalf = arr.slice(0, midIndex); //store left half of array const rightHalf = arr.slice(midIndex); //store right half of array //recursively split and merge each half //starts off with two arrays with one element each const sortedLeftHalf = mergeSort(leftHalf); //split left half const sortedRightHalf = mergeSort(rightHalf);//split right half const sortedArray = mergeHalves(sortedLeftHalf, sortedRightHalf); return sortedArray; //returns sorted array } //merges two halves together - helper function to mergeSort() function mergeHalves(leftHalf, rightHalf) { const mergedArray = []; //Init empty array to store sorted elements let leftIndex = 0; //index for traversing left half let rightIndex = 0; //index for traversing right half while (leftIndex < leftHalf.length && rightIndex < rightHalf.length) { /*compare first element of leftHalf and rightHalf */ if (leftHalf[leftIndex] < rightHalf[rightIndex]) { mergedArray.push(leftHalf[leftIndex]); //push smaller number onto array leftIndex++; //increment leftIndex and traverse left half } else { mergedArray.push(rightHalf[rightIndex]); //push smaller number onto array rightIndex++; //increment rightIndex and traverse right half } } /*if one of the halves still has unmerged elements, add them all */ const remainingElements = leftHalf.slice(leftIndex).concat(rightHalf.slice(rightIndex)); return mergedArray.concat(remainingElements); //add remainder onto mergedArray } mergeSort([5, 8, 1, 10]); // returns [1, 5, 8, 10]
Utilizing Quick Sort for Fast Sorting Algorithms
Quick sort works by picking a pivot element and then dividing the array into two parts according to its value. It has a time complexity of O(n log n) which makes it one of the most efficient sorting algorithms available. Additionally, it is suitable for sorting large datasets and complex structures.
function quickSort(arr) { //sorts an array of numbers in ascending order if (arr.length <= 1) { //base case - return if array contains 1 or 0 elements return arr; } const pivotValue = arr[arr.length - 1]; //initially set pivotValue = last item in array const leftArray = []; //init empty arrays to store elements less than/greater than pivotValue const rightArray = []; /*loop through each item in original array (except pivot value), pushing items less/greater than pivotValue onto respective arrays */ for (let i = 0; i < arr.length - 1; i++) { if (arr[i] < pivotValue) { leftArray.push(arr[i]); //push value less than pivot onto leftArray } else { rightArray.push(arr[i]); //push value greater than pivot onto rightArray } } /*recursively quickSort both halves */ const sortedLeftArray = quickSort(leftArray); //split & quickSort leftArray const sortedRightArray = quickSort(rightArray); //split & quickSort rightArray return sortedLeftArray.concat([pivotValue], sortedRightArray); //merges & returns sorted array } quickSort([5, 8, 1, 10]); // returns [1, 5, 8, 10]
Optimizing Performance with Heap Sort
Heap sort is an efficient algorithm for sorting large datasets which works by sorting a binary max heap. It has a time complexity of O(n log n) but is significantly faster than quick sort in practice as it does not require any additional storage or recursive calls.
function heapSort(arr) { //sorts an array of numbers in ascending order /*creates max heap out of given array - Maximum value located at rootNode */ var heapSize = arr.length; //init heapSize equal to length of given array buildMaxHeap(arr); //build max heap out of given array /*swap rootNode with last item/leafNode in heap*/ while (heapSize > 1) { swap(arr, 0, --heapSize); //swap rootNode & last item heapify(arr, 0, heapSize); //heapify reduces rootNode value accordingly } return arr; //return heap - now sorted } /*buildMaxHeap builds a maxHeap out of given array*/ function buildMaxHeap(arr) { var i = Math.floor(arr.length / 2 - 1); global /*loop dons on each element starting from parentNode*/ while (i >= 0) { heapify(arr, i--, arr.length); } } /*swap helper function - swaps parentNode with childNode*/ function swap(arr, a ,b) { var tmp = arr[a]; arr[a] = arr[b]; arr[b] = tmp; } /*heapify helper function-recursively checks each node*/ function heapify(heap, pos ,heapSize) { /*Find max among currentNode & its childNodes*/ var leftNode = 2 * pos + 1; var rightNode = 2 * pos + 2; var max = pos; if (leftNode < heapSize && heap[leftNode] > heap[max]) max = leftNode; if (rightNode < heapSize && heap[rightNode] > heap[max]) max = rightNode; /* swap if necessary*/ if (max != pos) { swap(heap ,pos ,max); heapify(heap ,