Fading Coder

One Final Commit for the Last Sprint

Home > Tech > Content

Fundamental Sorting Algorithms for Integer Arrays

Tech May 19 2

1. Selection Sort

The algorithm divides the input list into two parts: a sorted sublist built up from left to right, and the remaining unsorted items. During each iteration, the smallest element from the unsorted section is identified and swapped into its correct position at the end of the sorted sublist.

  • Time Complexity: O(N^2) where N is the array length.
  • Space Complexity: O(1) using only a few temporary variables.
public class ArraySorter {
    public int[] sort(int[] data) {
        int size = data.length;
        for (int curr = 0; curr < size - 1; curr++) {
            int smallestIdx = curr;
            for (int next = curr + 1; next < size; next++) {
                if (data[next] < data[smallestIdx]) {
                    smallestIdx = next;
                }
            }
            exchange(data, curr, smallestIdx);
        }
        return data;
    }

    private void exchange(int[] data, int a, int b) {
        int tmp = data[a];
        data[a] = data[b];
        data[b] = tmp;
    }
}

2. Insertion Sort

This stable sorting algorithm builds the final sorted array one item at a time. It is particularly efficient for datasets that are already substantially sorted.

public class ArraySorter {
    public int[] sort(int[] data) {
        int length = data.length;
        for (int i = 1; i < length; i++) {
            int key = data[i];
            int shiftIdx = i;
            while (shiftIdx > 0 && data[shiftIdx - 1] > key) {
                data[shiftIdx] = data[shiftIdx - 1];
                shiftIdx--;
            }
            data[shiftIdx] = key;
        }
        return data;
    }
}

3. Merge Sort

A divide-and-conquer algorithm that splits the array into halves, recursively sorts them, and finally merges the sorted halves back together.

public class MergeArraySorter {
    private int[] aux;

    public int[] sort(int[] data) {
        aux = new int[data.length];
        divideAndMerge(data, 0, data.length - 1);
        return data;
    }

    private void divideAndMerge(int[] data, int start, int end) {
        if (start >= end) {
            return;
        }
        int center = start + (end - start) / 2;
        divideAndMerge(data, start, center);
        divideAndMerge(data, center + 1, end);
        combine(data, start, center, end);
    }

    private void combine(int[] data, int start, int center, int end) {
        int left = start, right = center + 1, k = 0;
        while (left <= center && right <= end) {
            if (data[left] <= data[right]) {
                aux[k++] = data[left++];
            } else {
                aux[k++] = data[right++];
            }
        }
        while (left <= center) {
            aux[k++] = data[left++];
        }
        while (right <= end) {
            aux[k++] = data[right++];
        }
        for (int p = 0; p < end - start + 1; p++) {
            data[start + p] = aux[p];
        }
    }
}

4. Heap Sort

Heap sort optimizes selection sort by using a max-heap data structure to efficiently find the maximum element in O(log N) time instead of O(N). The parent of node i is (i-1)/2, the left child is (2*i)+1, and the right child is (2*i)+2.

  • Time Complexity: O(N log N) where N is the array length.
  • Space Complexity: O(1).
public class HeapArraySorter {
    public int[] sort(int[] data) {
        int lastIdx = data.length - 1;
        constructMaxHeap(data, lastIdx);
        for (int i = lastIdx; i > 0; i--) {
            exchange(data, 0, i);
            sink(data, 0, i - 1);
        }
        return data;
    }

    private void constructMaxHeap(int[] data, int lastIdx) {
        for (int node = (lastIdx - 1) / 2; node >= 0; node--) {
            sink(data, node, lastIdx);
        }
    }

    private void sink(int[] data, int node, int limit) {
        int leftChild = node * 2 + 1;
        if (leftChild > limit) return;
        int rightChild = leftChild + 1;
        int largest = node;
        if (leftChild <= limit && data[leftChild] > data[largest]) {
            largest = leftChild;
        }
        if (rightChild <= limit && data[rightChild] > data[largest]) {
            largest = rightChild;
        }
        if (largest != node) {
            exchange(data, node, largest);
            sink(data, largest, limit);
        }
    }

    private void exchange(int[] data, int a, int b) {
        int tmp = data[a];
        data[a] = data[b];
        data[b] = tmp;
    }
}

5. Quick Sort

Quick sort selects a 'pivot' element and partitions the array around it, placing the pivot in its final sorted position. It then recursively sorts the sub-arrays on either side. Randomization is utilized to avoid the worst-case O(N^2) scenario on already sorted inputs.

  • Time Complexity: O(N log N) on average; O(N^2) in the worst case.
  • Space Complexity: O(log N) for the recursion stack.
public class QuickArraySorter {
    public int[] sort(int[] data) {
        quickSort(data, 0, data.length - 1);
        return data;
    }

    private void quickSort(int[] data, int low, int high) {
        if (low >= high) return;
        int pivotIdx = randomPartition(data, low, high);
        quickSort(data, low, pivotIdx - 1);
        quickSort(data, pivotIdx + 1, high);
    }

    private int randomPartition(int[] data, int low, int high) {
        exchange(data, high, new Random().nextInt(high - low + 1) + low);
        int boundary = low;
        for (int curr = low; curr < high; curr++) {
            if (data[curr] <= data[high]) {
                exchange(data, boundary, curr);
                boundary++;
            }
        }
        exchange(data, boundary, high);
        return boundary;
    }

    private void exchange(int[] data, int a, int b) {
        int tmp = data[a];
        data[a] = data[b];
        data[b] = tmp;
    }
}

Hoare Partition Optimization

Using collision pointers (Hoare partition scheme) can accelerate the partitioning process by moving both ends towards the center simultaneously.

public class HoareQuickSorter {
    public int[] sort(int[] data) {
        quickSort(data, 0, data.length - 1);
        return data;
    }

    private void quickSort(int[] data, int low, int high) {
        if (low >= high) return;
        int pivotIdx = hoarePartition(data, low, high);
        quickSort(data, low, pivotIdx - 1);
        quickSort(data, pivotIdx + 1, high);
    }

    private int hoarePartition(int[] data, int low, int high) {
        exchange(data, high, new Random().nextInt(high - low + 1) + low);
        int leftPtr = low, rightPtr = high - 1;
        while (leftPtr <= rightPtr) {
            while (leftPtr < high && data[leftPtr] < data[high]) leftPtr++;
            while (rightPtr >= low && data[rightPtr] > data[high]) rightPtr--;
            if (leftPtr >= rightPtr) break;
            exchange(data, leftPtr, rightPtr);
            leftPtr++;
            rightPtr--;
        }
        exchange(data, leftPtr, high);
        return leftPtr;
    }

    private void exchange(int[] data, int a, int b) {
        int tmp = data[a];
        data[a] = data[b];
        data[b] = tmp;
    }
}

Related Articles

Understanding Strong and Weak References in Java

Strong References Strong reference are the most prevalent type of object referencing in Java. When an object has a strong reference pointing to it, the garbage collector will not reclaim its memory. F...

Comprehensive Guide to SSTI Explained with Payload Bypass Techniques

Introduction Server-Side Template Injection (SSTI) is a vulnerability in web applications where user input is improper handled within the template engine and executed on the server. This exploit can r...

Implement Image Upload Functionality for Django Integrated TinyMCE Editor

Django’s Admin panel is highly user-friendly, and pairing it with TinyMCE, an effective rich text editor, simplifies content management significantly. Combining the two is particular useful for bloggi...

Leave a Comment

Anonymous

◎Feel free to join the discussion and share your thoughts.