mirror of
https://github.com/TheAlgorithms/Java.git
synced 2025-07-07 01:35:16 +08:00
refactor: cleanup CycleSort
(#5271)
* refactor: cleanup CycleSort. Adding test for it. Simplify code * refactor: CycleSortTest to directory file * tests: Adding more various tests cases for testing sorting algorithms * checkstyle: imports and whitespaces fixes * tests: removing boolean sorting * checkstyle: fix "eedBraces: 'if' construct must use '{}'s" * checkstyle: reduce "Too many static imports" --------- Co-authored-by: Alex Klymenko <alx@alx.com>
This commit is contained in:
@ -865,6 +865,7 @@
|
|||||||
* [CocktailShakerSortTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/sorts/CocktailShakerSortTest.java)
|
* [CocktailShakerSortTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/sorts/CocktailShakerSortTest.java)
|
||||||
* [CountingSortTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/sorts/CountingSortTest.java)
|
* [CountingSortTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/sorts/CountingSortTest.java)
|
||||||
* [CombSortTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/sorts/CombSortTest.java)
|
* [CombSortTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/sorts/CombSortTest.java)
|
||||||
|
* [CycleSortTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/sorts/CycleSortTest.java)
|
||||||
* [DualPivotQuickSortTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/sorts/DualPivotQuickSortTest.java)
|
* [DualPivotQuickSortTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/sorts/DualPivotQuickSortTest.java)
|
||||||
* [DutchNationalFlagSortTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/sorts/DutchNationalFlagSortTest.java)
|
* [DutchNationalFlagSortTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/sorts/DutchNationalFlagSortTest.java)
|
||||||
* [ExchangeSortTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/sorts/ExchangeSortTest.java)
|
* [ExchangeSortTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/sorts/ExchangeSortTest.java)
|
||||||
|
@ -1,100 +1,83 @@
|
|||||||
package com.thealgorithms.sorts;
|
package com.thealgorithms.sorts;
|
||||||
|
|
||||||
import static com.thealgorithms.sorts.SortUtils.less;
|
|
||||||
import static com.thealgorithms.sorts.SortUtils.print;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* This class implements the cycle sort algorithm.
|
||||||
|
* Cycle sort is an in-place sorting algorithm, unstable, and efficient for scenarios with limited memory usage.
|
||||||
* @author Podshivalov Nikita (https://github.com/nikitap492)
|
* @author Podshivalov Nikita (https://github.com/nikitap492)
|
||||||
*/
|
*/
|
||||||
class CycleSort implements SortAlgorithm {
|
class CycleSort implements SortAlgorithm {
|
||||||
|
/**
|
||||||
|
* Sorts an array of comparable elements using the cycle sort algorithm.
|
||||||
|
*
|
||||||
|
* @param array the array to be sorted
|
||||||
|
* @param <T> the type of elements in the array, must be comparable
|
||||||
|
* @return the sorted array
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public <T extends Comparable<T>> T[] sort(T[] arr) {
|
public <T extends Comparable<T>> T[] sort(T[] array) {
|
||||||
int n = arr.length;
|
for (int cycleStart = 0; cycleStart <= array.length - 2; cycleStart++) {
|
||||||
|
T item = array[cycleStart];
|
||||||
|
|
||||||
// traverse array elements
|
// Find the position where we put the element
|
||||||
for (int j = 0; j <= n - 2; j++) {
|
int pos = cycleStart;
|
||||||
// initialize item as starting point
|
for (int i = cycleStart + 1; i < array.length; i++) {
|
||||||
T item = arr[j];
|
if (SortUtils.less(array[i], item)) {
|
||||||
|
|
||||||
// Find position where we put the item.
|
|
||||||
int pos = j;
|
|
||||||
for (int i = j + 1; i < n; i++) {
|
|
||||||
if (less(arr[i], item)) {
|
|
||||||
pos++;
|
pos++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// If item is already in correct position
|
// If the item is already in the correct position
|
||||||
if (pos == j) {
|
if (pos == cycleStart) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ignore all duplicate elements
|
// Ignore all duplicate elements
|
||||||
while (item.compareTo(arr[pos]) == 0) {
|
while (item.compareTo(array[pos]) == 0) {
|
||||||
pos += 1;
|
pos++;
|
||||||
}
|
}
|
||||||
|
|
||||||
// put the item to it's right position
|
// Put the item to its correct position
|
||||||
if (pos != j) {
|
if (pos != cycleStart) {
|
||||||
item = replace(arr, pos, item);
|
item = replace(array, pos, item);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Rotate rest of the cycle
|
// Rotate the rest of the cycle
|
||||||
while (pos != j) {
|
while (pos != cycleStart) {
|
||||||
pos = j;
|
pos = cycleStart;
|
||||||
|
|
||||||
// Find position where we put the element
|
// Find the position where we put the element
|
||||||
for (int i = j + 1; i < n; i++) {
|
for (int i = cycleStart + 1; i < array.length; i++) {
|
||||||
if (less(arr[i], item)) {
|
if (SortUtils.less(array[i], item)) {
|
||||||
pos += 1;
|
pos++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ignore all duplicate elements
|
// Ignore all duplicate elements
|
||||||
while (item.compareTo(arr[pos]) == 0) {
|
while (item.compareTo(array[pos]) == 0) {
|
||||||
pos += 1;
|
pos++;
|
||||||
}
|
}
|
||||||
|
|
||||||
// put the item to it's right position
|
// Put the item to its correct position
|
||||||
if (item != arr[pos]) {
|
if (item != array[pos]) {
|
||||||
item = replace(arr, pos, item);
|
item = replace(array, pos, item);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return array;
|
||||||
return arr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private <T extends Comparable<T>> T replace(T[] arr, int pos, T item) {
|
/**
|
||||||
T temp = item;
|
* Replaces an element in the array with the given item and returns the replaced item.
|
||||||
item = arr[pos];
|
*
|
||||||
arr[pos] = temp;
|
* @param array the array in which the replacement will occur
|
||||||
return item;
|
* @param pos the position at which the replacement will occur
|
||||||
}
|
* @param item the item to be placed in the array
|
||||||
|
* @param <T> the type of elements in the array, must be comparable
|
||||||
public static void main(String[] args) {
|
* @return the replaced item
|
||||||
Integer[] arr = {
|
*/
|
||||||
4,
|
private <T extends Comparable<T>> T replace(T[] array, int pos, T item) {
|
||||||
23,
|
T replacedItem = array[pos];
|
||||||
6,
|
array[pos] = item;
|
||||||
78,
|
return replacedItem;
|
||||||
1,
|
|
||||||
26,
|
|
||||||
11,
|
|
||||||
23,
|
|
||||||
0,
|
|
||||||
-6,
|
|
||||||
3,
|
|
||||||
54,
|
|
||||||
231,
|
|
||||||
9,
|
|
||||||
12,
|
|
||||||
};
|
|
||||||
CycleSort cycleSort = new CycleSort();
|
|
||||||
cycleSort.sort(arr);
|
|
||||||
|
|
||||||
System.out.println("After sort : ");
|
|
||||||
print(arr);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
8
src/test/java/com/thealgorithms/sorts/CycleSortTest.java
Normal file
8
src/test/java/com/thealgorithms/sorts/CycleSortTest.java
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
package com.thealgorithms.sorts;
|
||||||
|
|
||||||
|
public class CycleSortTest extends SortingAlgorithmTest {
|
||||||
|
@Override
|
||||||
|
SortAlgorithm getSortAlgorithm() {
|
||||||
|
return new CycleSort();
|
||||||
|
}
|
||||||
|
}
|
@ -1,11 +1,14 @@
|
|||||||
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.assertEquals;
|
||||||
import static org.junit.jupiter.api.Assertions.assertIterableEquals;
|
import static org.junit.jupiter.api.Assertions.assertIterableEquals;
|
||||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Objects;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
public abstract class SortingAlgorithmTest {
|
public abstract class SortingAlgorithmTest {
|
||||||
@ -171,4 +174,192 @@ public abstract class SortingAlgorithmTest {
|
|||||||
List<Double> sorted = getSortAlgorithm().sort(list);
|
List<Double> sorted = getSortAlgorithm().sort(list);
|
||||||
assertTrue(SortUtils.isSorted(sorted));
|
assertTrue(SortUtils.isSorted(sorted));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void shouldAcceptWhenArrayWithAllIdenticalValuesIsPassed() {
|
||||||
|
Integer[] array = {1, 1, 1, 1};
|
||||||
|
Integer[] sortedArray = getSortAlgorithm().sort(array);
|
||||||
|
assertArrayEquals(new Integer[] {1, 1, 1, 1}, sortedArray);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void shouldAcceptWhenListWithAllIdenticalValuesIsPassed() {
|
||||||
|
List<Integer> list = Arrays.asList(1, 1, 1, 1);
|
||||||
|
List<Integer> sortedList = getSortAlgorithm().sort(list);
|
||||||
|
assertEquals(Arrays.asList(1, 1, 1, 1), sortedList);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void shouldAcceptWhenArrayWithMixedPositiveAndNegativeValuesIsPassed() {
|
||||||
|
Integer[] array = {-1, 3, -2, 5, 0};
|
||||||
|
Integer[] sortedArray = getSortAlgorithm().sort(array);
|
||||||
|
assertArrayEquals(new Integer[] {-2, -1, 0, 3, 5}, sortedArray);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void shouldAcceptWhenListWithMixedPositiveAndNegativeValuesIsPassed() {
|
||||||
|
List<Integer> list = Arrays.asList(-1, 3, -2, 5, 0);
|
||||||
|
List<Integer> sortedList = getSortAlgorithm().sort(list);
|
||||||
|
assertEquals(Arrays.asList(-2, -1, 0, 3, 5), sortedList);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void shouldAcceptWhenArrayWithLargeNumbersIsPassed() {
|
||||||
|
Long[] array = {10000000000L, 9999999999L, 10000000001L};
|
||||||
|
Long[] sortedArray = getSortAlgorithm().sort(array);
|
||||||
|
assertArrayEquals(new Long[] {9999999999L, 10000000000L, 10000000001L}, sortedArray);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void shouldAcceptWhenListWithLargeNumbersIsPassed() {
|
||||||
|
List<Long> list = Arrays.asList(10000000000L, 9999999999L, 10000000001L);
|
||||||
|
List<Long> sortedList = getSortAlgorithm().sort(list);
|
||||||
|
assertEquals(Arrays.asList(9999999999L, 10000000000L, 10000000001L), sortedList);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void shouldAcceptWhenArrayWithMaxIntegerValuesIsPassed() {
|
||||||
|
Integer[] array = {Integer.MAX_VALUE, Integer.MIN_VALUE, 0};
|
||||||
|
Integer[] sortedArray = getSortAlgorithm().sort(array);
|
||||||
|
assertArrayEquals(new Integer[] {Integer.MIN_VALUE, 0, Integer.MAX_VALUE}, sortedArray);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void shouldAcceptWhenListWithMaxIntegerValuesIsPassed() {
|
||||||
|
List<Integer> list = Arrays.asList(Integer.MAX_VALUE, Integer.MIN_VALUE, 0);
|
||||||
|
List<Integer> sortedList = getSortAlgorithm().sort(list);
|
||||||
|
assertEquals(Arrays.asList(Integer.MIN_VALUE, 0, Integer.MAX_VALUE), sortedList);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void shouldAcceptWhenArrayWithMinIntegerValuesIsPassed() {
|
||||||
|
Integer[] array = {Integer.MIN_VALUE, Integer.MAX_VALUE, 0};
|
||||||
|
Integer[] sortedArray = getSortAlgorithm().sort(array);
|
||||||
|
assertArrayEquals(new Integer[] {Integer.MIN_VALUE, 0, Integer.MAX_VALUE}, sortedArray);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void shouldAcceptWhenListWithMinIntegerValuesIsPassed() {
|
||||||
|
List<Integer> list = Arrays.asList(Integer.MIN_VALUE, Integer.MAX_VALUE, 0);
|
||||||
|
List<Integer> sortedList = getSortAlgorithm().sort(list);
|
||||||
|
assertEquals(Arrays.asList(Integer.MIN_VALUE, 0, Integer.MAX_VALUE), sortedList);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void shouldAcceptWhenArrayWithSpecialCharactersIsPassed() {
|
||||||
|
String[] array = {"!", "@", "#", "$"};
|
||||||
|
String[] sortedArray = getSortAlgorithm().sort(array);
|
||||||
|
assertArrayEquals(new String[] {"!", "#", "$", "@"}, sortedArray);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void shouldAcceptWhenListWithSpecialCharactersIsPassed() {
|
||||||
|
List<String> list = Arrays.asList("!", "@", "#", "$");
|
||||||
|
List<String> sortedList = getSortAlgorithm().sort(list);
|
||||||
|
assertEquals(Arrays.asList("!", "#", "$", "@"), sortedList);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void shouldAcceptWhenArrayWithMixedCaseStringsIsPassed() {
|
||||||
|
String[] array = {"apple", "Banana", "cherry", "Date"};
|
||||||
|
String[] sortedArray = getSortAlgorithm().sort(array);
|
||||||
|
assertArrayEquals(new String[] {"Banana", "Date", "apple", "cherry"}, sortedArray);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void shouldAcceptWhenListWithMixedCaseStringsIsPassed() {
|
||||||
|
List<String> list = Arrays.asList("apple", "Banana", "cherry", "Date");
|
||||||
|
List<String> sortedList = getSortAlgorithm().sort(list);
|
||||||
|
assertEquals(Arrays.asList("Banana", "Date", "apple", "cherry"), sortedList);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void shouldHandleArrayWithNullValues() {
|
||||||
|
Integer[] array = {3, null, 2, null, 1};
|
||||||
|
org.junit.jupiter.api.Assertions.assertThrows(NullPointerException.class, () -> getSortAlgorithm().sort(array));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void shouldHandleListWithNullValues() {
|
||||||
|
List<Integer> list = Arrays.asList(3, null, 2, null, 1);
|
||||||
|
org.junit.jupiter.api.Assertions.assertThrows(NullPointerException.class, () -> getSortAlgorithm().sort(list));
|
||||||
|
}
|
||||||
|
|
||||||
|
static class CustomObject implements Comparable<CustomObject> {
|
||||||
|
int value;
|
||||||
|
|
||||||
|
CustomObject(int value) {
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int compareTo(CustomObject o) {
|
||||||
|
return Integer.compare(this.value, o.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "CustomObject{"
|
||||||
|
+ "value=" + value + '}';
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
if (this == o) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (o == null || getClass() != o.getClass()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
CustomObject that = (CustomObject) o;
|
||||||
|
return value == that.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return Objects.hashCode(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void shouldHandleArrayOfCustomObjects() {
|
||||||
|
CustomObject[] array = {new CustomObject(3), new CustomObject(1), new CustomObject(2)};
|
||||||
|
CustomObject[] sortedArray = getSortAlgorithm().sort(array);
|
||||||
|
assertArrayEquals(new CustomObject[] {new CustomObject(1), new CustomObject(2), new CustomObject(3)}, sortedArray);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void shouldHandleListOfCustomObjects() {
|
||||||
|
List<CustomObject> list = Arrays.asList(new CustomObject(3), new CustomObject(1), new CustomObject(2));
|
||||||
|
List<CustomObject> sortedList = getSortAlgorithm().sort(list);
|
||||||
|
assertEquals(Arrays.asList(new CustomObject(1), new CustomObject(2), new CustomObject(3)), sortedList);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void shouldHandleArrayOfFloatingPointNumbers() {
|
||||||
|
Double[] array = {3.3, 2.2, 1.1, Double.NaN, Double.POSITIVE_INFINITY, Double.NEGATIVE_INFINITY};
|
||||||
|
Double[] sortedArray = getSortAlgorithm().sort(array);
|
||||||
|
assertArrayEquals(new Double[] {Double.NEGATIVE_INFINITY, 1.1, 2.2, 3.3, Double.POSITIVE_INFINITY, Double.NaN}, sortedArray);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void shouldHandleListOfFloatingPointNumbers() {
|
||||||
|
List<Double> list = Arrays.asList(3.3, 2.2, 1.1, Double.NaN, Double.POSITIVE_INFINITY, Double.NEGATIVE_INFINITY);
|
||||||
|
List<Double> sortedList = getSortAlgorithm().sort(list);
|
||||||
|
assertEquals(Arrays.asList(Double.NEGATIVE_INFINITY, 1.1, 2.2, 3.3, Double.POSITIVE_INFINITY, Double.NaN), sortedList);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void shouldHandleArrayWithEmptyStrings() {
|
||||||
|
String[] array = {"apple", "", "banana", ""};
|
||||||
|
String[] sortedArray = getSortAlgorithm().sort(array);
|
||||||
|
assertArrayEquals(new String[] {"", "", "apple", "banana"}, sortedArray);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void shouldHandleListWithEmptyStrings() {
|
||||||
|
List<String> list = Arrays.asList("apple", "", "banana", "");
|
||||||
|
List<String> sortedList = getSortAlgorithm().sort(list);
|
||||||
|
assertEquals(Arrays.asList("", "", "apple", "banana"), sortedList);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user