Heap Sort: Simplify (#3777)
* bug fix for CircularBuffer + refactoring + add unit tests * change Insertion sort to classical implementation + add isSorted function to SortUtils + add SortUtilsRandomGenerator for generating random values and arrays * little fix * simplify heap sort * Update src/main/java/com/thealgorithms/sorts/HeapSort.java * Update src/main/java/com/thealgorithms/sorts/HeapSort.java Co-authored-by: Debasish Biswas <debasishbsws.abc@gmail.com>
This commit is contained in:
parent
72468cc707
commit
7692e8f47d
@ -1,126 +1,56 @@
|
|||||||
package com.thealgorithms.sorts;
|
package com.thealgorithms.sorts;
|
||||||
|
|
||||||
import static com.thealgorithms.sorts.SortUtils.*;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Heap Sort Algorithm Implements MinHeap
|
* Heap Sort Algorithm Implementation
|
||||||
*
|
*
|
||||||
* @author Podshivalov Nikita (https://github.com/nikitap492)
|
* @see <a href="https://en.wikipedia.org/wiki/Heapsort">Heap Sort Algorithm</a>
|
||||||
*/
|
*/
|
||||||
public class HeapSort implements SortAlgorithm {
|
public class HeapSort implements SortAlgorithm {
|
||||||
|
|
||||||
private static class Heap<T extends Comparable<T>> {
|
/**
|
||||||
|
* For simplicity, we are considering the heap root index as 1 instead of 0.
|
||||||
/**
|
* It simplifies future calculations. Because of that we are decreasing the
|
||||||
* Array to store heap
|
* provided indexes by 1 in {@link #swap(Object[], int, int)} and
|
||||||
*/
|
* {@link #less(Comparable[], int, int)} functions.
|
||||||
private T[] heap;
|
*/
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructor
|
|
||||||
*
|
|
||||||
* @param heap array of unordered integers
|
|
||||||
*/
|
|
||||||
public Heap(T[] heap) {
|
|
||||||
this.heap = heap;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Heapifies subtree from top as root to last as last child
|
|
||||||
*
|
|
||||||
* @param rootIndex index of root
|
|
||||||
* @param lastChild index of last child
|
|
||||||
*/
|
|
||||||
private void heapSubtree(int rootIndex, int lastChild) {
|
|
||||||
int leftIndex = rootIndex * 2 + 1;
|
|
||||||
int rightIndex = rootIndex * 2 + 2;
|
|
||||||
T root = heap[rootIndex];
|
|
||||||
if (rightIndex <= lastChild) { // if has right and left children
|
|
||||||
T left = heap[leftIndex];
|
|
||||||
T right = heap[rightIndex];
|
|
||||||
if (less(left, right) && less(left, root)) {
|
|
||||||
swap(heap, leftIndex, rootIndex);
|
|
||||||
heapSubtree(leftIndex, lastChild);
|
|
||||||
} else if (less(right, root)) {
|
|
||||||
swap(heap, rightIndex, rootIndex);
|
|
||||||
heapSubtree(rightIndex, lastChild);
|
|
||||||
}
|
|
||||||
} else if (leftIndex <= lastChild) { // if no right child, but has left child
|
|
||||||
T left = heap[leftIndex];
|
|
||||||
if (less(left, root)) {
|
|
||||||
swap(heap, leftIndex, rootIndex);
|
|
||||||
heapSubtree(leftIndex, lastChild);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Makes heap with root as root
|
|
||||||
*
|
|
||||||
* @param root index of root of heap
|
|
||||||
*/
|
|
||||||
private void makeMinHeap(int root) {
|
|
||||||
int leftIndex = root * 2 + 1;
|
|
||||||
int rightIndex = root * 2 + 2;
|
|
||||||
boolean hasLeftChild = leftIndex < heap.length;
|
|
||||||
boolean hasRightChild = rightIndex < heap.length;
|
|
||||||
if (hasRightChild) { // if has left and right
|
|
||||||
makeMinHeap(leftIndex);
|
|
||||||
makeMinHeap(rightIndex);
|
|
||||||
heapSubtree(root, heap.length - 1);
|
|
||||||
} else if (hasLeftChild) {
|
|
||||||
heapSubtree(root, heap.length - 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the root of heap
|
|
||||||
*
|
|
||||||
* @return root of heap
|
|
||||||
*/
|
|
||||||
private T getRoot(int size) {
|
|
||||||
swap(heap, 0, size);
|
|
||||||
heapSubtree(0, size - 1);
|
|
||||||
return heap[size]; // return old root
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public <T extends Comparable<T>> T[] sort(T[] unsorted) {
|
public <T extends Comparable<T>> T[] sort(T[] unsorted) {
|
||||||
return sort(Arrays.asList(unsorted)).toArray(unsorted);
|
int n = unsorted.length;
|
||||||
}
|
heapify(unsorted, n);
|
||||||
|
while (n > 1) {
|
||||||
@Override
|
swap(unsorted, 1, n--);
|
||||||
public <T extends Comparable<T>> List<T> sort(List<T> unsorted) {
|
siftDown(unsorted, 1, n);
|
||||||
int size = unsorted.size();
|
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
Heap<T> heap = new Heap<>(
|
|
||||||
unsorted.toArray((T[]) new Comparable[unsorted.size()])
|
|
||||||
);
|
|
||||||
|
|
||||||
heap.makeMinHeap(0); // make min heap using index 0 as root.
|
|
||||||
List<T> sorted = new ArrayList<>(size);
|
|
||||||
while (size > 0) {
|
|
||||||
T min = heap.getRoot(--size);
|
|
||||||
sorted.add(min);
|
|
||||||
}
|
}
|
||||||
|
return unsorted;
|
||||||
return sorted;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
private static <T extends Comparable<T>> void heapify(T[] unsorted, int n) {
|
||||||
* Main method
|
for (int k = n / 2; k >= 1; k--) {
|
||||||
*
|
siftDown(unsorted, k, n);
|
||||||
* @param args the command line arguments
|
}
|
||||||
*/
|
}
|
||||||
public static void main(String[] args) {
|
|
||||||
Integer[] heap = { 4, 23, 6, 78, 1, 54, 231, 9, 12 };
|
private static <T extends Comparable<T>> void siftDown(T[] unsorted, int k, int n) {
|
||||||
HeapSort heapSort = new HeapSort();
|
while (2 * k <= n) {
|
||||||
print(heapSort.sort(heap));
|
int j = 2 * k;
|
||||||
|
if (j < n && less(unsorted, j, j + 1)) {
|
||||||
|
j++;
|
||||||
|
}
|
||||||
|
if (!less(unsorted, k, j)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
swap(unsorted, k, j);
|
||||||
|
k = j;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static <T> void swap(T[] array, int idx, int idy) {
|
||||||
|
T swap = array[idx - 1];
|
||||||
|
array[idx - 1] = array[idy - 1];
|
||||||
|
array[idy - 1] = swap;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static <T extends Comparable<T>> boolean less(T[] array, int idx, int idy) {
|
||||||
|
return array[idx - 1].compareTo(array[idy - 1]) < 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,35 +1,95 @@
|
|||||||
package com.thealgorithms.sorts;
|
package com.thealgorithms.sorts;
|
||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertArrayEquals;
|
import static org.junit.jupiter.api.Assertions.assertArrayEquals;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
public class HeapSortTest {
|
public class HeapSortTest {
|
||||||
|
private HeapSort heapSort;
|
||||||
private HeapSort heapSort = new HeapSort();
|
|
||||||
|
@BeforeEach
|
||||||
@Test
|
void setUp() {
|
||||||
void testHeapSortCase1() {
|
heapSort = new HeapSort();
|
||||||
Integer[] array = { 49, 4, 36, 9, 144, 1 };
|
|
||||||
Integer[] sorted = heapSort.sort(array);
|
|
||||||
Integer[] expected = { 1, 4, 9, 36, 49, 144 };
|
|
||||||
assertArrayEquals(expected, sorted);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testHeapSortCase2() {
|
void shouldAcceptWhenEmptyArrayIsPassed() {
|
||||||
Integer[] array = { };
|
Integer[] array = new Integer[]{};
|
||||||
|
Integer[] expected = new Integer[]{};
|
||||||
|
|
||||||
Integer[] sorted = heapSort.sort(array);
|
Integer[] sorted = heapSort.sort(array);
|
||||||
Integer[] expected = { };
|
|
||||||
assertArrayEquals(expected, sorted);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void testHeapSortCase3 () {
|
|
||||||
Integer[] array = { -3, 5, 3, 4, 3, 7, 40, -20, 30, 0 };
|
|
||||||
Integer[] sorted = heapSort.sort(array);
|
|
||||||
Integer[] expected = { -20, -3, 0, 3, 3, 4, 5, 7, 30, 40 };
|
|
||||||
assertArrayEquals(expected, sorted);
|
assertArrayEquals(expected, sorted);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void shouldAcceptWhenSingleValuedArrayIsPassed() {
|
||||||
|
Integer[] array = new Integer[]{2};
|
||||||
|
Integer[] expected = new Integer[]{2};
|
||||||
|
|
||||||
|
Integer[] sorted = heapSort.sort(array);
|
||||||
|
|
||||||
|
assertArrayEquals(expected, sorted);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void shouldAcceptWhenArrayWithAllPositiveValuesIsPassed() {
|
||||||
|
Integer[] array = new Integer[]{60, 7, 55, 9, 999, 3};
|
||||||
|
Integer[] expected = new Integer[]{3, 7, 9, 55, 60, 999};
|
||||||
|
|
||||||
|
Integer[] sorted = heapSort.sort(array);
|
||||||
|
|
||||||
|
assertArrayEquals(expected, sorted);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void shouldAcceptWhenArrayWithAllNegativeValuesIsPassed() {
|
||||||
|
Integer[] array = new Integer[]{-60, -7, -55, -9, -999, -3};
|
||||||
|
Integer[] expected = new Integer[]{-999, -60, -55, -9, -7, -3};
|
||||||
|
|
||||||
|
Integer[] sorted = heapSort.sort(array);
|
||||||
|
|
||||||
|
assertArrayEquals(expected, sorted);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void shouldAcceptWhenArrayWithRealNumberValuesIsPassed() {
|
||||||
|
Integer[] array = new Integer[]{60, -7, 55, 9, -999, -3};
|
||||||
|
Integer[] expected = new Integer[]{-999, -7, -3, 9, 55, 60};
|
||||||
|
|
||||||
|
Integer[] sorted = heapSort.sort(array);
|
||||||
|
|
||||||
|
assertArrayEquals(expected, sorted);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void shouldAcceptWhenArrayWithDuplicateValueIsPassed() {
|
||||||
|
Integer[] array = new Integer[]{60, 7, 55, 55, 999, 3};
|
||||||
|
Integer[] expected = new Integer[]{3, 7, 55, 55, 60, 999};
|
||||||
|
|
||||||
|
Integer[] sorted = heapSort.sort(array);
|
||||||
|
|
||||||
|
assertArrayEquals(expected, sorted);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void shouldAcceptWhenStringValueArrayIsPassed() {
|
||||||
|
String[] array = {"z", "a", "x", "b", "y"};
|
||||||
|
String[] expected = {"a", "b", "x", "y", "z"};
|
||||||
|
|
||||||
|
String[] sorted = heapSort.sort(array);
|
||||||
|
|
||||||
|
assertArrayEquals(expected, sorted);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void shouldAcceptWhenRandomArrayIsPassed() {
|
||||||
|
int randomSize = SortUtilsRandomGenerator.generateInt(10_000);
|
||||||
|
Double[] array = SortUtilsRandomGenerator.generateArray(randomSize);
|
||||||
|
Double[] sorted = heapSort.sort(array);
|
||||||
|
assertTrue(SortUtils.isSorted(sorted));
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user