Basic algorithms in Java

Searching 🔎

Linear Search

This is the simplest search algorithm, we iterate through the whole array, if the integer we are searching for is there we return it's index in the array. If we don't see the integer, we return -1 to signal that it is not in the array.


_10
public static int linear(int[] array, int x) {
_10
for (int i = 0; i < array.length; i++) {
_10
if (array[i] == x) {
_10
return i;
_10
}
_10
}
_10
return -1;
_10
}

Binary Search

this algorithm leverages an already sorted array, by splitting the array and determining on which side of the split the element could be.

Iterative


_19
public static int binarySearchIterative(int[] array, int x) {
_19
int upperLimit = array.length -1;
_19
int lowerLimit = 0;
_19
int mid;
_19
_19
while (upperLimit >= lowerLimit) {
_19
mid = (upperLimit + lowerLimit) / 2;
_19
if (array[mid] == x) {
_19
return mid;
_19
}
_19
_19
if (array[mid] > x) {
_19
upperLimit = mid - 1;
_19
} else {
_19
lowerLimit = mid + 1;
_19
}
_19
}
_19
return -1;
_19
}

Recursive


_20
public static int binarySearchRecursive(int[] array, int lowerLimit, int upperLimit, int x) {
_20
if (upperLimit >= lowerLimit) {
_20
int mid = (upperLimit + lowerLimit) / 2;
_20
_20
if (array[mid] == x) {
_20
return mid;
_20
}
_20
_20
if (array[mid] > x) {
_20
return binarySearchRecursive(array, lowerLimit, mid - 1, x);
_20
}
_20
_20
return binarySearchRecursive(array, mid + 1, upperLimit, x);
_20
}
_20
return -1;
_20
}
_20
_20
public static int binarySearch(int[] array, int element) {
_20
return binarySearchRecursive(array, 0, array.length - 1, element);
_20
}

Sorting 📮

Selection Sort

The selection sort algorithm sorts an array by repeatedly finding the minimum element from an unsorted part of an array and placing it at the start of the unsorted part.


_15
public static void selectionSort(int[] array) {
_15
for (int i = 0; i < array.length ; i++) {
_15
int minIndex = i;
_15
// find smallest element in array.
_15
for (int j = i + 1; j < array.length; j++) {
_15
if (array[j] < array[minIndex]) {
_15
minIndex = j;
_15
}
_15
}
_15
// swap i with the found element.
_15
int temp = array[i];
_15
array[i] = array[minIndex];
_15
array[minIndex] = i;
_15
}
_15
}

Insertion Sort

The insertion sort algorithm sorts an array like a human would sort cards, when you are sorting cards let's say you start at the left, then, you look at the cards before the one you want to place if there are cards that are greater than your current card you put the card where its supposed to go and the others get shifted one place to the right. in real life you just insert the card at the correct place but in java you need to shift the cards that are greater than your current card to the right so you can place your card in that spot where you know it's supposed to go.


_12
public static void insertionSort(int[] array) {
_12
for (int i = 1; i < array.length; i++) {
_12
int key = array[i];
_12
int j = i - 1;
_12
_12
while (j >= 0 && array[j] > key) {
_12
array[j + 1] = array[j];
_12
j--;
_12
}
_12
array[j + 1] = key;
_12
}
_12
}

Bubble Sort

This is a slow sorting algorithm that checks successive elements of an array are they in order ? no -> swap, yes -> next pair.


_11
public static void bubbleSort(int[] array) {
_11
for (int i = 0; i < array.length; i++) {
_11
for (int j = i + 1; j < array.length; j++) {
_11
if (array[i] > array[j]) {
_11
int temp = array[i];
_11
array[i] = array[j];
_11
array[j] = temp;
_11
}
_11
}
_11
}
_11
}

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:

  • Pick first element as pivot.
  • Pick pick last element as pivot (implemented below)
  • Pick a random element as pivot.
  • Pick the median of low and high as pivot.

_41
public static void quickSort(int[] array) {
_41
quickSortRecursive(array, 0, array.length-1);
_41
}
_41
_41
public static void quickSortRecursive(int[] array, int low, int high) {
_41
if (low < high + 1) {
_41
int partition = partition(array, low, high);
_41
quickSortRecursive(array, low, partition - 1);
_41
quickSortRecursive(array, partition + 1, high);
_41
}
_41
}
_41
_41
public static int partition(int[] arr, int low, int high) {
_41
int pivot = getPivotIndex(low, high);
_41
int partitionIndex = 0;
_41
_41
swap(arr, pivot, high);
_41
_41
for (int i = 0; i < high; i++) {
_41
// we put the pivot arr[high]
_41
if (arr[i] <= arr[high]) {
_41
swap(arr, i, partitionIndex);
_41
partitionIndex++;
_41
}
_41
}
_41
swap(arr, partitionIndex, high);
_41
_41
return partitionIndex;
_41
}
_41
_41
private static int getPivotIndex(int low, int up)
_41
{
_41
Random rand = new Random();
_41
return rand.nextInt((up - low) + 1) + low;
_41
}
_41
_41
public static void swap(int[] arr, int a, int b) {
_41
int temp = arr[a];
_41
arr[a] = arr[b];
_41
arr[b] = temp;
_41
}

Merge Sort

Merge Sort is a Divide and Conquer algorithm. It divides 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, low, middle, middle+1, high) takes arr[low..middle] and arr[middle+1..high] which should be sorted and merges the two them into one.


_47
public static void mergeSort(int[] arr) {
_47
mergeSortRecursive(arr, 0, arr.length - 1);
_47
}
_47
_47
public static void mergeSortRecursive(int[] arr, int low, int high) {
_47
if (low < high) {
_47
int middle = (high + low)/2;
_47
mergeSortRecursive(arr, low, middle);
_47
mergeSortRecursive(arr, middle + 1, high);
_47
merge(arr, low, middle, middle + 1, high);
_47
}
_47
}
_47
_47
public static void merge(int[] arr, int low1, int high1, int low2, int high2) {
_47
int index1 = 0;
_47
int index2 = 0;
_47
int indexArr = low1;
_47
_47
int[] copy1 = new int[high1 - low1+1];
_47
int[] copy2 = new int[high2 - low2+1];
_47
_47
for (int i = 0; i < copy1.length; i++) {
_47
copy1[i] = arr[low1 + i];
_47
}
_47
for (int i = 0; i < copy2.length; i++) {
_47
copy2[i] = arr[low2 + i];
_47
}
_47
_47
while (index1 < copy1.length && index2 < copy2.length) {
_47
if (copy1[index1] <= copy2[index2]) {
_47
arr[indexArr] = copy1[index1];
_47
index1++;
_47
} else {
_47
arr[indexArr] = copy2[index2];
_47
index2++;
_47
}
_47
indexArr++;
_47
}
_47
_47
for (int i = index1; i < copy1.length; i++, indexArr++) {
_47
arr[indexArr] = copy1[i];
_47
}
_47
_47
for (int i = index2; i < copy2.length; i++, indexArr++) {
_47
arr[indexArr] = copy2[i];
_47
}
_47
}

Radix Sort

Radix is a sorting algorithm that does not use comparison.

Instead it iterates over the digits in the elements you want to sort (for example in base 10, ones', tenths', hundredths' ...) Then we iterate over our elements and we count how many times we find a digit, and we put that count in a count array.

Ok, deep breath 👃

With this count array, we can find what is called the prefix sum which gives you the position+1 of the element should be placed at in the next step.

Then we make a new output array (this array will be ordered but only relative to the digits that have been iterated on), to do this you have to iterate over the input array from right to left, getting the digit of the element. and using the count array with the digit as key to find the new place the element should take.

Thank you for coming to my TED talk 😆

There are several ways of doing Radix Sort:

  • with buckets (in practice a linked-list, or a queue like data-structure) takes a lot of memory
  • in combination with countingSort. takes less memory but costs more time.

implementation: radixSort with countingSort


_43
public static int[] radixSort(int[] arr) {
_43
int[] count = new int[10];
_43
int digit;
_43
_43
// find the length of the largest number.
_43
int max = arr[0];
_43
for (int i = 1; i < arr.length; i++) {
_43
if (arr[i] > max) {
_43
max = arr[i];
_43
}
_43
}
_43
int countDigits = Integer.toString(max).length();
_43
_43
// Iterate for each digit in the largest number in the array.
_43
// keep track of the digits, tenths, hundredths ... with digitTen
_43
for (int times = 1, digitTen = 1; times <= countDigits; times++, digitTen *= 10) {
_43
// clear the count array.
_43
Arrays.fill(count, 0);
_43
_43
// for each digit in the increase the count in the count array.
_43
for (int i = 0; i < arr.length; i++) {
_43
digit = arr[i] % (digitTen * 10);
_43
digit = digit/digitTen;
_43
count[digit]++;
_43
}
_43
_43
// get the prefix sum of the count array.
_43
for (int i = 1; i < count.length; i++) {
_43
count[i] = count[i - 1] + count[i];
_43
}
_43
_43
// use the prefix sum to find the correct index for a digit.
_43
int[] output = new int[arr.length];
_43
for (int i = arr.length - 1; i >= 0; i--) {
_43
digit = arr[i] % (digitTen * 10);
_43
digit = digit/digitTen;
_43
output[--count[digit]] = arr[i];
_43
}
_43
_43
arr = output;
_43
}
_43
return arr;
_43
}