Data Structures (Sorting)
Data Structures (Sorting)
TOPICS COVERED-
▪ Introduction to Sorting
▪ Quick Sort
▪ Merge Sort
▪ Counting Sort
▪ Heap Sort
▪ sort() Function in C++ STL
▪ Sorting using Built-in methods in Java
Introduction to Sorting-
Sorting any sequence means to arrange the elements of that sequence according to
some specific criterion.
For Example, the array arr[] = {5, 4, 2, 1, 3} after sorting in increasing order will be:
arr[] = {1, 2, 3, 4, 5}. The same array after sorting in descending order will be: arr[] =
{5, 4, 3, 2, 1}.
In-Place Sorting: An in-place sorting algorithm uses constant extra space for
producing the output (modifies the given array only). It sorts the list only by
modifying the order of the elements within the list.
In this tutorial, we will see three of such in-place sorting algorithms, namely:
• Insertion Sort
• Selection Sort
• Bubble Sort
Insertion Sort
Insertion Sort is an In-Place sorting algorithm. This algorithm works in a similar way
of sorting a deck of playing cards.
The idea is to start iterating from the second element of array till last element and
for every element insert at its correct position in the subarray before it.
In the below image you can see, how the array [4, 3, 2, 10, 12, 1, 5, 6] is being
sorted in increasing order following the insertion sort algorithm.
Algorithm:
Another Example:
arr[] = {12, 11, 13, 5, 6}
Let us loop for i = 1 (second element of the array) to 4 (Size of input array - 1).
Function Implementation:
int i, key, j;
key = arr[i];
j = i-1;
arr[j+1] = arr[j];
j = j-1;
arr[j+1] = key;
Bubble Sort-
Bubble Sort is also an in-place sorting algorithm. This is the simplest sorting
algorithm and it works on the principle that:
In one iteration if we swap all adjacent elements of an array such that after
swap the first element is less than the second element then at the end of the
iteration, the first element of the array will be the minimum element.
Bubble-Sort algorithm simply repeats the above steps N-1 times, where N is the
size of the array.
Function Implementation:
// A function to implement bubble sort
int i, j;
swap(&arr[j], &arr[j+1]);
Note: The above solution can be further optimized by keeping a flag to check if the
array is already sorted in the first pass itself and to stop any further iteration.
Selection Sort
The selection sort algorithm sorts an array by repeatedly finding the minimum
element (considering ascending order) from unsorted part and putting it at the
beginning. The algorithm maintains two subarrays in a given array.
arr[] = 64 25 12 22 11.
Function Implementation:
void selectionSort(int arr[], int n)
int i, j, min_idx;
min_idx = i;
min_idx = j;
swap(&arr[min_idx], &arr[i]);
Quick Sort-
QuickSort is a Divide and Conquer algorithm. It picks an element as pivot and
partitions the given array around the picked pivot. There are many different versions
of quickSort that pick pivot in different ways.
The key process in quickSort is partition(). Target of partitions is, given an array and
an element x of array as pivot, put x at its correct position in sorted array and put all
smaller elements (smaller than x) before x, and put all greater elements (greater
than x) after x. All this should be done in linear time.
Partition Algorithm:
There can be many ways to do partition, following pseudo code adopts the method
given in CLRS book. The logic is simple, we start from the leftmost element and
keep track of index of smaller (or equal to) elements as i. While traversing, if we
find a smaller element, we swap current element with arr[i]. Otherwise we ignore
current element.
Illustration of partition() :
Indexes: 0 1 2 3 4 5 6
i = 0
arr[] = {10, 80, 30, 90, 40, 50, 70} // No change as i and j
// are same
i = 1
arr[] = {10, 30, 80, 90, 40, 50, 70} // We swap 80 and 30
i = 2
arr[] = {10, 30, 40, 90, 80, 50, 70} // 80 and 40 Swapped
j = 5 : Since arr[j] <= pivot, do i++ and swap arr[i] with arr[j]
i = 3
arr[] = {10, 30, 40, 50, 80, 90, 70} // 90 and 50 Swapped
arr[] = {10, 30, 40, 50, 70, 90, 80} // 80 and 70 Swapped
it.
Implementation:
of pivot */
// equal to pivot
swap(&arr[i], &arr[j]);
return (i + 1);
at right place */
quickSort(arr, pi + 1, high);
Analysis of QuickSort
Worst Case: The worst case occurs when the partition process always picks greatest or
smallest element as pivot. If we consider above partition strategy where last element is
always picked as pivot, the worst case would occur when the array is already sorted in
increasing or decreasing order. Following is recurrence for worst case.
Best Case: The best case occurs when the partition process always picks the middle
element as pivot. Following is recurrence for best case.
Although the worst case time complexity of QuickSort is O(n2) which is more than many
other sorting algorithms like Merge Sort and Heap Sort, QuickSort is faster in practice,
because its inner loop can be efficiently implemented on most architectures, and in most
real-world data. QuickSort can be implemented in different ways by changing the choice of
pivot, so that the worst case rarely occurs for a given type of data. However, merge sort is
generally considered better when data is huge and stored in external storage.
Merge Sort-
Merge Sort is a Divide and Conquer algorithm. It divides the input array in two halves, calls
itself for the two halves and then merges the two sorted halves. The merge() function is
used for merging two halves. The merge(arr, l, m, r) is key process that assumes that
arr[l..m] and arr[m+1..r] are sorted and merges the two sorted sub-arrays into one in a
sorted manner. See following implementation for details:
MergeSort(arr[], l, r)
If r > l
1. Find the middle point to divide the array into two halves:
middle m = (l+r)/2
2. Call mergeSort for first half:
Call mergeSort(arr, l, m)
3. Call mergeSort for second half:
Call mergeSort(arr, m+1, r)
4. Merge the two halves sorted in step 2 and 3:
Call merge(arr, l, m, r)
The following diagram from wikipedia shows the complete merge sort process for an
example array {38, 27, 43, 3, 9, 82, 10}. If we take a closer look at the diagram, we can see
that the array is recursively divided in two halves till the size becomes 1. Once the size
becomes 1, the merge processes comes into action and starts merging arrays back till the
complete array is merged.
Implementation:
// Merges two subarrays of arr[]. }
int i, j, k; {
int n2 = r - m; i++;
k++;
are any */
/* Copy data to temp arrays L[] and R[] */ while (j < n2)
j = 0; // Initial index of second subarray /* l is for left index and r is right index of the
while (i < n1 && j < n2) void mergeSort(int arr[], int l, int r)
{ {
{ {
} int m = l+(r-l)/2;
{ mergeSort(arr, l, m);
} }
k++; }
Time Complexity: Sorting arrays on different machines. Merge Sort is a recursive algorithm
and time complexity can be expressed as following recurrence relation.
T(n) = 2T(n/2) + Θ(n)
The above recurrence can be solved either using Recurrence Tree method or Master
method. It falls in case II of Master Method and solution of the recurrence is Θ(nLogn).
Time complexity of Merge Sort is Θ(nLogn) in all 3 cases (worst, average and best) as
merge sort always divides the array in two halves and take linear time to merge two
halves.
Counting Sort-
It is a sorting technique based on keys between a specific range. It works by counting the
number of objects having distinct key values (kind of hashing). Then doing some arithmetic
to calculate the position of each object in the output sequence.
2) Modify the count array such that each element at each index
stores the sum of previous counts.
Index: 0 1 2 3 4 5 6 7 8 9
Count: 0 2 4 4 5 6 6 7 7 7
Implementation:
// The main function that sort the given string arr[] in // position of this character in output array
// The output character array that will have sorted arr // Build the output character array
memset(count, 0, sizeof(count));
Time Complexity: O(N + K) where N is the number of elements in input array and K is the
range of input.
Auxiliary Space: O(N + K)
The problem with the previous counting sort was that it could not sort the elements if we
have negative numbers in the array because there are no negative array indices. So what
we can do is, we can find the minimum element and store count of that minimum element
at zero index.
Implementation:
count[arr[i]-min]--; }
Important Points:
1. Counting sort is efficient if the range of input data is not significantly greater
than the number of objects to be sorted. Consider the situation where the
input sequence is between range 1 to 10K and the data is 10, 5, 10K, 5K.
2. It is not a comparison based sorting. It's running time complexity is O(n) with
space proportional to the range of data.
3. It is often used as a sub-routine to another sorting algorithm like radix sort.
4. Counting sort uses a partial hashing to count the occurrence of the data
object in O(1).
5. Counting sort can be extended to work for negative inputs also.
Heap Sort-
Heap sort is a comparison based sorting technique based on Binary Heap data structure. It
is similar to selection sort where we first find the maximum element and place the
maximum element at the end. We repeat the same process for remaining elements.
Let us first define a Complete Binary Tree. A complete binary tree is a binary tree in which
every level, except possibly the last, is completely filled, and all nodes are as far left as
possible (SourceWikipedia).
A Binary Heap is a Complete Binary Tree where items are stored in a special order such
that value in a parent node is greater(or smaller) than the values in its two children nodes.
The former is called as max heap and the latter is called min heap. The heap can be
represented by binary tree or array.
Array based representation for Binary Heap: Since a Binary Heap is a Complete Binary
Tree, it can be easily represented as array and array based representation is space efficient.
If the parent node is stored at index I, the left child can be calculated by 2 * I + 1 and right
child by 2 * I + 2 (assuming the indexing starts at 0).
Heapify procedure can be applied to a node only if its children nodes are heapified. So the
heapification must be performed in the bottom up order.
Lets understand with the help of an example:
int largest = i; // Initialize largest as root if (l < n && arr[l] > arr[largest])
// If right child is larger than largest so far // Build heap (rearrange array)
{ {
swap(arr[0], arr[i]);
} heapify(arr, i, 0);
} }
Important Notes:
Heap sort algorithm has limited use because Quicksort and Mergesort are better in practice.
Nevertheless, the Heap data structure itself is enormously used.
sort(arr, arr+n);
sort(vec.begin(), vec.end());
#include <bits/stdc++.h>
int main()
{ sort(vec.begin(), vec.end());
// Sorting Array
int arr[] = {1, 5, 8, 9, 6, 7, 3, 4, 2, 0}; cout << "\nVector after sorting is : \n";
sort(arr, arr+n);
return 0;
Output :
#include <bits/stdc++.h>
int n = sizeof(arr)/sizeof(arr[0]); }
Output:
Array after sorting :
9 8 7 6 5 4 3 2 1 0
#include<bits/stdc++.h> };
// An interval has start time and end time bool compareInterval(Interval i1, Interval i2)
struct Interval {
int n = sizeof(arr)/sizeof(arr[0]);
return 0;
// start time
Output:
Syntax:
public static void sort(int[] arr, int from_Index, int to_Index)
Below are different ways of using the sort() method of Arrays class in Java to sort
arrays differently.
// A sample Java program to sort an array of integers // Our arr contains 8 elements
// using Arrays.sort(). It by default sorts in int[] arr = {13, 7, 6, 45, 21, 9, 101, 102};
// ascending order
{ Arrays.toString(arr));
{ }
• Output:
// A sample Java program to sort a subarray // Sort subarray from index 1 to 4, i.e.,
{ Arrays.toString(arr));
•
Output:
import java.util.Arrays; {
{ Arrays.sort(arr, Collections.reverseOrder());
• Output:
// in ascending and descending orders using Arrays.sort(). // Sorts arr[] in ascending order
Arrays.toString(arr));
"quiz.geeksforgeeks.org", Arrays.toString(arr));
"code.geeksforgeeks.org" }
}; }
• Output:
Modified arr[] :
[code 1="practice.geeksforgeeks.org," 2="quiz.geeksforgeeks.org"
language=".geeksforgeeks.org,"][/code]
Modified arr[] :
[quiz.geeksforgeeks.org, practice.geeksforgeeks.org, code.geeksfo
rgeeks.org]
We can also sort an array according to user defined criteria: We use Comparator
interface for this purpose. Below is an example.
// interface }
import java.util.*; }
{ {
•
Output:
3 12
5 7
10 20
Collections.sort()
The Collections.sort() method is present in Collections class. It is used to sort the elements
present in the specified list of Collection in ascending order.
It works similar to the Arrays.sort() method but it is better as it can sort the elements of
Array as well as any collection interfaces like a linked list, queue and many more.
Syntax:
Example:
{
// Let us print the sorted list
// Create a list of strings
System.out.println("List after the use of" +
ArrayList<String> al = new ArrayList<String>();
" Collection.sort() :\n" + al);
al.add("Geeks For Geeks");
}
al.add("Friends");
}
al.add("Dear");
• Output:
• List after the use of Collection.sort() :
Collections.sort(al, Collections.reverseOrder()); }
• Output:
• List after the use of Collection.sort() :
Sorting an ArrayList according to user defined criteria: We can use Comparator Interface
for this purpose
import java.lang.*; }
import java.io.*; }
{ // roll number
// Constructor }
{ class Main
this.rollno = rollno; {
this.address = address; {
for (int i=0; i<ar.size(); i++) for (int i=0; i<ar.size(); i++)
System.out.println(ar.get(i)); System.out.println(ar.get(i));
}}
Output :
• Unsorted
• Sorted by rollno
HIMANSHU KUMAR(LINKEDIN)
https://www.linkedin.com/in/himanshukumarmahuri
CREDITS- INTERNET
DISCLOSURE- ALL THE DATA AND IMAGES ARE TAKEN FROM GOOGLE AND INTERNET.