From edfb04f4cd659762cba38918278907fbecdf3a44 Mon Sep 17 00:00:00 2001 From: vzvu3k6k Date: Sun, 15 Nov 2020 02:37:51 +0900 Subject: [PATCH 1/5] Add benchmarkFramework for sort functions --- sorts/sorts_test.go | 54 ++++++++++----------------------------------- 1 file changed, 12 insertions(+), 42 deletions(-) diff --git a/sorts/sorts_test.go b/sorts/sorts_test.go index cacfdcd31..5b7a9fdb7 100644 --- a/sorts/sorts_test.go +++ b/sorts/sorts_test.go @@ -60,69 +60,39 @@ func TestSelection(t *testing.T) { //END TESTS -func BenchmarkBubble(b *testing.B) { +func benchmarkFramework(b *testing.B, sortingFunction func([]int) []int) { for i := 0; i < b.N; i++ { for _, test := range sortTests { - bubbleSort(test.input) + sortingFunction(test.input) } } } +func BenchmarkBubble(b *testing.B) { + benchmarkFramework(b, bubbleSort) +} func BenchmarkInsertion(b *testing.B) { - for i := 0; i < b.N; i++ { - for _, test := range sortTests { - InsertionSort(test.input) - } - } + benchmarkFramework(b, InsertionSort) } - func BenchmarkMerge(b *testing.B) { - for i := 0; i < b.N; i++ { - for _, test := range sortTests { - Mergesort(test.input) - } - } + benchmarkFramework(b, Mergesort) } - func BenchmarkHeap(b *testing.B) { - for i := 0; i < b.N; i++ { - for _, test := range sortTests { - HeapSort(test.input) - } - } + benchmarkFramework(b, HeapSort) } - func BenchmarkQuick(b *testing.B) { - for i := 0; i < b.N; i++ { - for _, test := range sortTests { - QuickSort(test.input) - } - } + benchmarkFramework(b, QuickSort) } - func BenchmarkShell(b *testing.B) { - for i := 0; i < b.N; i++ { - for _, test := range sortTests { - ShellSort(test.input) - } - } + benchmarkFramework(b, ShellSort) } - func BenchmarkRadix(b *testing.B) { - for i := 0; i < b.N; i++ { - for _, test := range sortTests { - RadixSort(test.input) - } - } + benchmarkFramework(b, RadixSort) } // Very Slow, consider commenting func BenchmarkSelection(b *testing.B) { - for i := 0; i < b.N; i++ { - for _, test := range sortTests { - SelectionSort(test.input) - } - } + benchmarkFramework(b, SelectionSort) } func compareSlices(a []int, b []int) (int, bool) { From 2c8fbf0bde3eb01018fae0058f73d758ead28322 Mon Sep 17 00:00:00 2001 From: vzvu3k6k Date: Sun, 15 Nov 2020 02:34:46 +0900 Subject: [PATCH 2/5] Fix sort testcase input sorted unintentionally A slice is a references to its underlying array. If a slice is passed as an argument and modified in a function, the original slice is also modified. As getSortedVersion and other sorting functions modify a given slice, testcase inputs are unintentionally sorted beforehand. To avoid that, passes a cloned slices to these functions. --- sorts/sorts_test.go | 7 +++++-- sorts/sorts_testcases.go | 11 +++++++++-- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/sorts/sorts_test.go b/sorts/sorts_test.go index 5b7a9fdb7..3cdd9b7a8 100644 --- a/sorts/sorts_test.go +++ b/sorts/sorts_test.go @@ -7,7 +7,7 @@ import ( func testFramework(t *testing.T, sortingFunction func([]int) []int) { for _, test := range sortTests { t.Run(test.name, func(t *testing.T) { - actual := sortingFunction(test.input) + actual := sortingFunction(cloneIntSlice(test.input)) pos, sorted := compareSlices(actual, test.expected) if !sorted { if pos == -1 { @@ -63,7 +63,10 @@ func TestSelection(t *testing.T) { func benchmarkFramework(b *testing.B, sortingFunction func([]int) []int) { for i := 0; i < b.N; i++ { for _, test := range sortTests { - sortingFunction(test.input) + b.StopTimer() + input := cloneIntSlice(test.input) + b.StartTimer() + sortingFunction(input) } } } diff --git a/sorts/sorts_testcases.go b/sorts/sorts_testcases.go index 56550cee9..132982785 100644 --- a/sorts/sorts_testcases.go +++ b/sorts/sorts_testcases.go @@ -70,6 +70,13 @@ func makeRandomSignedSlice(size int) []int { } func getSortedVersion(a []int) []int { - sort.Slice(a, func(i, j int) bool { return a[i] < a[j] }) - return a + b := cloneIntSlice(a) + sort.Slice(b, func(i, j int) bool { return b[i] < b[j] }) + return b +} + +func cloneIntSlice(src []int) []int { + vals := make([]int, len(src)) + copy(vals, src) + return vals } From 651bbbc854e043ecf0b543f36a959c6f9115b90d Mon Sep 17 00:00:00 2001 From: vzvu3k6k Date: Sun, 28 Feb 2021 02:55:47 +0900 Subject: [PATCH 3/5] Add comment to cloneIntSlice --- sorts/sorts_testcases.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sorts/sorts_testcases.go b/sorts/sorts_testcases.go index 132982785..947cf3336 100644 --- a/sorts/sorts_testcases.go +++ b/sorts/sorts_testcases.go @@ -75,6 +75,8 @@ func getSortedVersion(a []int) []int { return b } +// cloneIntSlice returns a copy of a given slice of int. +// Useful to protect a slice from in-place sorting functions. func cloneIntSlice(src []int) []int { vals := make([]int, len(src)) copy(vals, src) From 0bbc1db91ee0758516fd5a3d5f3c273c816498b8 Mon Sep 17 00:00:00 2001 From: vzvu3k6k Date: Sun, 28 Feb 2021 03:43:42 +0900 Subject: [PATCH 4/5] Reduce slice length to prevent timeout in test This timeout is caused by fixing an issue that slices of testcases were unintentionally being sorted. If array is sorted, the complexities of bubble sort and insertion sort are O(n), but in general they are O(n^2) and 500k is large enough to cause timeout. --- sorts/sorts_testcases.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/sorts/sorts_testcases.go b/sorts/sorts_testcases.go index 947cf3336..41295bbe9 100644 --- a/sorts/sorts_testcases.go +++ b/sorts/sorts_testcases.go @@ -13,8 +13,8 @@ type sortTest struct { name string } -var uarr []int = makeRandomUnsignedSlice(500_000) -var arr []int = makeRandomSignedSlice(500_000) +var uarr []int = makeRandomUnsignedSlice(5_000) +var arr []int = makeRandomSignedSlice(5_000) var sortTests = []sortTest{ //Sorted slice @@ -23,7 +23,7 @@ var sortTests = []sortTest{ //Reversed slice {[]int{10, 9, 8, 7, 6, 5, 4, 3, 2, 1}, []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, "Reversed Unsigned"}, - //500k unsigned int values sort + //5k unsigned int values sort {uarr, getSortedVersion(uarr), "Large Random Unsigned"}, //Sorted slice @@ -42,7 +42,7 @@ var sortTests = []sortTest{ {[]int{-5, 7, 4, -2, 6, 5, 8, 3, 2, -7, -1, 0, -3, 9, -6, -4, 10, 9, 1, -8, -9, -10}, []int{-10, -9, -8, -7, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 9, 10}, "Random order Signed"}, - //500k int values sort + //5k int values sort {arr, getSortedVersion(arr), "Large Random Signed"}, //Empty slice From b8f20b45d26373648abd0b379f7b6a0224cffd36 Mon Sep 17 00:00:00 2001 From: vzvu3k6k Date: Sun, 28 Feb 2021 13:06:48 +0900 Subject: [PATCH 5/5] Add comment to getSortedVersion Co-authored-by: Taj --- sorts/sorts_testcases.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sorts/sorts_testcases.go b/sorts/sorts_testcases.go index 41295bbe9..735ae3d87 100644 --- a/sorts/sorts_testcases.go +++ b/sorts/sorts_testcases.go @@ -69,6 +69,8 @@ func makeRandomSignedSlice(size int) []int { return vals } +// getSortedVersion Takes a slice of ints and returns a slice as a sorted (in +// ascending order) copy of the slice passed as the argument. func getSortedVersion(a []int) []int { b := cloneIntSlice(a) sort.Slice(b, func(i, j int) bool { return b[i] < b[j] })