From cf76698bccd0679f958cd649bd6668b43f2391e0 Mon Sep 17 00:00:00 2001 From: Antonia Strack Date: Thu, 21 Apr 2022 10:50:06 +0200 Subject: [PATCH 1/4] Add WiggleSort --- .../com/thealgorithms/sorts/WiggleSort.java | 90 +++++++++++++++++++ 1 file changed, 90 insertions(+) create mode 100644 src/main/java/com/thealgorithms/sorts/WiggleSort.java diff --git a/src/main/java/com/thealgorithms/sorts/WiggleSort.java b/src/main/java/com/thealgorithms/sorts/WiggleSort.java new file mode 100644 index 000000000000..a3d57f84bcdc --- /dev/null +++ b/src/main/java/com/thealgorithms/sorts/WiggleSort.java @@ -0,0 +1,90 @@ +package com.thealgorithms.sorts; + +import com.thealgorithms.searches.QuickSelect; + +import java.util.Arrays; + +import static com.thealgorithms.maths.Ceil.ceil; +import static com.thealgorithms.maths.Floor.floor; +import static com.thealgorithms.searches.QuickSelect.select; + +/** + * A wriggle sort implementation based on John L.s' answer in + * https://cs.stackexchange.com/questions/125372/how-to-wiggle-sort-an-array-in-linear-time-complexity + */ +public class WiggleSort implements SortAlgorithm { + @Override + public > T[] sort(T[] unsorted) { + return wiggleSort(unsorted); + } + + private int mapIndex(int index, int n){ + return (2 * index) % (n-1 | 1); + } + + /** + * Modified Dutch National Flag Sort. See also: sorts/DutchNationalFlagSort + * @param sortThis array to sort into group "greater", "equal" and "smaller" than median + * @param median defines the groups + * @param extends interface Comparable + */ + private > void triColorSort(T[] sortThis, T median){ + int n = sortThis.length; + int i = 0; + int j = 0; + int k = n - 1; + while (j <= k) { + if (0 > sortThis[mapIndex(j, n)].compareTo(median)) { + SortUtils.swap(sortThis, mapIndex(j, n), mapIndex(i, n)); + i++; + j++; + } else if (0 < sortThis[mapIndex(j, n)].compareTo(median)) { + SortUtils.swap(sortThis, mapIndex(j, n), mapIndex(k, n)); + k--; + } else { + j++; + } + } + } + + private > T[] wiggleSort(T[] sortThis) { + // find the median using quickSelect (if the result isn't in the array, use the next greater value) + T median; + + if(sortThis.length % 2 == 0) { + median = select(Arrays.asList(sortThis), (int) (sortThis.length / 2.0)); + } else { + median = select(Arrays.asList(sortThis), (int) floor(sortThis.length / 2.0)); + } + + System.out.println(median); + + for(int i = 0; i < sortThis.length; i++){ + int numMedians = 0; + if(0 == sortThis[i].compareTo(median)){ + numMedians++; + } + if( numMedians > ceil(sortThis.length/ 2.0)){ + throw new IllegalArgumentException("No more than half the number of values may be the same."); + } + } + + triColorSort(sortThis, median); + return sortThis; + } + public static void main(String[] args) { + WiggleSort wiggleSort = new WiggleSort(); + + Integer[] integers0 = new Integer[]{1, 2, 3, 4, 5}; + Integer[] integers1 = new Integer[]{1, 2, 1, 1, 5}; + String[] strings = new String[]{"a", "b", "e", "d"}; + + wiggleSort.sort(integers0); + wiggleSort.sort(integers1); + wiggleSort.sort(strings); + + System.out.println(Arrays.toString(integers0)); + System.out.println(Arrays.toString(integers1)); + System.out.println(Arrays.toString(strings)); + } +} From c95f7f0bf746566a436b3c4c4eee73d5e1f611c1 Mon Sep 17 00:00:00 2001 From: Antonia Strack Date: Thu, 21 Apr 2022 10:50:42 +0200 Subject: [PATCH 2/4] Add WiggleSort --- src/main/java/com/thealgorithms/sorts/WiggleSort.java | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/main/java/com/thealgorithms/sorts/WiggleSort.java b/src/main/java/com/thealgorithms/sorts/WiggleSort.java index a3d57f84bcdc..ea86bd630ff1 100644 --- a/src/main/java/com/thealgorithms/sorts/WiggleSort.java +++ b/src/main/java/com/thealgorithms/sorts/WiggleSort.java @@ -1,7 +1,5 @@ package com.thealgorithms.sorts; -import com.thealgorithms.searches.QuickSelect; - import java.util.Arrays; import static com.thealgorithms.maths.Ceil.ceil; @@ -59,12 +57,12 @@ private > T[] wiggleSort(T[] sortThis) { System.out.println(median); - for(int i = 0; i < sortThis.length; i++){ + for (T sortThi : sortThis) { int numMedians = 0; - if(0 == sortThis[i].compareTo(median)){ + if (0 == sortThi.compareTo(median)) { numMedians++; } - if( numMedians > ceil(sortThis.length/ 2.0)){ + if (numMedians > ceil(sortThis.length / 2.0)) { throw new IllegalArgumentException("No more than half the number of values may be the same."); } } From b6b154eaefdfda44150e4f8a53d1f1c8d86bb52c Mon Sep 17 00:00:00 2001 From: Antonia Strack Date: Sun, 24 Apr 2022 00:51:30 +0200 Subject: [PATCH 3/4] add Tests, remove main and outputs, fix bug, add comment, fix typo --- .../com/thealgorithms/sorts/WiggleSort.java | 33 +++--------- .../thealgorithms/sorts/WiggleSortTest.java | 53 +++++++++++++++++++ 2 files changed, 60 insertions(+), 26 deletions(-) create mode 100644 src/test/java/com/thealgorithms/sorts/WiggleSortTest.java diff --git a/src/main/java/com/thealgorithms/sorts/WiggleSort.java b/src/main/java/com/thealgorithms/sorts/WiggleSort.java index ea86bd630ff1..d9041b6e3d93 100644 --- a/src/main/java/com/thealgorithms/sorts/WiggleSort.java +++ b/src/main/java/com/thealgorithms/sorts/WiggleSort.java @@ -7,8 +7,10 @@ import static com.thealgorithms.searches.QuickSelect.select; /** - * A wriggle sort implementation based on John L.s' answer in + * A wiggle sort implementation based on John L.s' answer in * https://cs.stackexchange.com/questions/125372/how-to-wiggle-sort-an-array-in-linear-time-complexity + * Not all arrays are wiggle-sortable. This algorithm will find some obviously not wiggle-sortable arrays and throw an error, + * but there are some exceptions that won't be caught, for example [1, 2, 2]. */ public class WiggleSort implements SortAlgorithm { @Override @@ -17,7 +19,7 @@ public > T[] sort(T[] unsorted) { } private int mapIndex(int index, int n){ - return (2 * index) % (n-1 | 1); + return ((2 * index + 1) % (n | 1)) ; } /** @@ -32,11 +34,11 @@ private > void triColorSort(T[] sortThis, T median){ int j = 0; int k = n - 1; while (j <= k) { - if (0 > sortThis[mapIndex(j, n)].compareTo(median)) { + if (0 < sortThis[mapIndex(j, n)].compareTo(median)) { SortUtils.swap(sortThis, mapIndex(j, n), mapIndex(i, n)); i++; j++; - } else if (0 < sortThis[mapIndex(j, n)].compareTo(median)) { + } else if (0 > sortThis[mapIndex(j, n)].compareTo(median)) { SortUtils.swap(sortThis, mapIndex(j, n), mapIndex(k, n)); k--; } else { @@ -49,13 +51,7 @@ private > T[] wiggleSort(T[] sortThis) { // find the median using quickSelect (if the result isn't in the array, use the next greater value) T median; - if(sortThis.length % 2 == 0) { - median = select(Arrays.asList(sortThis), (int) (sortThis.length / 2.0)); - } else { - median = select(Arrays.asList(sortThis), (int) floor(sortThis.length / 2.0)); - } - - System.out.println(median); + median = select(Arrays.asList(sortThis), (int) floor(sortThis.length / 2.0) -1); for (T sortThi : sortThis) { int numMedians = 0; @@ -70,19 +66,4 @@ private > T[] wiggleSort(T[] sortThis) { triColorSort(sortThis, median); return sortThis; } - public static void main(String[] args) { - WiggleSort wiggleSort = new WiggleSort(); - - Integer[] integers0 = new Integer[]{1, 2, 3, 4, 5}; - Integer[] integers1 = new Integer[]{1, 2, 1, 1, 5}; - String[] strings = new String[]{"a", "b", "e", "d"}; - - wiggleSort.sort(integers0); - wiggleSort.sort(integers1); - wiggleSort.sort(strings); - - System.out.println(Arrays.toString(integers0)); - System.out.println(Arrays.toString(integers1)); - System.out.println(Arrays.toString(strings)); - } } diff --git a/src/test/java/com/thealgorithms/sorts/WiggleSortTest.java b/src/test/java/com/thealgorithms/sorts/WiggleSortTest.java new file mode 100644 index 000000000000..eee1c0b339f6 --- /dev/null +++ b/src/test/java/com/thealgorithms/sorts/WiggleSortTest.java @@ -0,0 +1,53 @@ +package com.thealgorithms.sorts; + +import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertArrayEquals; + + +public class WiggleSortTest { + @Test + void WiggleTestNumbersEven(){ + WiggleSort wiggleSort = new WiggleSort(); + Integer[] values = {1, 2, 3, 4}; + Integer[] result = {2, 4, 1, 3}; + wiggleSort.sort(values); + assertArrayEquals(values, result); + } + + @Test + void WiggleTestNumbersOdd(){ + WiggleSort wiggleSort = new WiggleSort(); + Integer[] values = {1, 2, 3, 4, 5}; + Integer[] result = {3, 4, 2, 5, 1}; + wiggleSort.sort(values); + assertArrayEquals(values, result); + + } + + @Test + void WiggleTestNumbersOddDuplicates(){ + WiggleSort wiggleSort = new WiggleSort(); + Integer[] values = {7, 2, 2, 2, 5}; + Integer[] result = {2, 7, 2, 5, 2}; + wiggleSort.sort(values); + assertArrayEquals(values, result); + } + + @Test + void WiggleTestNumbersEvenDuplicates(){ + WiggleSort wiggleSort = new WiggleSort(); + Integer[] values = {1, 2, 4, 4}; + Integer[] result = {2, 4, 1, 4}; + wiggleSort.sort(values); + assertArrayEquals(values, result); + } + + @Test + void WiggleTestStrings(){ + WiggleSort wiggleSort = new WiggleSort(); + String[] values = {"a", "b", "d", "c"}; + String[] result = {"b", "c", "a", "d"}; + wiggleSort.sort(values); + assertArrayEquals(values, result); + } +} From a696d768614c42d89daff210117a43cf15329083 Mon Sep 17 00:00:00 2001 From: Antonia Strack Date: Mon, 25 Apr 2022 15:02:16 +0200 Subject: [PATCH 4/4] remove off by-one-error for odd arrays, add link explaining the error and further discussion --- .../com/thealgorithms/sorts/WiggleSort.java | 33 +++++++++++++------ .../thealgorithms/sorts/WiggleSortTest.java | 30 ++++++++++++++--- 2 files changed, 49 insertions(+), 14 deletions(-) diff --git a/src/main/java/com/thealgorithms/sorts/WiggleSort.java b/src/main/java/com/thealgorithms/sorts/WiggleSort.java index d9041b6e3d93..b368c74422a9 100644 --- a/src/main/java/com/thealgorithms/sorts/WiggleSort.java +++ b/src/main/java/com/thealgorithms/sorts/WiggleSort.java @@ -9,6 +9,7 @@ /** * A wiggle sort implementation based on John L.s' answer in * https://cs.stackexchange.com/questions/125372/how-to-wiggle-sort-an-array-in-linear-time-complexity + * Also have a look at: https://cs.stackexchange.com/questions/125372/how-to-wiggle-sort-an-array-in-linear-time-complexity?noredirect=1&lq=1 * Not all arrays are wiggle-sortable. This algorithm will find some obviously not wiggle-sortable arrays and throw an error, * but there are some exceptions that won't be caught, for example [1, 2, 2]. */ @@ -18,17 +19,18 @@ public > T[] sort(T[] unsorted) { return wiggleSort(unsorted); } - private int mapIndex(int index, int n){ - return ((2 * index + 1) % (n | 1)) ; + private int mapIndex(int index, int n) { + return ((2 * index + 1) % (n | 1)); } /** * Modified Dutch National Flag Sort. See also: sorts/DutchNationalFlagSort + * * @param sortThis array to sort into group "greater", "equal" and "smaller" than median - * @param median defines the groups - * @param extends interface Comparable + * @param median defines the groups + * @param extends interface Comparable */ - private > void triColorSort(T[] sortThis, T median){ + private > void triColorSort(T[] sortThis, T median) { int n = sortThis.length; int i = 0; int j = 0; @@ -51,19 +53,30 @@ private > T[] wiggleSort(T[] sortThis) { // find the median using quickSelect (if the result isn't in the array, use the next greater value) T median; - median = select(Arrays.asList(sortThis), (int) floor(sortThis.length / 2.0) -1); + median = select(Arrays.asList(sortThis), (int) floor(sortThis.length / 2.0)); + + int numMedians = 0; for (T sortThi : sortThis) { - int numMedians = 0; if (0 == sortThi.compareTo(median)) { numMedians++; } - if (numMedians > ceil(sortThis.length / 2.0)) { - throw new IllegalArgumentException("No more than half the number of values may be the same."); + } + // added condition preventing off-by-one errors for odd arrays. + // https://cs.stackexchange.com/questions/150886/how-to-find-wiggle-sortable-arrays-did-i-misunderstand-john-l-s-answer?noredirect=1&lq=1 + if (sortThis.length % 2 == 1 && numMedians == ceil(sortThis.length / 2.0)) { + T smallestValue = select(Arrays.asList(sortThis), 0); + if (!(0 == smallestValue.compareTo(median))) { + throw new IllegalArgumentException("For odd Arrays if the median appears ceil(n/2) times, " + + "the median has to be the smallest values in the array."); } } + if (numMedians > ceil(sortThis.length / 2.0)) { + throw new IllegalArgumentException("No more than half the number of values may be the same."); + + } triColorSort(sortThis, median); return sortThis; } -} +} \ No newline at end of file diff --git a/src/test/java/com/thealgorithms/sorts/WiggleSortTest.java b/src/test/java/com/thealgorithms/sorts/WiggleSortTest.java index eee1c0b339f6..336170a33535 100644 --- a/src/test/java/com/thealgorithms/sorts/WiggleSortTest.java +++ b/src/test/java/com/thealgorithms/sorts/WiggleSortTest.java @@ -1,6 +1,9 @@ package com.thealgorithms.sorts; import org.junit.jupiter.api.Test; + +import java.util.Arrays; + import static org.junit.jupiter.api.Assertions.assertArrayEquals; @@ -9,7 +12,7 @@ public class WiggleSortTest { void WiggleTestNumbersEven(){ WiggleSort wiggleSort = new WiggleSort(); Integer[] values = {1, 2, 3, 4}; - Integer[] result = {2, 4, 1, 3}; + Integer[] result = {1, 4, 2, 3}; wiggleSort.sort(values); assertArrayEquals(values, result); } @@ -18,7 +21,7 @@ void WiggleTestNumbersEven(){ void WiggleTestNumbersOdd(){ WiggleSort wiggleSort = new WiggleSort(); Integer[] values = {1, 2, 3, 4, 5}; - Integer[] result = {3, 4, 2, 5, 1}; + Integer[] result = {3, 5, 1, 4, 2}; wiggleSort.sort(values); assertArrayEquals(values, result); @@ -33,11 +36,30 @@ void WiggleTestNumbersOddDuplicates(){ assertArrayEquals(values, result); } + @Test + void WiggleTestNumbersOddMultipleDuplicates(){ + WiggleSort wiggleSort = new WiggleSort(); + Integer[] values = {1, 1, 2, 2, 5}; + Integer[] result = {2, 5, 1, 2, 1}; + wiggleSort.sort(values); + assertArrayEquals(values, result); + } + + @Test + void WiggleTestNumbersEvenMultipleDuplicates(){ + WiggleSort wiggleSort = new WiggleSort(); + Integer[] values = {1, 1, 2, 2, 2, 5}; + Integer[] result = {2, 5, 1, 2, 1, 2}; + wiggleSort.sort(values); + System.out.println(Arrays.toString(values)); + assertArrayEquals(values, result); + } + @Test void WiggleTestNumbersEvenDuplicates(){ WiggleSort wiggleSort = new WiggleSort(); Integer[] values = {1, 2, 4, 4}; - Integer[] result = {2, 4, 1, 4}; + Integer[] result = {1, 4, 2, 4}; wiggleSort.sort(values); assertArrayEquals(values, result); } @@ -46,7 +68,7 @@ void WiggleTestNumbersEvenDuplicates(){ void WiggleTestStrings(){ WiggleSort wiggleSort = new WiggleSort(); String[] values = {"a", "b", "d", "c"}; - String[] result = {"b", "c", "a", "d"}; + String[] result = {"a", "d", "b", "c"}; wiggleSort.sort(values); assertArrayEquals(values, result); }