├── .github └── FUNDING.yml ├── .gitignore ├── README.md ├── pom.xml └── src ├── main └── java │ └── murraco │ ├── BubbleSort.java │ ├── Heapsort.java │ ├── InsertionSort.java │ ├── MergeSort.java │ ├── Quicksort.java │ └── SelectionSort.java └── test └── java └── murraco └── SortingAlgorithmsTest.java /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] 4 | patreon: # Replace with a single Patreon username 5 | open_collective: # Replace with a single Open Collective username 6 | ko_fi: murraco # Replace with a single Ko-fi username 7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel 8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry 9 | liberapay: # Replace with a single Liberapay username 10 | issuehunt: # Replace with a single IssueHunt username 11 | lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry 12 | polar: # Replace with a single Polar username 13 | buy_me_a_coffee: # Replace with a single Buy Me a Coffee username 14 | custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] 15 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Eclipse 2 | .classpath 3 | .project 4 | .settings/ 5 | 6 | # Maven 7 | log/ 8 | target/ -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Sorting Algorithms 2 | 3 | ![](https://img.shields.io/badge/build-success-brightgreen.svg) 4 | ![](https://img.shields.io/badge/test-pass-brightgreen.svg) 5 | 6 | # Algorithms 7 | 8 | ![](https://img.shields.io/badge/bubblesort-✓-blue.svg) 9 | ![](https://img.shields.io/badge/insertionsort-✓-blue.svg) 10 | ![](https://img.shields.io/badge/selectionsort-✓-blue.svg) 11 | ![](https://img.shields.io/badge/mergesort-✓-blue.svg) 12 | ![](https://img.shields.io/badge/heapsort-✓-blue.svg) 13 | ![](https://img.shields.io/badge/quicksort-✓-blue.svg) 14 | 15 | # File Structure 16 | 17 | ``` 18 | sorting-algorhtms/ 19 | │ 20 | ├── src/main/java/murraco 21 | │ └── murraco 22 | │ ├── BubbleSort.java 23 | │ ├── Heapsort.java 24 | │ ├── InsertionSort.java 25 | │ ├── MergeSort.java 26 | │ ├── Quicksort.java 27 | │ └── SelectionSort.java 28 | │ 29 | ├── src/test/java/ 30 | │ └── murraco 31 | │ └── SortingAlgorithmsTest.java 32 | │ 33 | ├── .gitignore 34 | ├── pom.xml 35 | └── README.md 36 | ``` 37 | 38 | ## BubbleSort 39 | 40 | **stable:** `Yes` - **time:** `O(n^2)` - **space:** `O(1)` 41 | 42 | In bubble sort, we start at the beginning of the array and swap the first two elements if the first is greater than the second. Then, we go to the next pair, and so on, continuously making sweeps of the array until it's sorted 43 | 44 | The single best advantage of a bubble sort is that it's very simple to understand and code from memory. Additionally, it's a stable sort algorithm that requires no additional memory, since all swaps are made in place. Normally it's `O(n^2)` runtime, and hence is very slow for large data sets. 45 | 46 | ## InsertionSort 47 | 48 | **stable:** `Yes` - **time:** `O(n^2)` - **space:** `O(1)` 49 | 50 | It's a stable sorting algorithm that seeks to sort a list one element at a time. With each iteration, it takes the next element waiting to be sorted, and adds it, in proper location, to those elements that have already been sorted. 51 | 52 | It works very efficiently for lists that are nearly sorted initially. Furthermore, it can also work on data-sets that are constantly being added to. For instance, if one wanted to maintain a sorted list of the highest scores achieved in a game, an insertion sort would work well since the new elements would be added to the data as the game was played. 53 | 54 | ## SelectionSort 55 | 56 | **stable:** `No` - **time:** `O(n^2)` - **space:** `O(1)` 57 | 58 | It starts with the first element in the array (or list) and scans through the array to find the element with the smallest key, which it swaps with the first element. The process is then repeated with each subsequent element until the last element is reached. 59 | 60 | It has the advantage that requires at most `n-1` swaps. In situations in which moving data elements is more expensive than comparing them, selection sort may perform better than other algorithms. The efficiency of an algorithm depends on what you're optimizing for. 61 | 62 | ## MergeSort 63 | 64 | **stable:** `No` - **time:** `O(n log n)` - **space:** `O(n)` 65 | 66 | Merge sort is a divide-and-conquer algorithm that works by splitting a data set into two or more subsets, sorting the subsets, and then merging them together into the final sorted set. 67 | 68 | Unlike most other sorting algorithms, merge sort is a good choice for data-sets that are too large to fit into memory. In a typical scenario, the contents of a large file are split into multiple smaller files. Each of the smaller files is read into memory, sorted using an appropriate algorithm, and written back out. A merge operation is then performed using the sorted files as input and the sorted data is written directly to the final output file. 69 | 70 | Each recursively-call has `O(n)` runtime, and a total of `O(log n)` recursions are required, thus the runtime of this algorithm is `O(n log n)`. A merge sort can also be modified for performance on lists that are nearly sorted to begin with. After sorting each half of the data, if the highest element in one list is less than the lowest element in the other half, then the merge step is unnecessary. 71 | 72 | Apart from being fairly efficient, a merge sort has the advantage that it can be used to solve other problems such as determining how **unsorted** a given list is. 73 | 74 | ## Heapsort 75 | 76 | **stable:** `No` - **time:** `O(n log n)` - **space:** `O(1)` 77 | 78 | Heapsort is simple to implement, performs an `O(n log n)` in place sort, but is not stable. 79 | 80 | The first loop, the `O(n)` **heapify** phase, puts the array into heap order. The second loop, the `O(n log n)` **sortdown** phase, repeatedly extracts the maximum and restores heap order. 81 | 82 | Both phases are slightly adaptive, though not in any particularly useful manner. In the nearly sorted case, the heapify phase destroys the original order. In the reversed case, the heapify phase is as fast as possible since the array starts in heap order, but then the sortdown phase is typical. In the few unique keys case, there is some speedup, but not as much as in 3-way quicksort. 83 | 84 | ## Quicksort 85 | 86 | **stable:** `No` - **time:** `O(n log n)` - **space:** `O(log n)` 87 | 88 | Quicksort is a divide-and-conquer algorithm that involves choosing a pivot value from a data-set and splitting the set into two subsets: a set that contains all values less than the pivot and a set that contains all values greater than or equal to the pivot. The pivot/split process is recursively applied to each subset until there are no more subsets to split. The results are combined to form the final sorted set. 89 | 90 | The challenge of a quicksort is to determine a reasonable **midpoint** value for dividing the data into two groups. The efficiency of the algorithm is entirely dependent upon how successfully and accurate the midpoint value is selected. In the best case, the runtime is `O(n log n`). In the worst case where one of the two groups always has only a single element, the runtime drops to `O(n^2)`. 91 | 92 | If it's known that the data to be sorted all fit within a given range, or fit a certain distribution model, this knowledge can be used to improve the efficiency of the algorithm by choosing midpoint values that are likely to divide the data in half as close to evenly as possible. A generic algorithm that is designed to work without respect to data types or value ranges may simply select a value from the unsorted list, or use some random method to determine the midpoint. 93 | 94 | # Contribution 95 | 96 | - Report issues 97 | - Open pull request with improvements 98 | - Spread the word 99 | - Reach out to me directly at 100 | 101 | # Buy me a coffee to show your support! 102 | 103 | [![ko-fi](https://ko-fi.com/img/githubbutton_sm.svg)](https://ko-fi.com/murraco) 104 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | 5 | murraco 6 | sorting-algorithms 7 | 1.0.0 8 | 9 | sorting-algorithms 10 | 11 | 12 | UTF-8 13 | UTF-8 14 | 1.8 15 | 16 | 17 | 18 | 19 | junit 20 | junit 21 | 4.13.1 22 | 23 | 24 | 25 | 26 | 27 | 28 | maven-compiler-plugin 29 | 3.6.1 30 | 31 | 32 | 1.8 33 | 1.8 34 | 35 | 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /src/main/java/murraco/BubbleSort.java: -------------------------------------------------------------------------------- 1 | package murraco; 2 | 3 | public class BubbleSort { 4 | 5 | // Time complexity: average O(n^2) and best O(n) - Space complexity: O(1) 6 | public static > void bubbleSort(T[] arr) { 7 | for (int i = 0; i < arr.length - 1; i++) { 8 | for (int j = 1; j < arr.length; j++) { 9 | if (arr[j].compareTo(arr[j - 1]) < 0) { 10 | T temp = arr[j]; 11 | arr[j] = arr[j - 1]; 12 | arr[j - 1] = temp; 13 | } 14 | } 15 | } 16 | } 17 | 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/murraco/Heapsort.java: -------------------------------------------------------------------------------- 1 | package murraco; 2 | 3 | public class Heapsort { 4 | 5 | // Time complexity: O(n*log(n)) - Space complexity: O(1) 6 | public static > void heapSort(T[] arr) { 7 | buildMaxHeap(arr); 8 | int heapSize = arr.length - 1; 9 | for (int i = arr.length - 1; i > 0; i--) { 10 | swap(arr, 0, heapSize); 11 | heapSize--; 12 | maxHeapify(arr, 0, heapSize); 13 | } 14 | } 15 | 16 | public static > void maxHeapify(T[] arr, int i, int n) { 17 | int leftChild = i * 2 + 1; 18 | int rightChild = leftChild + 1; 19 | int largest = i; 20 | if (leftChild <= n && arr[i].compareTo(arr[leftChild]) < 0) { 21 | largest = leftChild; 22 | } 23 | if (rightChild <= n && arr[largest].compareTo(arr[rightChild]) < 0) { 24 | largest = rightChild; 25 | } 26 | if (largest != i) { 27 | swap(arr, i, largest); 28 | maxHeapify(arr, largest, n); 29 | } 30 | } 31 | 32 | public static > void buildMaxHeap(T[] arr) { 33 | for (int i = arr.length / 2; i > -1; i--) { 34 | maxHeapify(arr, i, arr.length - 1); 35 | } 36 | } 37 | 38 | public static > void swap(T[] arr, int i, int j) { 39 | T temp = arr[i]; 40 | arr[i] = arr[j]; 41 | arr[j] = temp; 42 | } 43 | 44 | } 45 | -------------------------------------------------------------------------------- /src/main/java/murraco/InsertionSort.java: -------------------------------------------------------------------------------- 1 | package murraco; 2 | 3 | public class InsertionSort { 4 | 5 | // Time complexity: average O(n^2) and best O(n) - Space complexity: O(1) 6 | public static > void insertionSort(T[] arr) { 7 | for (int i = 0; i < arr.length; i++) { 8 | T temp = arr[i]; 9 | int j = i; 10 | while (j > 0 && arr[j - 1].compareTo(temp) > 0) { 11 | arr[j] = arr[j - 1]; 12 | j--; 13 | } 14 | arr[j] = temp; 15 | } 16 | } 17 | 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/murraco/MergeSort.java: -------------------------------------------------------------------------------- 1 | package murraco; 2 | 3 | public class MergeSort { 4 | 5 | // Time complexity: O(n*log(n)) - Space complexity: O(n) 6 | public static void mergeSort(Integer[] arr) { 7 | if (arr.length <= 1) { 8 | return; 9 | } 10 | int mid = arr.length / 2; 11 | Integer[] left = new Integer[mid]; 12 | Integer[] right = new Integer[arr.length - mid]; 13 | for (int i = 0; i < mid; i++) { 14 | left[i] = arr[i]; 15 | } 16 | for (int i = mid; i < arr.length; i++) { 17 | right[i - mid] = arr[i]; 18 | } 19 | mergeSort(left); 20 | mergeSort(right); 21 | merge(arr, left, right); 22 | } 23 | 24 | public static void merge(Integer[] arr, Integer[] left, Integer[] right) { 25 | int j = 0; 26 | int k = 0; 27 | for (int i = 0; i < arr.length; i++) { 28 | if (j == left.length) { 29 | arr[i] = right[k++]; 30 | } else if (k == right.length) { 31 | arr[i] = left[j++]; 32 | } else if (left[j].compareTo(right[k]) < 0) { 33 | arr[i] = left[j++]; 34 | } else { 35 | arr[i] = right[k++]; 36 | } 37 | } 38 | } 39 | 40 | } 41 | -------------------------------------------------------------------------------- /src/main/java/murraco/Quicksort.java: -------------------------------------------------------------------------------- 1 | package murraco; 2 | 3 | public class Quicksort { 4 | 5 | // Time complexity: average O(n*log(n)) and worst O(n^2) - Space complexity: O(log(n)) 6 | public static > void quickSort(T[] arr) { 7 | quickSort(arr, 0, arr.length - 1); 8 | } 9 | 10 | public static > void quickSort(T[] arr, int start, int end) { 11 | if (start < end) { 12 | int pivotIndex = partition(arr, start, end); 13 | quickSort(arr, start, pivotIndex - 1); 14 | quickSort(arr, pivotIndex + 1, end); 15 | } 16 | } 17 | 18 | public static > int partition(T[] arr, int start, int end) { 19 | int pivotIndex = pickPivotIndex(start, end); 20 | T pivot = arr[pivotIndex]; 21 | swap(arr, pivotIndex, end); 22 | int index = start; 23 | for (int i = start; i < end; i++) { 24 | if (arr[i].compareTo(pivot) < 0) { 25 | swap(arr, i, index); 26 | index++; 27 | } 28 | } 29 | swap(arr, index, end); 30 | return index; 31 | } 32 | 33 | public static int pickPivotIndex(int start, int end) { 34 | return (int) (start + (end - start + 1) * Math.random()); 35 | } 36 | 37 | public static > void swap(T[] arr, int i, int j) { 38 | T temp = arr[i]; 39 | arr[i] = arr[j]; 40 | arr[j] = temp; 41 | } 42 | 43 | } 44 | -------------------------------------------------------------------------------- /src/main/java/murraco/SelectionSort.java: -------------------------------------------------------------------------------- 1 | package murraco; 2 | 3 | public class SelectionSort { 4 | 5 | // Time complexity: O(n^2) - Space complexity: O(1) 6 | public static > void selectionSort(T[] arr) { 7 | for (int i = 0; i < arr.length - 1; i++) { 8 | int iMin = i; 9 | for (int j = i + 1; j < arr.length; j++) { 10 | iMin = (arr[j].compareTo(arr[iMin]) < 0) ? j : iMin; 11 | } 12 | swap(arr, i, iMin); 13 | } 14 | } 15 | 16 | public static > void swap(T[] arr, int i, int j) { 17 | T temp = arr[i]; 18 | arr[i] = arr[j]; 19 | arr[j] = temp; 20 | } 21 | 22 | } 23 | -------------------------------------------------------------------------------- /src/test/java/murraco/SortingAlgorithmsTest.java: -------------------------------------------------------------------------------- 1 | package murraco; 2 | 3 | import static org.junit.Assert.assertEquals; 4 | 5 | import java.util.Arrays; 6 | 7 | import org.junit.Test; 8 | 9 | import murraco.BubbleSort; 10 | import murraco.Heapsort; 11 | import murraco.InsertionSort; 12 | import murraco.MergeSort; 13 | import murraco.Quicksort; 14 | import murraco.SelectionSort; 15 | 16 | public class SortingAlgorithmsTest { 17 | 18 | @Test 19 | public void testBubbleSort() { 20 | final Integer[] data = {4, 3, 0, 11, 7, 5, 15, 12, 99, 1}; 21 | BubbleSort.bubbleSort(data); 22 | assertEquals("[0, 1, 3, 4, 5, 7, 11, 12, 15, 99]", Arrays.toString(data)); 23 | } 24 | 25 | @Test 26 | public void testInsertionSort() { 27 | final Integer[] data = {4, 3, 0, 11, 7, 5, 15, 12, 99, 1}; 28 | InsertionSort.insertionSort(data); 29 | assertEquals("[0, 1, 3, 4, 5, 7, 11, 12, 15, 99]", Arrays.toString(data)); 30 | } 31 | 32 | @Test 33 | public void testSelectionSort() { 34 | final Integer[] data = {4, 3, 0, 11, 7, 5, 15, 12, 99, 1}; 35 | SelectionSort.selectionSort(data); 36 | assertEquals("[0, 1, 3, 4, 5, 7, 11, 12, 15, 99]", Arrays.toString(data)); 37 | } 38 | 39 | @Test 40 | public void testMergeSort() { 41 | final Integer[] data = {4, 3, 0, 11, 7, 5, 15, 12, 99, 1}; 42 | MergeSort.mergeSort(data); 43 | assertEquals("[0, 1, 3, 4, 5, 7, 11, 12, 15, 99]", Arrays.toString(data)); 44 | } 45 | 46 | @Test 47 | public void testHeapsort() { 48 | final Integer[] data = {4, 3, 0, 11, 7, 5, 15, 12, 99, 1}; 49 | Heapsort.heapSort(data); 50 | assertEquals("[0, 1, 3, 4, 5, 7, 11, 12, 15, 99]", Arrays.toString(data)); 51 | } 52 | 53 | @Test 54 | public void testQuicksort() { 55 | final Integer[] data = {4, 3, 0, 11, 7, 5, 15, 12, 99, 1}; 56 | Quicksort.quickSort(data); 57 | assertEquals("[0, 1, 3, 4, 5, 7, 11, 12, 15, 99]", Arrays.toString(data)); 58 | } 59 | } 60 | --------------------------------------------------------------------------------