unit-iii_searching-and-sorting_final
unit-iii_searching-and-sorting_final
1. Sequential search
2. Binary search
3. Fibonacci search
4. Index sequential search
5. Hashed search
The performance of a searching algorithm can be
computed by counting the number of comparisons to
find a given value.
Linear Search
Sentinel Linear Search as the name suggests is a type of Linear Search where the number
of comparisons is reduced as compared to a traditional linear search. In a traditional linear
search, only N comparisons are made, and in a Sentinel Linear Search, the sentinel value is
used to avoid any out-of-bounds comparisons, but there is no additional comparison made
specifically for the index of the element being searched.
IIn this search, the last element of the array is replaced with the element to be searched
and then the linear search is performed on the array without checking whether the current
index is inside the index range of the array or not because the element to be searched will
definitely be found inside the array even if it was not present in the original array since the
last element got replaced with it. So, the index to be checked will never be out of the
bounds of the array. The number of comparisons in the worst case there will be (N + 2).
Sentinel Search
The basic idea of Sentinel Linear Search is to add an extra element at the end of
the array (i.e., the sentinel value) that matches the search key. By doing so, we
can avoid the conditional check for the end of the array in the loop and terminate
the search early, as soon as we find the sentinel element. This eliminates the
need for a separate check for the end of the array, resulting in a slight
improvement in the average case performance of the algorithm.
Sentinel Search Algorithm
.
def sentinelLinearSearch(array, key):
last = array[-1] ------------------------------------------------------------1
array[-1] = key ------------------------------------------------------------ 1
i=0 ------------------------------------------------------
------1
while array[i] != key:------------------------------------------------------------n
i += 1 ------------------------------------------------------
------n-1
array[len(array) - 1] = last--------------------------------------------------1
if i < len(array) - 1 or last == key:----------------------------------------1
return i ------------------------------------------------------
------1
else:
return -1 ------------------------------------------------------------1
array = [1, 2, 3, 4, 5, 6, 7, 8, 9]
key = 8
index = sentinelLinearSearch(array, key)
if index == -1:
print(f"{key} is not found in the array: {array}")
else:
print(f"{key} is found at index {index+1} in the array: {array}")
Time Complexity
● Divide the search space into two halves by finding the middle index “mid”.
● Compare the middle element of the search space with the key.
● If the key is found at middle element, the process is terminated.
● If the key is not found at middle element, choose which half will be used as the next search
space.
● If the key is smaller than the middle element, then the left side is used for next search.
● If the key is larger than the middle element, then the right side is used for next search.
● This process is continued until the key is found or the total search space is exhausted.
Example
Consider an array arr[] = {2, 5, 8, 12, 16, 23, 38, 56, 72, 91}, and the target = 23.
First Step: Calculate the mid and compare the mid element with the key. If the key is less
than mid element, move to left and if it is greater than the mid then move search space to
the right.
● Key (i.e., 23) is greater than current mid element (i.e., 16). The search space moves
to the right.
Step 2
● Key is less than the current mid 56. The search space moves
to the left.
Step 3
Second Step: If the key matches the value of the mid element,
the element is found and stop search.
Time Complexity
Pros
1. Suitable for sorted data
2. Efficient for large lists
3. Suitable for storage structures that support direct
access to data
4. Time complexity is O(log2 (n))
Cons
1. Not applicable for unsorted data
2. Not suitable for storage structures that do not support
direct access to data, for example,
magnetic tape and linked list
3. Inefficient for small list
Fibonacci Search
Q1. What are the Boundary Cases of the Insertion Sort algorithm?
Insertion sort takes the maximum time to sort if elements are sorted in reverse
order and it takes minimum time (Order of n) when elements are already sorted.
Pass 2:
Pass 3:
Pass 5 :
Pseudocode
void selectionSort(int arr[], int n)
{
int i, j, min_idx;
// One by one move boundary of unsorted subarray
for (i = 0; i < n - 1; i++)
{ // Find the minimum element in unsorted array
min_idx = i;
for (j = i + 1; j < n; j++)
{
if (arr[j] < arr[min_idx])
min_idx = j;
}// Swap the found minimum element with the first element
if (min_idx != i)
swap(arr[min_idx], arr[i]);
}
}
Time Complexity
Space Complexity
⚫ Selection sort’s space complexity is O(1), as it doesn’t take any extra space.
Advantages of Selection Sort
⚫ Is easy to implement
⚫ Works well on small lists
⚫ Does not require additional temporary storage
Disadvantages of Selection Sort
Question 2: How many swaps does the selection sort algorithm make?
Answer: The selection sort algorithm makes n-1 swaps in the worst case and zero
swaps in the best case. Therefore, it never makes more than O(n) swaps. So, it is
handy in situations where “memory write” is a costly operation.
Step 1 − Start
Step 2 − Initialize the value of gap size. Example: h
Step 3 − Divide the list into smaller sub-part. Each
must have equal intervals to h
Step 4 − Sort these sub-lists using insertion sort
Step 5 – Repeat this step 2 until the list is sorted.
Step 6 – Print a sorted list.
Step 7 – Stop
Working of Shell Sort
⚫ https://www.geeksforgeeks.org/sorting-algorithms/
⚫ https://www.tutorialspoint.com/data_structures_alg
orithms/sorting_algorithms.htm
⚫ https://www.geeksforgeeks.org/searching-
algorithms/