Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                

Chapter Two

Download as pdf or txt
Download as pdf or txt
You are on page 1of 62

Unit 2:

Searching and Sorting


Unit 2:Syllabus
2.1 Searching
Searching is the fundamental process of locating a specific element or item within a collection of
data. This collection of data can take various forms, such as arrays, lists, trees, or other structured
representations. The primary objective of searching is to determine whether the desired element
exists within the data, and if so, to identify its precise location or retrieve it. It plays an important
role in various computational tasks and real-world applications, including information retrieval,
data analysis, decision-making processes, and more.

There are two types of Searching :


1.Linear Search.
2.Binary Search.

https://www.geeksforgeeks.org/searching-algorithms/
https://www.youtube.com/watch?v=6iZwMbaXt14
Linear Search
Linear search is also called as sequential search algorithm. It is the simplest searching algorithm.
In Linear search, we simply traverse the list completely and match each element of the list with
the item whose location is to be found. If the match is found, then the location of the item is
returned; otherwise, the algorithm returns NULL.
It is widely used to search an element from the unordered list, i.e., the list in which items are not
sorted.

Space Complexity
Since linear search uses no extra space, its space complexity is O(n), where n is the number of
elements in an array.
Time Complexity
• Best-case complexity = O(1) occurs when the searched item is present at the first element in the
search array.
• Worst-case complexity = O(n) occurs when the required element is at the tail of the array or not
present at all.
• Average-case complexity = O(n) average case occurs when the item to be searched is in
Working of Linear search
Now, let's see the working of the linear search Algorithm.

To understand the working of linear search algorithm, let's take an unsorted array. It will be easy to
understand the working of linear search with an example.

Let the elements of array are -

Let the element to be searched is K = 41

Now, start from the first element and compare K with each element of the array.
The value of K, i.e., 41, is not matched with the first element of the array. So, move to the next
element. And follow the same process until the respective element is found.

Now, the element to be searched is found. So algorithm will return the index of the element
matched.
Advantages of Linear Search Algorithm:
Linear search can be used irrespective of whether the array is sorted or not. It can be used on
arrays of any data type.
Does not require any additional memory.
It is a well-suited algorithm for small datasets.

Disadvantages of Linear Search Algorithm:


Linear search has a time complexity of O(N), which in turn makes it slow for large datasets.
Not suitable for large arrays.
When to use Linear Search Algorithm?
When we are dealing with a small dataset.
When you are searching for a dataset stored in contiguous memory.
Applications of Linear Search Algorithm:

Unsorted Lists: When we have an unsorted array or list, linear search is most commonly used to
find any element in the collection.
Small Data Sets: Linear Search is preferred over binary search when we have small data sets with
Searching Linked Lists: In linked list implementations, linear search is commonly used to find
elements within the list. Each node is checked sequentially until the desired element is found.
Simple Implementation: Linear Search is much easier to understand and implement as compared
to Binary Search or Ternary Search.
Linear Search Algorithm
The algorithm for linear search is relatively simple. The procedure starts at the very first index of
the input array to be searched.
Step 1 − Start from the 0th index of the input array, compare the key value with the value present
in the 0th index.
Step 2 − If the value matches with the key, return the position at which the value was found.
Step 3 − If the value does not match with the key, compare the next element in the array.
Step 4 − Repeat Step 3 until there is a match found. Return the position at which the match was
found.
Step 5 − If it is an unsuccessful search, print that the element is not present in the array and exit
the program.

https://www.youtube.com/watch?v=Yh__pz3X-HY
Binary Search
The binary search algorithm is a quick way to find a specific item in a sorted list. It starts by setting two
pointers, low and high, at the beginning and end of the list. The algorithm finds the middle of the list and
checks if the middle item is what you're looking for. If it is, the search is over. If the item you're looking
for is smaller than the middle item, the search continues in the left half of the list by moving the high
pointer. If the item is larger, the search moves to the right half by moving the low pointer. This process
continues, each time cutting the search area in half, until the item is found or there are no more items to
check. Binary search works fast because it reduces the number of possible places to look very quickly, but
it only works if the list is already sorted.
It works faster than a linear search algorithm. The binary search uses the divide and conquers principle.

Time Complexity:
• The worst-case complexity in binary search is O(n log n).
• The average case complexity in binary search is O(n log n)
• Best case complexity = O (1)
Space complexity:
In the worst case, the space complexity is O(1).
Working of Binary Search
Let us understand the working of a binary search algorithm with the help of an example.
Consider a sorted array having 10 elements as shown:

Suppose we wish to search 38 in the array.


Step 1: Find the middle element of the array.
index(Middle) = index(low) + index(high)/2.
Here, middle = (0+9)/2 = 4 i.e. the element at the 4th index i.e. 25.
Step 2: Compare 38 with the middle element. 38 > 25 So, discard the first half.
Step 3: Select the send half of the array. For the second half, Mid = low + high/2 as shown:
Mid=0+4/2=2

Step 4: Find the middle element of this smaller array which comes out to 32. Compare 38 with 32.
38 > 32 Thus, discard the first half of this array.
Step 5: Select the remaining half of the array by doing Mid=low + high/2 as shown:
Mid= 0+1/2=0

Finally, we have found 38 and thus the algorithm will halt here.
According to original list 38 is at index 8
Output: 8.
Advantages of Binary Search:
Binary search is faster than linear search, especially for large arrays.
More efficient than other searching algorithms with a similar time complexity, such as
interpolation search or exponential search.
Binary search is well-suited for searching large datasets that are stored in external memory, such
as on a hard drive or in the cloud.

Disadvantages of Binary Search:


The array should be sorted.
Binary search requires that the data structure being searched be stored in contiguous memory
locations.
Binary search requires that the elements of the array be comparable, meaning that they must be
able to be ordered.
Applications of Binary Search:
Searching in sorted arrays: Binary search is used to efficiently find an element in a sorted array.
Database queries: Binary search can be used to quickly locate records in a database table that is
sorted by a specific key.
Finding the closest match: Binary search can be used to find the closest value to a target value in a
sorted list.
Algorithm for Binary Search
Following are the steps of implementation that we will be following:

1.Start with the middle element:


• If the target value is equal to the middle element of the array, then return the index of the
middle element.
• If not, then compare the middle element with the target value,
• If the target value is greater than the number in the middle index, then pick the elements to
the right of the middle index, and start with Step 1.
• If the target value is less than the number in the middle index, then pick the elements to
the left of the middle index, and start with Step 1.
2.When a match is found, return the index of the element matched.
3.If no match is found, then return -1
Linear Search vs Binary Search
2.2 Sorting
Sorting refers to rearrangement of a given array or list of elements according to a comparison
operator on the elements. The comparison operator is used to decide the new order of elements in
the respective data structure.

When we have a large amount of data, it can be difficult to deal with it, especially when it is
arranged randomly. When this happens, sorting that data becomes crucial. It is necessary to sort
data in order to make searching easier.
Different Sorting Algorithms
There are many different techniques available for sorting, differentiated by their efficiency and
space requirements. Following are some sorting techniques
1.Bubble Sort
2.Selection Sort
3.Insertion Sort
4.Quick Sort
5.Merge Sort
Bubble Sort:
Bubble Sort is a simple algorithm which is used to sort a given set of n elements provided in
form of an array with n number of elements. Bubble Sort compares all the element one by one and
sort them based on their values.

If the given array has to be sorted in ascending order, then bubble sort will start by comparing the
first element of the array with the second element, if the first element is greater than the second
element, it will swap both the elements, and then move on to compare the second and the third
element, and so on.

If we have total n elements, then we need to repeat this process for n-1 times.
It is known as bubble sort, because with every complete iteration the largest element in the given
array, bubbles up towards the last place or the highest index, just like a water bubble rises up to
the water surface.
Sorting takes place by stepping through all the elements one-by-one and comparing it with the
adjacent element and swapping them if required.
Bubble Sort Algorithm

Step 1 − Check if the first element in the input array is greater than the next element in the array.
Step 2 − If it is greater, swap the two elements; otherwise move the pointer forward in the array.
Step 3 − Repeat Step 2 until we reach the end of the array.
Step 4 − Check if the elements are sorted; if not, repeat the same process (Step 1 to Step 3) from
the last element of the array to the first.
Step 5 − The final output achieved is the sorted array.
Working of Bubble sort Algorithm
Now, let's see the working of Bubble sort Algorithm.
To understand the working of bubble sort algorithm, let's take an unsorted array. We are taking a
short and accurate array, as we know the complexity of bubble sort is O(n2).

Let the elements of array are -

First Pass
Sorting will start from the initial two elements. Let compare them to check which is greater.

Here, 32 is greater than 13 (32 > 13), so it is already sorted. Now, compare 32 with 26.
Here, 10 is smaller than 35 that are not sorted. So, swapping is required. Now, we reach at the end
of the array. After first pass, the array will be -

Now, move to the second iteration.


Second Pass
The same process will be followed for second iteration.

Here, 10 is smaller than 32. So, swapping is required. After swapping, the array will be -
Here, 26 is smaller than 32. So, swapping is required. After swapping new array will look like -

Now, compare 32 and 35

Here, 35 is greater than 32. So, there is no swapping required as they are already sorted.
Now, the comparison will be in between 35 and 10.
Bubble sort complexity
The time complexity of Bubble Sort is O(n2).
The space complexity for Bubble Sort is O(1), because only a single additional memory space is
required i.e. for temp variable.

Advantages of Bubble Sort:


• Bubble sort is easy to understand and implement.
• It does not require any additional memory space.
• It is a stable sorting algorithm, meaning that elements with the same key value maintain their
relative order in the sorted output.
Disadvantages of Bubble Sort:
• Bubble sort has a time complexity of O(N2) which makes it very slow for large data sets.
• Bubble sort is a comparison-based sorting algorithm, which means that it requires a
comparison operator to determine the relative order of elements in the input data set. It can
limit the efficiency of the algorithm in certain cases.
Selection Sort
In selection sort, the smallest value among the unsorted elements of the array is selected in every
pass and inserted to its appropriate position into the array. It is also the simplest algorithm. It is an
in-place comparison sorting algorithm. In this algorithm, the array is divided into two parts, first is
sorted part, and another one is the unsorted part. Initially, the sorted part of the array is empty, and
unsorted part is the given array. Sorted part is placed at the left, while the unsorted part is placed
at the right.

In selection sort, the first smallest element is selected from the unsorted array and placed at the
first position. After that second smallest element is selected and placed in the second position. The
process continues until the array is entirely sorted.

The average and worst-case complexity of selection sort is O(n2), where n is the number of items.
Due to this, it is not suitable for large data sets.
Selection sort is generally used when -
A small array is to be sorted
Swapping cost doesn't matter
It is compulsory to check all elements
Selection Sort Algorithm
1.Start with the First Element: Begin with the first element in the list as the current position.

2.Find the Minimum: Scan the unsorted portion of the list to find the smallest element.

3.Swap: Swap the found smallest element with the element at the current position.

4.Move to the Next Position: Move to the next position in the list and repeat the process for the
remaining unsorted portion.

5.Repeat: Continue this process until the entire list is sorted.


Working of Selection sort Algorithm
Now, let's see the working of the Selection sort Algorithm.
To understand the working of the Selection sort algorithm, let's take an unsorted array. It will be
easier to understand the Selection sort via an example.
Let the elements of array are -

Now, for the first position in the sorted array, the entire array is to be scanned sequentially.
At present, 12 is stored at the first position, after searching the entire array, it is found that 8 is the
smallest value.
So, swap 12 with 8. After the first iteration, 8 will appear at the first position in the sorted array.

For the second position, where 29 is stored presently, we again sequentially scan the rest of the
items of unsorted array. After scanning, we find that 12 is the second lowest element in the array
that should be appeared at second position.

Now, swap 29 with 12. After the second iteration, 12 will appear at the second position in the
sorted array. So, after two iterations, the two smallest values are placed at the beginning in a
sorted way.
The same process is applied to the rest of the array elements. Now, we are showing a pictorial
representation of the entire sorting process.

Now, the array is completely sorted.


Selection sort complexity
1. Time Complexity
• Best Case Complexity - It occurs when there is no sorting required, i.e. the array is
already sorted. The best-case time complexity of selection sort is O(n2).
• Average Case Complexity - It occurs when the array elements are in jumbled order that
is not properly ascending and not properly descending. The average case time complexity
of selection sort is O(n2).
• Worst Case Complexity - It occurs when the array elements are required to be sorted in
reverse order. That means suppose you have to sort the array elements in ascending order,
but its elements are in descending order. The worst-case time complexity of selection sort
is O(n2).
2. Space Complexity
The space complexity of selection sort is O(1). It is because, in selection sort, an extra
variable is required for swapping.
Advantages of Selection Sort Algorithm
Simple and easy to understand.
Works well with small datasets.

Disadvantages of the Selection Sort Algorithm


Selection sort has a time complexity of O(n^2) in the worst and average case.
Does not work well on large datasets.
Does not preserve the relative order of items with equal keys which means it is not stable.
Insertion Sort
Insertion sort works similar to the sorting of playing cards in hands. It is assumed that the first
card is already sorted in the card game, and then we select an unsorted card. If the selected
unsorted card is greater than the first card, it will be placed at the right side; otherwise, it will be
placed at the left side. Similarly, all unsorted cards are taken and put in their exact place.

The same approach is applied in insertion sort. The idea behind the insertion sort is that first take
one element, iterate it through the sorted array. Although it is simple to use, it is not appropriate
for large data sets as the time complexity of insertion sort in the average case and worst case is
O(n2), where n is the number of items. Insertion sort is less efficient than the other sorting
algorithms like heap sort, quick sort, merge sort, etc.
Algorithm
The simple steps of achieving the insertion sort are listed as follows -
Step 1 - If the element is the first element, assume that it is already sorted. Return 1.
Step2 - Pick the next element, and store it separately in a key.
Step3 - Now, compare the key with all elements in the sorted array.
Step 4 - If the element in the sorted array is smaller than the current element, then move to
the next element. Else, shift greater elements in the array towards the right.
Step 5 - Insert the value.
Step 6 - Repeat until the array is sorted.
Working of Insertion sort Algorithm
Now, let's see the working of the insertion sort Algorithm.
To understand the working of the insertion sort algorithm, let's take an unsorted array. It
will be easier to understand the insertion sort via an example.
Let the elements of array are -

Initially, the first two elements are compared in insertion sort.

Here, 31 is greater than 12. That means both elements are already in ascending order. So,
for now, 12 is stored in a sorted sub-array.
Now, move to the next two elements and compare them.

Here, 25 is smaller than 31. So, 31 is not at correct position. Now, swap 31 with 25. Along
with swapping, insertion sort will also check it with all elements in the sorted array.
For now, the sorted array has only one element, i.e. 12. So, 25 is greater than 12. Hence, the
sorted array remains sorted after swapping.

Now, two elements in the sorted array are 12 and 25. Move forward to the next elements that
are 31 and 8.
Both 31 and 8 are not sorted. So, swap them.

After swapping, elements 25 and 8 are unsorted.

So, swap them.

Now, elements 12 and 8 are unsorted.


So, swap them too.

Now, the sorted array has three items that are 8, 12 and 25. Move to the next items that
are 31 and 32.

Hence, they are already sorted. Now, the sorted array includes 8, 12,
25 and 31.

Move to the next elements that are 32 and 17.


17 is smaller than 32. So, swap them.

Swapping makes 31 and 17 unsorted. So, swap them too.

Now, swapping makes 25 and 17 unsorted. So, perform swapping again.

Now, the array is completely sorted.


Insertion sort complexity
1. Time Complexity
• Best Case Complexity - It occurs when there is no sorting required, i.e. the array is
already sorted. The best-case time complexity of insertion sort is O(n).
• Average Case Complexity - It occurs when the array elements are in jumbled order that
is not properly ascending and not properly descending. The average case time complexity
of insertion sort is O(n2).
• Worst Case Complexity - It occurs when the array elements are required to be sorted in
reverse order. That means suppose you have to sort the array elements in ascending order,
but its elements are in descending order. The worst-case time complexity of insertion sort
is O(n2).
2. Space Complexity
The space complexity of insertion sort is O(1). It is because, in insertion sort, an extra
variable is required for swapping.
Advantages of Insertion Sort:
•Simple and easy to implement.
•Stable sorting algorithm.
•Efficient for small lists and nearly sorted lists.
•Space-efficient.

Disadvantages of Insertion Sort:


•Inefficient for large lists.
•Not as efficient as other sorting algorithms (e.g., merge sort, quick sort) for most cases.

Applications of Insertion Sort:


Insertion sort is commonly used in situations where:
•The list is small or nearly sorted.
•Simplicity and stability are important.
Quick Sort
Quicksort is based on a divide and conquer strategy. It works in the following steps:
1. It selects an element from within the array known as the pivot element.
2. Then it makes use of the partition algorithm to divide the array into two sub-arrays. One
sub-array has all the values less than the pivot element. The other sub-array has all the
values higher than the pivot element.
3. In the next step, the quicksort algorithm calls itself recursively to sort these two sub-
arrays.
4. Once the sorting is done, we can combine both the sub-arrays into a single sorted array.
The most important part of quicksort is the partition algorithm. The partition algorithm puts
the element into either of the two subarrays depending on the pivot point. We can choose
pivot point in many ways:
• Take the first element as the pivot point
• Take the last element of the array as the pivot point
• Take the middle element of the array as the pivot element.
• Take random element as the pivot element in every recursive call
Partition Algorithm
Step 1: Choose the highest index value i.e. the last element of the array as a pivot point
Step 2: Point to the 1st and last index of the array using two variables.
Step 3: Left points to the low index and Right points to the high
Step 4: while Array[Left] < pivot Move Right
Step 5: while Array[Right] > pivot Move Left
Step 6: If no match found in step 5 and step 6, swap Left and Right
Step 7: If Left ≥ Right, their meeting point is the new pivot
Quicksort Algorithm:
Step 1 − Array[Right] = pivot
Step 2 − Apply partition algorithm over data items using pivot element
Step 3 − quicksort(left of pivot)
Step 4 − quicksort(right of pivot)
Working of Quick Sort Algorithm
Now, let's see the working of the Quicksort Algorithm.
To understand the working of quick sort, let's take an unsorted array. It will make the
concept more clear and understandable.
Let the elements of array are -

In the given array, we consider the leftmost element as pivot. So, in this case, a[left] = 24,
a[right] = 27 and a[pivot] = 24.
Since, pivot is at left, so algorithm starts from right and move towards left.
Now, a[pivot] < a[right], so algorithm moves forward one position towards left, i.e. -

Now, a[left] = 24, a[right] = 19, and a[pivot] = 24.


Because, a[pivot] > a[right], so, algorithm will swap a[pivot] with a[right], and pivot
moves to right, as -
Now, a[left] = 19, a[right] = 24, and a[pivot] = 24. Since, pivot is at right, so algorithm starts
from left and moves to right.
As a[pivot] > a[left], so algorithm moves one position to right as -

Now, a[left] = 9, a[right] = 24, and a[pivot] = 24. As a[pivot] > a[left], so algorithm
moves one position to right as -
Now, a[left] = 29, a[right] = 24, and a[pivot] = 24. As a[pivot] < a[left], so, swap a[pivot]
and a[left], now pivot is at left, i.e.

Since, pivot is at left, so algorithm starts from right, and move to left. Now, a[left] = 24,
a[right] = 29, and a[pivot] = 24. As a[pivot] < a[right], so algorithm moves one position to
left, as -
Now, a[pivot] = 24, a[left] = 24, and a[right] = 14. As a[pivot] > a[right], so, swap a[pivot]
and a[right], now pivot is at right, i.e. -

Now, a[pivot] = 24, a[left] = 14, and a[right] = 24. Pivot is at right, so the algorithm starts
from left and move to right.
Now, a[pivot] = 24, a[left] = 24, and a[right] = 24. So, pivot, left and right are pointing the
same element. It represents the termination of procedure.
Element 24, which is the pivot element is placed at its exact position.
Elements that are right side of element 24 are greater than it, and the elements that are left
side of element 24 are smaller than it.

Now, in a similar manner, quick sort algorithm is separately applied to the left and right
sub-arrays. After sorting gets done, the array will be -
Quicksort complexity
1. Time Complexity
• Best Case Complexity - In Quicksort, the best-case occurs when the pivot element is the
middle element or near to the middle element. The best-case time complexity of quicksort
is O(n*logn).
• Average Case Complexity - It occurs when the array elements are in jumbled order that
is not properly ascending and not properly descending. The average case time complexity
of quicksort is O(n*logn).
• Worst Case Complexity - In quick sort, worst case occurs when the pivot element is
either greatest or smallest element. Suppose, if the pivot element is always the last element
of the array, the worst case would occur when the given array is sorted already in ascending
or descending order. The worst-case time complexity of quicksort is O(n2).
2. Space Complexity
The space complexity of quicksort is O(n*logn).
Advantages of Quick Sort:
•It is a divide-and-conquer algorithm that makes it easier to solve problems.
•It is efficient on large data sets.
•It has a low overhead, as it only requires a small amount of memory to function.

Disadvantages of Quick Sort:


•It has a worst-case time complexity of O(N 2 ), which occurs when the pivot is chosen poorly.
•It is not a good choice for small data sets.
•It is not a stable sort, meaning that if two elements have the same key, their relative order will not
be preserved in the sorted output in case of quick sort, because here we are swapping elements
according to the pivot’s position (without considering their original positions).
Merge sort
Merge sort is similar to the quick sort algorithm as it uses the divide and conquer approach to sort
the elements. It is one of the most popular and efficient sorting algorithm. It divides the given list
into two equal halves, calls itself for the two halves and then merges the two sorted halves. We
have to define the merge() function to perform the merging.

The sub-lists are divided again and again into halves until the list cannot be divided further. Then
we combine the pair of one element lists into two-element lists, sorting them in the process. The
sorted two-element pairs is merged into the four-element lists, and so on until we get the sorted
list.
How does Merge Sort work?
Merge sort is a popular sorting algorithm known for its efficiency and stability. It follows
the divide-and-conquer approach to sort a given array of elements.
Here’s a step-by-step explanation of how merge sort works:
1. Divide the list or array recursively into two halves until it can no more be divided.
2. Each subarray is sorted individually using the merge sort algorithm.
3. The sorted subarrays are merged back together in sorted order. The process continues until all
elements from both subarrays have been merged.
Working of Merge sort Algorithm
Now, let's see the working of merge sort Algorithm.
To understand the working of the merge sort algorithm, let's take an unsorted array. It will be
easier to understand the merge sort via an example.
Let the elements of array are -

According to the merge sort, first divide the given array into two equal halves. Merge sort keeps
dividing the list into equal parts until it cannot be further divided.
As there are eight elements in the given array, so it is divided into two arrays of size 4.
Now, again divide these two arrays into halves. As they are of size 4, so divide them into new
arrays of size 2.

Now, again divide these arrays to get the atomic value that cannot be further divided.

Now, combine them in the same manner they were broken.


In combining, first compare the element of each array and then combine them into another array
in sorted order.
So, first compare 12 and 31, both are in sorted positions. Then compare 25 and 8, and in the list of
two values, put 8 first followed by 25. Then compare 32 and 17, sort them and put 17 first
followed by 32. After that, compare 40 and 42, and place them sequentially.
In the next iteration of combining, now compare the arrays with two data values and merge them
into an array of found values in sorted order.

Now, there is a final merging of the arrays. After the final merging of above arrays, the array will
look like -

Now, the array is completely sorted.


Complexity Analysis of Merge Sort:
Time Complexity:
• O(n log n), When the array is already sorted or nearly sorted.
• O(n log n), When the array is randomly ordered.
• O(n log n), When the array is sorted in reverse order.

Space Complexity: O(n), Additional space is required for the temporary array used during
merging.

Applications of Merge Sort:


Sorting large datasets
External sorting (when the dataset is too large to fit in memory)
Inversion counting (counting the number of inversions in an array)
Finding the median of an array
Advantages of Merge Sort:
• Stability : Merge sort is a stable sorting algorithm, which means it maintains the relative order
of equal elements in the input array.
•Guaranteed worst-case performance: Merge sort has a worst-case time complexity of O(N
logN) , which means it performs well even on large datasets.
•Simple to implement: The divide-and-conquer approach is straightforward.

Disadvantages of Merge Sort:


• Space complexity: Merge sort requires additional memory to store the merged sub-arrays
during the sorting process.
•Not in-place: Merge sort is not an in-place sorting algorithm, which means it requires additional
memory to store the sorted data. This can be a disadvantage in applications where memory usage
is a concern.

You might also like