Search algorithms and their implementations

As the name suggests, searching algorithms find and retrieve a data item within a data structure. One of the popular use-cases of search algorithms is a search engine. Search engines like Google, AOL, Bing, and Yahoo utilize search algorithms to quickly crawl and index billions of information on the internet to get a user a piece of the requested information. The algorithm’s efficiency determines how fast the search engines can retrieve this information and the abundance of information in their index.

In real life, there are diverse ways we search for items. The way librarians search for books differs from searching for keys in their bag, a word in a dictionary, or a product on a supermarket shelf.
For a computer program, it is no different. Several search algorithms cater to various search processes. They include:

  • Linear search
  • Binary search
  • Jump search
  • Sublist search
  • Interpolation search
  • Fibonacci search

Linear Search

A linear search starts its search at the beginning of the data structure or list, works its way sequentially through each data element until it reaches the item it is searching for at the end of the list.
It is a simple algorithm but highly inefficient. A list containing a few elements works well with this algorithm, but it becomes inept when we have a considerable number of pieces. Say we have a million features in the list, and the item we need is at the 900,000th index. In such a case, a linear search will go through over 800,000+ items to get to its intended element. That is a lot of time spent processing.
The time complexity for a linear search is 0(n). It means execution time increases as the number of elements increases. We use this algorithm with unsorted and sorted elements.

The Algorithm

STEP 1:
Start searching at first element (i)
STEP 2:
Move to the second element and repeat for all elements
STEP 3:
At current element, check if it is the required element
IF TRUE
PRINT 'Element found at index number'
STEP 4:
Until FOUND == TRUE, or element not found, Repeat search till th
STEP 5:
STEP 6:

Code implementation in Javascript

nums = [1, 2, 23, 4, 11, 77, 55, 44, 33, 67]
a = 4

function LinearSearch(nums, a)
{
  let results = []
  for (let i = 0; i < nums.length; i++)
  {
    if (nums[i] === a)
    {
      results.push(i)
    }
  }
  // return -1 when the results array is empty 
  if (!results)
  {
    return -1
  }
  // else return results 
  return results
}
document.write(LinearSearch(nums, a))

Code implementation in Python

index = -1
nums = [10, 18, 9, 4, 66, 90, 2, 16, 34, 65]
a = 34

def linear_search(nums, a):
  i = 0

while i < len(nums):
  if nums[i] == a:
  globals()['index'] = i
return True

i = i + 1

if linear_search(nums, a):
  print('Number found at index', index + 1)# specify the index the number is found at
else :
  print('Number not found')

print(linear_search(nums, a))

Binary Search

Unlike linear search, binary search picks a midpoint in the data structure and divides the elements into two, from that point. It works only with sorted elements since it must determine if the item it is searching for is higher or lower than the other two sides. It chooses the next midpoint of the search based on this.
If the element it searches for is more significant than the midpoint, it moves to the right side with higher values and searches there. If the searched item is lower, it moves to the left side. If the element is equal to the midpoint, it stops its search there. We continue with this process until we get what we want.
Binary search is considered a more efficient algorithm than linear search. It divides elements and quickly discards elements not worth its time and moves to more relevant details. The time complexity is 0(log n).
A drawback with Binary Search is that if multiple occurrences of a particular element exist in an array, it does not return the index of that first element but the index closest to it.
An array containing the following values [1,2,3,4,4,5] returns a 3 if we search for 4.

The Algorithm

STEP 1:  
Start
STEP 2:
Determine the middle item in the list using the formula;
mid = low + (high - low) / 2
to set a midpoint.
STEP 3:
Compare the value of the middle element to the element being searched for.
STEP 4:
IF TRUE, GOTO STEP 7
ELSE
STEP 5:
IF target element is > middle element,
THEN
discard the left hand side of the list
ELSE
STEP 6:
IF target element is < middle element
THEN
Discard the right hand side of the list
ENDIF
STEP 7:
Repeat process 2-6 and iteration until target element == Trueor no more item
STEP 8:
Start

Code implementation in JavaScript

//program to write binary search algorithm 
function binary_search(num, index)
{ //num is the array, index the target element 
  let start = 0;
  let end = num.length - 1;
  while (start <= end)
  {
    let midpoint = Math.floor((start + end) / 2);
    if (num[midpoint] === index)
    {
      // Found the element 
      return midpoint;
    }
    else if (num[midpoint] < index)
    {
      // if the index is less than the midpoint, the program keeps searching to the right  
      start = midpoint + 1;
    }
    else
    {
      // if the index is greater than the midpoint, the program continues searching to the left 
      end = midpoint - 1;
    }
  }
  // index not found 
  return -1;
}
let num = [1, 2, 3, 4, 5, 6, 7, 8, 9]
let index = 7
document.write(binary_search(num, index))

Code Implementation in Python

sequence_a = [2, 4, 5, 6, 7, 8, 9, 10, 12, 13, 14]
index = 6

def binary_search(arr, item):
  beg_index = 0
end_index = len(arr) - 1

while beg_index <= end_index:
  midpoint = beg_index + (end_index - beg_index) // 2 
midpoint_value = arr[midpoint]
if midpoint_value == item:
  return midpoint

elif item < midpoint_value:
  end_index = midpoint - 1

else :
  beg_index = midpoint + 1

return None

if binary_search(sequence_a, index):
  print('Number', index, 'found')
else :
  print('Number not found')

print('At index', binary_search(sequence_a, index))

Fibonacci algorithm

Are you familiar with the mathematical Fibonacci sequence? The Fibonacci algorithm is the same as the Fibonacci sequence and follows the same logic. In programming, the Fibonacci sequence provides an intricate side-view when it comes to determining the difference between loops and recursion.
Fibonacci sequence is a group of numbers, starting from 0 where the next number is an addition of the last number + the current number. So we have:

0, 1, 1, 2, 3, 5, 13, 21, 34...

Usually, the first number is initialized to either a 0 or 1, depending on where we want to start counting. Fibonacci algorithms work with three numbers, the first number, the following number after it, and their sum. If we initialize to 0, the following number is 1, and the value of the next number is 0+1, which is 1, after which we add 1 + 1 to give us the following number 2.

0,1,1,2...

Calculating for a Fibonacci sequence is calculating the nth term of a set of sequences. The nth term is the sum of the (n-1)th and the (n-2)th term. The formula for this is,

tn  =  tn-1 + tn-2

The time complexity for the Fibonacci algorithm is 0(log n), just like a binary search. One of its uses is in the financial trade market, where Fibonacci numbers serve as technical indicators.

Algorithm

STEP 1:
Start
STEP 2:
Declare the variables for the first, second, third numbers, increment and nth position (x, y, z, i, n)
STEP 3:
Initialize the variables, x = 0, y = 1 and c = 2
STEP 4:
Get the value of the number of terms, n
STEP 5:
Get the sum of the first two terms
STEP 6:
Repeat until i<=n
Z = x + y
Print z
x = y, y = z
i = i + 1
STEP 7:
Stop

Code implementation with Javascript

//program to write fibonacci algorithm 
function fibonacci_search(num)
{
  var x = 1,
    y = 0,
    z;
  while (num >= 0)
  {
    z = x;
    x = x + y;
    y = z;
    num--;
  }
  return y;
}
document.write(fibonacci_search(8))

Code implementation with Python

# Fibonnacci sequence solution

def fibonacci(no): #the base
case
if no <= 1:
  return no
  else :
    return (fibonacci(no - 1) + fibonacci(no - 2))
  length = int(input("Length of the sequence "))# takes input from the user

  if length <= 0:
    print("Please enter a number greater than zero")
  else :
    print("Fibonacci sequence:")
  for i in range(length):
    print(fibonacci(i))

# output
# Length of the sequence 10# Fibonacci sequence:
# 0,1,1,2,3,5,8,13,21,34

Jump Search Algorithm

Jump search, like binary search, works only with sorted arrays and uses a divide and conquer approach, designed as an improvement over linear search. The algorithm searches for an element by jumping m number of components and determines if the searched term is between the previous and current jump.
To start the process, we need a low and high value, namely, the starting and ending points of the array. The algorithm also has a size n, the size of the array, and a block jump or size m.
If we have an array of 1 - 12 (making the size n = 12), with index 0 to 11, our low value is 1, which is at index 0, and the high value is 12, which is at index 11. If we take our jump block, m, to be 3, the algorithm iterates by jumping over every three elements. So it moves from index 0 - 3, jumps from 3 to 6, and 6 to 9.
At every jump, we compare the elements in the array with the target element and array’s size. We also note the number of jumps the program makes.

Between 0-3, 1 jump

Between 3 - 6, 2 jumps

Between 6 - 9, 3 jumps

Here, it stops. Jumping from 9 - 12 is smaller than the jump size (which is 3). Our last index stops at 11. From index 9, we perform the search linearly, moving from 9 to 10 to 11. This linear movement is still counted as a jump but not of block m. therefore the total number of jumps = 5.
The time Complexity, O(√n) is calculated by the number of jumps and the number of elements within each block.

Algorithm

STEP 1:
Start
STEP 2:
Determine jump size, m with the formular, math.sqrt(n(arr))
STEP 3:
Start iteration at the beginning of n
STEP 4:
When i = 0, start iteration with m jump. Do this until the end of the list (n < i)
STEP 5:
Compare the target element with elements in the list after each jump.
IF target element == TRUE
STEP 10
STEP 6:
IF target element less than m, continue jump
STEP 7:
IF target element greater than jump
Stop at the previous jump and perform a linear search
STEP 8:
IF m jump cannot be completed, but there are elements in n, perform a linear search
STEP 9:
IF target element == FALSE,
Exit
STEP 10:
Exit

Code implementation in JavaScript

function jumpSearch(n, element)
{
  let len = n.length
  //making m the jump block 
  let m = Math.floor(Math.sqrt(len));
  //starting index 
  let startindex = 0,
    currentStep = m;
  while (n[Math.min(currentStep, len) - 1] < element)
  {
    //processing to the next jump if target element not found in the current jump 
    startindex = currentStep;
    currentStep += m;
    if (startindex >= len) return -1;
  }
  //Linear Search block  
  while (n[startindex] < element)
  {
    startindex++;
    //if we can't find target element in the array 
    if (startindex == Math.min(currentStep, len)) return -1;
  }
  if (n[startindex] == element) return startindex
  else return -1;
}
let n = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
let element = 12;
document.write(jumpSearch(n, element))

Code implementation in Python

import math

def jump_search(n, element):

  #n - The array / list
  # element - Item that the index needs to find

print("Processing Jump Search")
a = len(n)
m = int(math.sqrt(a))# m = jump block
i = 0

while i != len(n) - 1 and n[i] < element:
  print("Processing Batch - {}".format(n[i: i + m]))

if n[i + m - 1] == element:
  return i + m - 1

elif n[i + m - 1] > element:
  B = n[i: i + m - 1]
return linear_search(B, element, i)
i += m

B = n[i: i + m]
print("Processing Batch - {}".format(B))
return linear_search(B, element, i)

The Linear Search function part of the code

def linear_search(B, element, loc): 
#loc - The Index where the remaining batch begins# B is the derived list
print("\t Starting Linear Search")
i = 0

while i != len(B):
  if B[i] == element:
  return loc + i
i += 1
return -1

if __name__ == "__main__":

  print(jump_search(n, 12))

# prints the index

Sublist Algorithm

The sublist search algorithm determines if there is a sublist in another list. It compares the first list to the second to ascertain if list one is in list two.
If we had a list containing [25, 12, 19, 2] and another that had [14, 25, 33, 12,2, 80, 19, 72], we could immediately see some shared elements. What the sublist algorithm does is to check this in a linear, sequential manner.

Algorithm

STEP 1: 
Start
STEP 2:
Declare the variables for the two lists
STEP 3:
Take first node of the second list
STEP 4:
Match the elements of the first list with this node
STEP 5:
IF the elements match, return TRUE
STEP 6:
ELSE, iterate through the first node
STEP 7:
AND take the second list to the second node
STEP 8:
Repeat the process until both lists are empty
STEP 9:
IF the first list becomes empty,
Return 'List not found'
STEP 10:
Exit

Code implementation with JavaScript

// JavaScript program to find a list in second list 
// A Linked List node 
class Node
{
  constructor()
  {
    this.data = 0;
    this.next = null;
  }
}
// Returns true if first list is present in second list 
function findList(list1, list2)
{
  var ptr1 = list1,
    ptr2 = list2;
  // If both linked lists are empty,return true 
  if (list1 == null && list2 == null) return true;
  // Else If one is empty and other is not, return false 
  if (list1 == null || (list2 != null && second == null)) return false;
  // pick nodes one by one 
  while (list2 != null)
  {
    // Initialize ptr2 with 
    // current node of second 
    ptr2 = list2;
    while (ptr1 != null)
    {
      if (ptr2 == null) return false;
      else if (ptr1.data == ptr2.data)
      {
        ptr1 = ptr1.next;
        ptr2 = ptr2.next;
      }
      // If not equal then break the loop 
      else break;
    }
    // Return true if first list gets traversed 
    if (ptr1 == null) return true;
    // Initialize ptr1 with first again 
    ptr1 = first;
    // move to the node of second list 
    second = second.next;
  }
  return false;
}
/* Function to print the nodes */
function printNode(node)
{
  while (node != null)
  {
    document.write("%d ", node.data);
    node = node.next;
  }
}
// The function we need to add new node to linked lists 
function newNode(key)
{
  var temp = new Node();
  temp.data = key;
  temp.next = null;
  return temp;
}
// Driver Code 
/* 
 Let us create two linked lists to test 
 the above functions. Created lists 
 shall be x: 1->2->3->4 y: 1->2->1->2->3->4 
 */
var x = newNode(1);
x.next = newNode(2);
x.next.next = newNode(3);
x.next.next.next = newNode(4);
var y = newNode(1);
y.next = newNode(2);
y.next.next = newNode(1);
y.next.next.next = newNode(2);
y.next.next.next.next = newNode(3);
y.next.next.next.next.next = newNode(4);
if (findNode(x, y) == true) document.write("LIST FOUND");
else document.write("LIST NOT FOUND");

Code implementation with Python

#Python3 program to find a list in another list
class Node:
  def __init__(self, value = 0):

self.value = value
self.next = None

# Returns true
if first list is present in second list
def findList(list1, list2):
  if not first and not second:
  return True

# If ONLY one of them is empty, #
return False
if not list1 or not list2:
  return False

ptr1 = first
ptr2 = second

# Iterate the second list by picking nodes one after the other
while ptr2:

  #Initialize 'ptr2'
with current node of 'second'
ptr2 = second

while ptr1:
  if not ptr2:
  return False
elif ptr1.value == ptr2.value:
  ptr1 = ptr1.next
  ptr2 = ptr2.next
else:
  break

# If 'ptr1' is None / empty, that means the 'first LL' has been completely traversed and matched so return True
if not ptr1:
  return True

return False

Interpolation Search Algorithm

The interpolation algorithm is another divide-and-conquer algorithm. It works with a sorted array of uniform distribution.
Unlike the other algorithms, it does not just start a search. Instead, it has a mathematical formula and performs some calculations to determine where to begin that search.
Two conditions are necessary for this algorithm to perform

  1. The elements must be sorted
  2. The elements of the list must be uniformly distributed. The difference between the elements must be the same.

The formula to get a starting position:

Interpolation Search Algorithm

Where,

low is the starting index value
x is the searched element
a is the values of the indexes
High is the last index value of the array

If we have an array of the following values

[1, 4, 7, 10, 13, 16, 19, 21, 24] with a uniform difference of 3, and we need to find 16, here is how we go about it.

Low = 0
High = 24
x = 16
a[l] = 1
a[h] = 26

Interpolation Search Example

16 is at index 5. It has taken just one step to find 16.

Sometimes, we might have a large array that is slightly not uniformed. This won't give a perfect answer. We will need to readjust the values of…
The time complexity is 0(log n) when values are uniformly distributed as 0(n), for worst-case when values are not evenly distributed.

Algorithm

STEP 1:
Start
STEP 2:
Declare the variables. x = target element
STEP 3:
Write the formula to calculate the value of the index
STEP 4:
If the value of the x and index == True, the index is returned.
STEP 5:
If the value is less than the index,
THEN the value of the index is recalculated with adjusted values for the left sub-array
STEP 6:
If the value is higher than the index,
THEN the value of the index is recalculated with adjusted values for the right sub-array.
STEP 7:
If value of x and index == FALSE
RETURN 'Index not found'
STEP 8:
Exit

Code implementation with JavaScript

//Interpolation code javascript 
const arr = [1, 4, 6, 7, 9, 12, 15, 16, 17, 23, 25, 26, 27, 31];
const index = 25;
const interpolation_Search = (arr = [], index) =>
{
  let l = 0;
  let r = arr.length - 1;
  while (l <= r)
  {
    const a_r = arr[r] - arr[l];
    Const a = r - l;
    const x = index - arr[left];
    if (x < 0)
    {
      return -1;
    }
    if (!a_r)
    {
      return arr[l] === index ? l : -1;
    }
    const middleIndex = l + Math.floor((x * a) / a_r);
    if (arr[middleIndex] === index)
    {
      return middleIndex;
    }
    if (arr[middleIndex] < index)
    {
      l = middleIndex + 1;
    }
    else
    {
      r = middleIndex - 1;
    }
  };
  return -1;
};
console.log(interpolation_Search(arr, index));

Code implementation with Python

#program to write interpolation search

def Interpolation_search(arr, index):
  low = 0
high = (len(arr) - 1)
while low <= high and index >= arr[low] and index <= arr[high]:
  element = low + int(((float(high - low) / (arr[high] - arr[low])) * (index - arr[low])))
if arr[element] == index:
  return element
if arr[element] < index:
  low = element + 1;
else :
  high = element - 1;
return -1

print(Interpolation_search([1, 2, 3, 4, 5, 6, 7, 8], 6))

Conclusion

We hope we’ve given you some good case on how to use Search Algorithms and have mentioned the most popular in their respective JavaScript and Python implementation. Search algorithms are integral part of Algorithmic knowledge in Software Engineering – and the ‘have to know’ for every software engineer!

Author

Kris Terziev

Kris is the Head of Research and Development at CodeCoda and, as he himself says, is constantly seeking better methods of developing and implementing software solutions.
In his previous experience as a software engineer, he has experienced everything from plain assembly code through the optimization of the process of business and functional analysis and the development of Fintech Applications.
During his school years, he won several medals in international competitions in mathematics and computer science. Concerning his professional interests, he pays special attention to algorithms and software development methodologies.