# JavaScript Algorithms: Sorting, Searching, and Graph Traversal

JavaScript is a versatile programming language widely used for web development. While it is known for its ability to enhance the interactivity of web pages, JavaScript also provides powerful algorithms for sorting, searching, and graph traversal. These algorithms are essential in solving complex problems efficiently. In this article, we will explore advanced JavaScript algorithms, including sorting algorithms like quicksort and mergesort, searching algorithms like binary search, and graph traversal algorithms like breadth-first search and depth-first search.

## Sorting Algorithms

Sorting algorithms play a crucial role in organizing data in a specific order. JavaScript offers several efficient sorting algorithms, two of which are quicksort and mergesort.

Let's take a look at each algorithm and their implementation in JavaScript −

### Quicksort

Quicksort is a popular divide-and-conquer sorting algorithm. It works by selecting a pivot element and partitioning the array into two sub-arrays, one with elements smaller than the pivot and the other with elements greater than the pivot. The algorithm is then recursively applied to the sub-arrays.

### Example

Consider the code shown below.

function quicksort(arr) {
if (arr.length <= 1) {
return arr;
}

const pivot = arr;
const left = [];
const right = [];

for (let i = 1; i < arr.length; i++) {
if (arr[i] < pivot) {
left.push(arr[i]);
} else {
right.push(arr[i]);
}
}

return [...quicksort(left), pivot, ...quicksort(right)];
}

const arr = [5, 2, 9, 1, 7];
console.log(quicksort(arr));


### Explanation

In the code snippet above, the quicksort function takes an array as input and recursively applies the quicksort algorithm. It selects the first element as the pivot and creates two sub-arrays, left and right, to hold elements smaller and larger than the pivot, respectively. Finally, it concatenates the sorted left array, the pivot, and the sorted right array to return the sorted array.

The output of the above code will be [1, 2, 5, 7, 9], which is the sorted version of the input array [5, 2, 9, 1, 7].

## Mergesort

Mergesort is another efficient sorting algorithm that follows the divide-and-conquer approach. It works by dividing the array into smaller sub-arrays, sorting them, and then merging them back together.

### Example

Consider the code shown below.

function mergesort(arr) {
if (arr.length <= 1) {
return arr;
}

const mid = Math.floor(arr.length / 2);
const left = mergesort(arr.slice(0, mid));
const right = mergesort(arr.slice(mid));

return merge(left, right);
}

function merge(left, right) {
const merged = [];
let leftIndex = 0;
let rightIndex = 0;

while (leftIndex < left.length && rightIndex < right.length) {
if (left[leftIndex] < right[rightIndex]) {
merged.push(left[leftIndex]);
leftIndex++;
} else {
merged.push(right[rightIndex]);
rightIndex++;
}
}

return merged.concat(left.slice(leftIndex)).concat(right.slice(rightIndex));
}

const arr = [5, 2, 9, 1, 7];
console.log(mergesort(arr));


### Explanation

The mergesort function takes an array as input and recursively applies the mergesort algorithm. It divides the array into two halves and recursively sorts them using mergesort. The merge function is used to merge the sorted sub-arrays back together by comparing the elements from both arrays and appending them to the merged array in ascending order. The sorted left and right arrays are concatenated with any remaining elements from either array.

The output of the above code will also be [1, 2, 5, 7, 9], indicating that the mergesort algorithm successfully sorted the input array.

## Searching Algorithms

Searching algorithms are used to find a specific element or condition within a given dataset. One of the most efficient searching algorithms is the binary search algorithm. Let's explore its implementation in JavaScript −

### Binary Search

Binary search is a divide-and-conquer algorithm used to search for a specific element in a sorted array. It repeatedly divides the array in half and compares the target element with the middle element to determine if it should search the left or right half.

### Example

Consider the code shown below.

function binarySearch(arr, target) {
let start = 0;
let end = arr.length - 1;

while (start <= end) {
const mid = Math.floor((start + end) / 2);

if (arr[mid] === target) {
return mid;
} else if (arr[mid] < target) {
start = mid + 1;
} else {
end = mid - 1;
}
}

return -1;
}

const arr = [1, 2, 5, 7, 9];
console.log(binarySearch(arr, 7));


### Explanation

The binarySearch function takes a sorted array arr and a target element target as input. It initialises two pointers, start and end, representing the start and end indices of the sub-array. It then enters a loop that continues until the start pointer is less than or equal to the end pointer. In each iteration, it calculates the middle index mid and compares the target element with the middle element of the sub-array. If the target is found, it returns the index. Otherwise, it adjusts the start and end pointers based on whether the target is greater or less than the middle element.

The output of the above code will be 3, indicating that the target element 7 was found at index 3 in the array [1, 2, 5, 7, 9].

## Graph Traversal Algorithms

Graph traversal algorithms are used to explore or traverse a graph data structure. They can be used to solve various problems, such as finding the shortest path or detecting cycles. Two commonly used graph traversal algorithms are breadth-first search (BFS) and depth-first search (DFS). Let's examine their implementation in JavaScript:

Breadth-first search is an algorithm that explores all the vertices of a graph at the same level before moving to the next level. It uses a queue to keep track of the vertices to visit next.

### Example

Consider the code shown below.

function bfs(graph, start) {
const queue = [start];
const visited = new Set();

while (queue.length > 0) {
const vertex = queue.shift();

if (!visited.has(vertex)) {
console.log(vertex);

for (const neighbor of graph[vertex]) {
queue.push(neighbor);
}
}
}
}

const graph = {
A: ['B', 'C'],
B: ['A', 'D'],
C: ['A', 'E'],
D: ['B'],
E: ['C']
};

console.log('BFS traversal:');
bfs(graph, 'A');


### Explanation

The bfs function takes a graph represented as an adjacency list and a starting vertex as input. It initialises a queue with the starting vertex and a visited set to keep track of visited vertices. It then enters a loop that continues until the queue is empty. In each iteration, it dequeues a vertex from the queue, checks if it has been visited, and if not, marks it as visited and prints it. It then adds all unvisited neighbours of the vertex to the queue.

### Depth-First Search (DFS)

Depth-first search is an algorithm that explores all the vertices of a graph by traversing as far as possible along each branch before backtracking. It uses a stack or recursion to keep track of the vertices to visit next.

### Example

function dfs(graph, start, visited = new Set()) {
console.log(start);

for (const neighbor of graph[start]) {
if (!visited.has(neighbor)) {
dfs(graph, neighbor, visited);
}
}
}

const graph = {
A: ['B', 'C'],
B: ['A', 'D'],
C: ['A', 'E'],
D: ['B'],
E: ['C']
};

console.log('DFS traversal:');
dfs(graph, 'A');


### Explanation

The dfs function takes a graph represented as an adjacency list, a starting vertex, and a visited set (optional) as input. It prints the current vertex, marks it as visited, and recursively applies the dfs function to its unvisited neighbours. This process continues until all vertices have been visited.

Updated on: 25-Jul-2023

142 Views 