Sorting Techniques
Sorting Techniques
Sure, I can help you prepare a comprehensive document on common sorting techniques. We'll start with a summary table comparing various
sorting algorithms, followed by a brief description of each algorithm, and then provide the code in both Java and Python with explanations and
comments.
Summary Table
Worst Case Data
Sorting Average Case
Time Stable Requirement Other Characteristics
Algorithm Time Complexity
Complexity (Online/Offline)
Bubble
O(n^2) O(n^2) Yes Offline Simple but inefficient
Sort
Insertion Efficient for small datasets or
O(n^2) O(n^2) Yes Online
Sort nearly sorted data
Selection
O(n^2) O(n^2) No Offline Simple but inefficient
Sort
Quick Sort O(n log n) O(n^2) No Offline Fast, in-place, but unstable
In-place, not stable, uses heap
Heap Sort O(n log n) O(n log n) No Offline
data structure
Merge
O(n log n) O(n log n) Yes Offline Stable, requires extra space
Sort
Only for integers, uses extra
Counting
O(n + k) O(n + k) Yes Offline space proportional to range of
Sort
input
Descriptions
Bubble Sort
Bubble Sort is a simple sorting algorithm that repeatedly steps through the list, compares adjacent elements, and swaps them if they are in the
wrong order. This process is repeated until the list is sorted. It is known for its simplicity but is highly inefficient for large lists.
Insertion Sort
Insertion Sort works by building a sorted portion of the list one item at a time. It takes each element from the input list and inserts it into the correct
position in the already sorted part of the list. It is efficient for small datasets or lists that are already partially sorted.
Selection Sort
Selection Sort divides the list into a sorted and an unsorted region. It repeatedly selects the smallest (or largest) element from the unsorted region
and moves it to the end of the sorted region. Despite its simplicity, it is inefficient for large lists.
Quick Sort
Quick Sort is a divide-and-conquer algorithm that selects a 'pivot' element and partitions the list into elements less than the pivot and elements
greater than the pivot. The process is then recursively applied to the partitions. It is fast and efficient but not stable.
Heap Sort
Heap Sort uses a binary heap data structure to sort elements. It first builds a max-heap and then repeatedly extracts the maximum element to
build the sorted list. It is an efficient in-place sorting algorithm but not stable.
Merge Sort
Merge Sort is a divide-and-conquer algorithm that divides the list into equal halves, recursively sorts them, and then merges the sorted halves. It is
stable and has consistent performance but requires additional space for the merging process.
Counting Sort
Counting Sort is a non-comparative sorting algorithm that works by counting the occurrences of each unique element in the input list. It then uses
this count to determine the positions of each element in the sorted output. It is efficient for sorting integers but requires extra space proportional to
the range of the input.
Code Implementations
Bubble Sort
Java:
Python:
def bubble_sort(arr):
n = len(arr)
for i in range(n):
swapped = False
for j in range(0, n - i - 1):
if arr[j] > arr[j + 1]:
# Swap arr[j] and arr[j + 1]
arr[j], arr[j + 1] = arr[j + 1], arr[j]
swapped = True
# If no elements were swapped, the array is already sorted
if not swapped:
break
Insertion Sort
Java:
public class InsertionSort {
public static void insertionSort(int[] array) {
for (int i = 1; i < array.length; i++) {
int key = array[i];
int j = i - 1;
// Move elements of array[0..i-1], that are greater than key, to one position ahead
// of their current position
while (j >= 0 && array[j] > key) {
array[j + 1] = array[j];
j = j - 1;
}
array[j + 1] = key;
}
}
}
Python:
def insertion_sort(arr):
for i in range(1, len(arr)):
key = arr[i]
j = i - 1
# Move elements of arr[0..i-1], that are greater than key, to one position ahead
# of their current position
while j >= 0 and key < arr[j]:
arr[j + 1] = arr[j]
j -= 1
arr[j + 1] = key
Selection Sort
Java:
public class SelectionSort {
public static void selectionSort(int[] array) {
int n = array.length;
for (int i = 0; i < n - 1; i++) {
// Find the minimum element in unsorted array
int minIndex = i;
for (int j = i + 1; j < n; j++) {
if (array[j] < array[minIndex]) {
minIndex = j;
}
}
// Swap the found minimum element with the first element
int temp = array[minIndex];
array[minIndex] = array[i];
array[i] = temp;
}
}
}
Python:
def selection_sort(arr):
for i in range(len(arr)):
# Find the minimum element in unsorted array
min_idx = i
for j in range(i + 1, len(arr)):
if arr[j] < arr[min_idx]:
min_idx = j
# Swap the found minimum element with the first element
arr[i], arr[min_idx] = arr[min_idx], arr[i]
Quick Sort
Java:
public class QuickSort {
public static void quickSort(int[] array, int low, int high) {
if (low < high) {
// pi is partitioning index, array[pi] is now at right place
int pi = partition(array, low, high);
// Recursively sort elements before partition and after partition
quickSort(array, low, pi - 1);
quickSort(array, pi + 1, high);
}
}
Python:
def quick_sort(arr, low, high):
if low < high:
# pi is partitioning index, arr[pi] is now at right place
pi = partition(arr, low, high)
# Recursively sort elements before partition and after partition
quick_sort(arr, low, pi - 1)
quick_sort(arr, pi + 1, high)
The Collections.sort() method in Java uses the Timsort algorithm, which is a hybrid sorting algorithm derived from merge sort and insertion
sort. It is designed to perform well on many kinds of real-world data, providing the following characteristics:
The sort() method in Python's list and the sorted() function also use Timsort. This algorithm is a hybrid sorting algorithm derived from merge
sort and insertion sort, designed to perform well on many kinds of real-world data. It provides the following characteristics:
Both the Java Collections.sort() and Python sort() methods are implemented with Timsort, making them highly efficient and stable for a
wide range of sorting tasks.
Merge Sort
Java:
public class MergeSort {
public static void mergeSort(int[] array, int left, int right) {
if (left < right) {
int mid = (left + right) / 2;
private static void merge(int[] array, int left, int mid, int right) {
int n1 = mid - left + 1;
int n2 = right - mid;
int i = 0, j = 0;
int k = left;
while (i < n1 && j < n2) {
if (L[i] <= R[j]) {
array[k] = L[i];
i++;
} else {
array[k] = R[j];
j++;
}
k++;
}
Python:
def merge_sort(arr):
if len(arr) > 1:
mid = len(arr) // 2 # Finding the mid of the array
L = arr[:mid] # Dividing the elements into 2 halves
R = arr[mid:]
i = j = k = 0
Counting Sort
Java:
public class CountingSort {
public static void countingSort(int[] array) {
int max = getMax(array);
int[] count = new int[max + 1];
int[] output = new int[array.length];
// Change count[i] so that count[i] now contains actual position of this character in output array
for (int i = 1; i <= max; i++) {
count[i] += count[i - 1];
}
// Copy the output array to array, so that array now contains sorted characters
System.arraycopy(output, 0, array, 0, array.length);
}
Python:
def counting_sort(arr):
max_val = max(arr)
count = [0] * (max_val + 1)
output = [0] * len(arr)
# Change count[i] so that count[i] now contains actual position of this character in output array
for i in range(1, len(count)):
count[i] += count[i - 1]
# Copy the output array to arr, so that arr now contains sorted characters
for i in range(len(arr)):
arr[i] = output[i]
Heap Sort
Java:
public class HeapSort {
public static void heapSort(int[] array) {
int n = array.length;
Python:
def heap_sort(arr):
n = len(arr)
# Build a maxheap.
for i in range(n // 2 - 1, -1, -1):
heapify(arr, n, i)
Descriptions
Bubble Sort: A simple sorting algorithm that repeatedly steps through the
list, compares adjacent elements, and swaps them if they are in the wrong order. It is easy to understand but highly inefficient for large lists.
Insertion Sort: Works by building a sorted portion of the list one item at a time. It is efficient for small datasets or lists that are already partially
sorted.
Selection Sort: Divides the list into a sorted and an unsorted region. Repeatedly selects the smallest (or largest) element from the unsorted
region and moves it to the end of the sorted region. Simple but inefficient for large lists.
Quick Sort: A divide-and-conquer algorithm that selects a 'pivot' element and partitions the list into elements less than the pivot and elements
greater than the pivot. Recursively applied to partitions. Fast and efficient but not stable.
Heap Sort: Uses a binary heap data structure to sort elements. Builds a max-heap and repeatedly extracts the maximum element to build the
sorted list. Efficient and in-place but not stable.
Merge Sort: A divide-and-conquer algorithm that divides the list into equal halves, recursively sorts them, and then merges the sorted halves.
Stable and consistent performance but requires additional space for merging.
Counting Sort: A non-comparative sorting algorithm that works by counting the occurrences of each unique element in the input list and uses this
count to determine the positions of each element in the sorted output. Efficient for sorting integers but requires extra space proportional to the
range of the input.
This document covers the summary table, explanations, and code implementations for each sorting algorithm, providing a solid foundation for
understanding common sorting techniques in computer science.