Skip to content

Fix Linear probing hash map implementation #3902

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 15 commits into from
Feb 26, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
change Insertion sort to classical implementation + add isSorted func…
…tion to SortUtils + add SortUtilsRandomGenerator for generating random values and arrays
  • Loading branch information
NarekDW committed Oct 21, 2022
commit aa1f18aff125b66b6713cdde92a47fc3a07bc30d
85 changes: 64 additions & 21 deletions src/main/java/com/thealgorithms/sorts/InsertionSort.java
Original file line number Diff line number Diff line change
@@ -1,45 +1,88 @@
package com.thealgorithms.sorts;

import static com.thealgorithms.sorts.SortUtils.less;
import static com.thealgorithms.sorts.SortUtils.print;
import java.util.function.Function;

import static com.thealgorithms.sorts.SortUtils.*;

class InsertionSort implements SortAlgorithm {

/**
* Generic insertion sort algorithm in increasing order.
*
* @param array the array to be sorted.
* @param <T> the class of array.
* @param <T> the class of array.
* @return sorted array.
*/
@Override
public <T extends Comparable<T>> T[] sort(T[] array) {
for (int i = 1; i < array.length; i++) {
T insertValue = array[i];
int j;
for (j = i - 1; j >= 0 && less(insertValue, array[j]); j--) {
array[j + 1] = array[j];
}
if (j != i - 1) {
array[j + 1] = insertValue;
for (int i = 1; i < array.length; i++)
for (int j = i; j > 0 && less(array[j], array[j - 1]); j--)
swap(array, j, j - 1);
return array;
}

/**
* Sentinel sort is a function which on the first step finds the minimal element in the provided
* array and puts it to the zero position, such a trick gives us an ability to avoid redundant
* comparisons like `j > 0` and swaps (we can move elements on position right, until we find
* the right position for the chosen element) on further step.
*
* @param array the array to be sorted
* @param <T> Generic type which extends Comparable interface.
* @return sorted array
*/
public <T extends Comparable<T>> T[] sentinelSort(T[] array) {
int minElemIndex = 0;
int n = array.length;
if (n < 1)
return array;

// put the smallest element to the 0 position as a sentinel, which will allow us to avoid
// redundant comparisons like `j > 0` further
for (int i = 1; i < n; i++)
if (less(array[i], array[minElemIndex]))
minElemIndex = i;
swap(array, 0, minElemIndex);

for (int i = 2; i < n; i++) {
int j = i;
T currentValue = array[i];
while (less(currentValue, array[j - 1])) {
array[j] = array[j - 1];
j--;
}

array[j] = currentValue;
}

return array;
}

/**
* Driver Code
*/
public static void main(String[] args) {
Integer[] integers = { 4, 23, 6, 78, 1, 54, 231, 9, 12 };
InsertionSort sort = new InsertionSort();
sort.sort(integers);
print(integers);
/* [1, 4, 6, 9, 12, 23, 54, 78, 231] */

String[] strings = { "c", "a", "e", "b", "d" };
sort.sort(strings);
print(strings);
/* [a, b, c, d, e] */
int size = 100_000;
Double[] randomArray = SortUtilsRandomGenerator.generateArray(size);
Double[] copyRandomArray = new Double[size];
System.arraycopy(randomArray, 0, copyRandomArray, 0, size);

InsertionSort insertionSort = new InsertionSort();
double insertionTime = measureApproxExecTime(insertionSort::sort, randomArray);
System.out.printf("Original insertion time: %5.2f sec.\n", insertionTime);

double insertionSentinelTime = measureApproxExecTime(insertionSort::sentinelSort, copyRandomArray);
System.out.printf("Sentinel insertion time: %5.2f sec.\n", insertionSentinelTime);

// ~ 1.5 time sentinel sort is faster, then classical Insertion sort implementation.
System.out.printf("Sentinel insertion is %f3.2 time faster than Original insertion sort\n",
insertionTime / insertionSentinelTime);
}

private static double measureApproxExecTime(Function<Double[], Double[]> sortAlgorithm, Double[] randomArray) {
long start = System.currentTimeMillis();
sortAlgorithm.apply(randomArray);
long end = System.currentTimeMillis();
return (end - start) / 1000.0;
}
}
13 changes: 13 additions & 0 deletions src/main/java/com/thealgorithms/sorts/SortUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -99,4 +99,17 @@ static <T extends Comparable<T>> void flip(T[] array, int left, int right) {
swap(array, left++, right--);
}
}

/**
* Function to check if the array is sorted. By default, it will check if the array is sorted in ASC order.
*
* @param array - an array which to check is it sorted or not.
* @return true - if array sorted in ASC order, false otherwise.
*/
static <T extends Comparable<T>> boolean isSorted(T[] array) {
for (int i = 1; i < array.length; i++)
if (less(array[i], array[i - 1]))
return false;
return true;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package com.thealgorithms.sorts;

import java.util.Random;

public class SortUtilsRandomGenerator {

private static final Random random;
private static final long seed;

static {
seed = System.currentTimeMillis();
random = new Random(seed);
}


/**
* Function to generate array of double values, with predefined size.
*
* @param size result array size
* @return array of Double values, randomly generated, each element is between [0, 1)
*/
public static Double[] generateArray(int size) {
Double[] arr = new Double[size];
for (int i = 0; i < size; i++)
arr[i] = generateDouble();
return arr;
}

/**
* Function to generate Double value.
*
* @return Double value [0, 1)
*/
public static Double generateDouble() {
return random.nextDouble();
}

}
114 changes: 114 additions & 0 deletions src/test/java/com/thealgorithms/sorts/InsertionSortTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
package com.thealgorithms.sorts;

import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

import java.util.function.Function;

import static org.junit.jupiter.api.Assertions.*;

class InsertionSortTest {
private InsertionSort insertionSort;

@BeforeEach
void setUp() {
insertionSort = new InsertionSort();
}

@Test
void insertionSortSortEmptyArrayShouldPass() {
testEmptyArray(insertionSort::sort);
testEmptyArray(insertionSort::sentinelSort);
}

private void testEmptyArray(Function<Integer[], Integer[]> sortAlgorithm) {
Integer[] array = {};
Integer[] sorted = sortAlgorithm.apply(array);
Integer[] expected = {};
assertArrayEquals(expected, sorted);
assertTrue(SortUtils.isSorted(sorted));
}

@Test
void insertionSortClassicalSortSingleValueArrayShouldPass() {
testSingleValue(insertionSort::sort);
testSingleValue(insertionSort::sentinelSort);
}

private void testSingleValue(Function<Integer[], Integer[]> sortAlgorithm) {
Integer[] array = {7};
Integer[] sorted = sortAlgorithm.apply(array);
Integer[] expected = {7};
assertArrayEquals(expected, sorted);
assertTrue(SortUtils.isSorted(sorted));
}

@Test
void insertionSortClassicalWithIntegerArrayShouldPass() {
testIntegerArray(insertionSort::sort);
testIntegerArray(insertionSort::sentinelSort);
}

private void testIntegerArray(Function<Integer[], Integer[]> sortAlgorithm) {
Integer[] array = {49, 4, 36, 9, 144, 1};
Integer[] sorted = sortAlgorithm.apply(array);
Integer[] expected = {1, 4, 9, 36, 49, 144};
assertArrayEquals(expected, sorted);
assertTrue(SortUtils.isSorted(sorted));
}

@Test
void insertionSortClassicalForArrayWithNegativeValuesShouldPass() {
testWithNegativeValues(insertionSort::sort);
testWithNegativeValues(insertionSort::sentinelSort);
}

private void testWithNegativeValues(Function<Integer[], Integer[]> sortAlgorithm) {
Integer[] array = {49, -36, -144, -49, 1, 9};
Integer[] sorted = sortAlgorithm.apply(array);
Integer[] expected = {-144, -49, -36, 1, 9, 49};
assertArrayEquals(expected, sorted);
assertTrue(SortUtils.isSorted(sorted));
}

@Test
void insertionSortClassicalForArrayWithDuplicateValuesShouldPass() {
testWithDuplicates(insertionSort::sort);
testWithDuplicates(insertionSort::sentinelSort);
}

private void testWithDuplicates(Function<Integer[], Integer[]> sortAlgorithm) {
Integer[] array = {36, 1, 49, 1, 4, 9};
Integer[] sorted = sortAlgorithm.apply(array);
Integer[] expected = {1, 1, 4, 9, 36, 49};
assertArrayEquals(expected, sorted);
assertTrue(SortUtils.isSorted(sorted));
}

@Test
void insertionSortClassicalWithStringArrayShouldPass() {
testWithStringArray(insertionSort::sort);
testWithStringArray(insertionSort::sentinelSort);
}

private void testWithStringArray(Function<String[], String[]> sortAlgorithm) {
String[] array = {"c", "a", "e", "b", "d"};
String[] sorted = sortAlgorithm.apply(array);
String[] expected = {"a", "b", "c", "d", "e"};
assertArrayEquals(expected, sorted);
assertTrue(SortUtils.isSorted(sorted));
}

@Test
void insertionSortClassicalWithRandomArrayPass() {
testWithRandomArray(insertionSort::sort);
testWithRandomArray(insertionSort::sentinelSort);
}

private void testWithRandomArray(Function<Double[], Double[]> sortAlgorithm) {
int randomSize = (int) (SortUtilsRandomGenerator.generateDouble() * 10_000);
Double[] array = SortUtilsRandomGenerator.generateArray(randomSize);
Double[] sorted = sortAlgorithm.apply(array);
assertTrue(SortUtils.isSorted(sorted));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package com.thealgorithms.sorts;

import org.junit.jupiter.api.RepeatedTest;
import org.junit.jupiter.api.Test;

import static org.assertj.core.api.Assertions.assertThat;

class SortUtilsRandomGeneratorTest {

@RepeatedTest(1000)
void generateArray() {
int size = 1_000;
Double[] doubles = SortUtilsRandomGenerator.generateArray(size);
assertThat(doubles).hasSize(size);
assertThat(doubles).doesNotContainNull();
}

@Test
void generateArrayEmpty() {
int size = 0;
Double[] doubles = SortUtilsRandomGenerator.generateArray(size);
assertThat(doubles).hasSize(size);
}

@RepeatedTest(1000)
void generateDouble() {
Double randomDouble = SortUtilsRandomGenerator.generateDouble();
assertThat(randomDouble).isBetween(0.0, 1.0);
assertThat(randomDouble).isNotEqualTo(1.0);
}
}
44 changes: 44 additions & 0 deletions src/test/java/com/thealgorithms/sorts/SortUtilsTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package com.thealgorithms.sorts;

import org.junit.jupiter.api.Test;

import static org.junit.jupiter.api.Assertions.*;

class SortUtilsTest {

@Test
void isSortedEmptyArray() {
Double[] emptyArray = {};
assertTrue(SortUtils.isSorted(emptyArray));
}

@Test
void isSortedWithSingleElement() {
Double[] singleElementArray = {1.0};
assertTrue(SortUtils.isSorted(singleElementArray));
}

@Test
void isSortedTrue() {
Integer[] array = {1, 1, 2, 3, 5, 8, 11};
assertTrue(SortUtils.isSorted(array));

Integer[] identicalArray = {1, 1, 1, 1, 1};
assertTrue(SortUtils.isSorted(identicalArray));

Double[] doubles = {-15.123, -15.111, 0.0, 0.12, 0.15};
assertTrue(SortUtils.isSorted(doubles));
}

@Test
void isSortedFalse() {
Double[] array = {1.0, 3.0, -0.15};
assertFalse(SortUtils.isSorted(array));

Integer[] array2 = {14, 15, 16, 1};
assertFalse(SortUtils.isSorted(array2));

Integer[] array3 = {5, 4, 3, 2, 1};
assertFalse(SortUtils.isSorted(array3));
}
}