Skip to content

Commit 72a682a

Browse files
author
mattan
committed
- Added new test cases for sort, with negative integers
- Changed sort function names to uppercase where they were lowercase - Enclosed each iteration in t.Run() to ensure all tests are executed - Added a unified test framework to avoid code duplication - Fixed Radix sort to deal with negative numbers
1 parent efedf3a commit 72a682a

File tree

7 files changed

+78
-130
lines changed

7 files changed

+78
-130
lines changed

sorts/heap_sort.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ func (h maxHeap) MaxHeapify(i int) {
3333

3434
func (h maxHeap) size() int { return h.heapSize } // ???
3535

36-
func heapSort(slice []int) []int {
36+
func HeapSort(slice []int) []int {
3737
h := buildMaxHeap(slice)
3838
//log.Println(slice)
3939
for i := len(h.slice) - 1; i >= 1; i-- {

sorts/insertion_sort.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
//Package sorts a package for demonstrating sorting algorithms in Go
22
package sorts
33

4-
func insertionSort(arr []int) []int {
4+
func InsertionSort(arr []int) []int {
55
for out := 1; out < len(arr); out++ {
66
temp := arr[out]
77
in := out

sorts/quick_sort.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import (
55
"math/rand"
66
)
77

8-
func quickSort(arr []int) []int {
8+
func QuickSort(arr []int) []int {
99

1010
if len(arr) <= 1 {
1111
return arr
@@ -28,8 +28,8 @@ func quickSort(arr []int) []int {
2828
}
2929
}
3030

31-
lowPart = quickSort(lowPart)
32-
highPart = quickSort(highPart)
31+
lowPart = QuickSort(lowPart)
32+
highPart = QuickSort(highPart)
3333

3434
lowPart = append(lowPart, middlePart...)
3535
lowPart = append(lowPart, highPart...)

sorts/radix_sort.go

Lines changed: 6 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,7 @@
11
package sorts
22

3-
import (
4-
"math"
5-
)
6-
73
func max(arr []int) int {
8-
max := math.MinInt64
4+
max := arr[0]
95
for _, item := range arr {
106
if item > max {
117
max = item
@@ -17,10 +13,10 @@ func max(arr []int) int {
1713
func countSort(arr []int, exp int) []int {
1814
var digits [10]int
1915
var output = make([]int, len(arr))
16+
2017
for _, item := range arr {
2118
digits[(item/exp)%10]++
2219
}
23-
2420
for i := 1; i < 10; i++ {
2521
digits[i] += digits[i-1]
2622
}
@@ -33,18 +29,10 @@ func countSort(arr []int, exp int) []int {
3329
return output
3430
}
3531

36-
func RadixSort(arr []int) []int {
37-
maxElement := max(arr)
38-
for exp := 1; maxElement/exp > 0; exp *= 10 {
39-
arr = countSort(arr, exp)
40-
}
41-
return arr
42-
}
43-
44-
// The following adds support for signed ints
45-
/*
46-
4732
func unsignedRadixSort(arr []int) []int {
33+
if len(arr) == 0 {
34+
return arr
35+
}
4836
maxElement := max(arr)
4937
for exp := 1; maxElement/exp > 0; exp *= 10 {
5038
arr = countSort(arr, exp)
@@ -65,9 +53,8 @@ func RadixSort(arr []int) []int {
6553
negatives = unsignedRadixSort(negatives)
6654

6755
// Reverse the negative array and restore signs
68-
for i, j := 0, len(negatives) -1; i < j; i,j = i + 1, j - 1 {
56+
for i, j := 0, len(negatives)-1; i <= j; i, j = i+1, j-1 {
6957
negatives[i], negatives[j] = -negatives[j], -negatives[i]
7058
}
7159
return append(negatives, unsignedRadixSort(nonNegatives)...)
7260
}
73-
*/

sorts/shell_sort.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
//Package sorts a package for demonstrating sorting algorithms in Go
22
package sorts
33

4-
func shellSort(arr []int) []int {
4+
func ShellSort(arr []int) []int {
55
for d := int(len(arr) / 2); d > 0; d /= 2 {
66
for i := d; i < len(arr); i++ {
77
for j := i; j >= d && arr[j-d] > arr[j]; j -= d {

sorts/sorts_case_test.go

Lines changed: 30 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -13,25 +13,39 @@ type sortTest struct {
1313
name string
1414
}
1515

16+
var uarr []int = makeRandNonNegativeArray(500_000)
1617
var arr []int = makeRandArray(500_000)
1718

1819
var sortTests = []sortTest{
1920
//Sorted slice
20-
{[]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10},
21-
[]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, "Sorted"},
21+
{[]int{-10, -9, -8, -7, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10},
22+
[]int{-10, -9, -8, -7, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, "Sorted"},
23+
2224
//Reversed slice
23-
{[]int{10, 9, 8, 7, 6, 5, 4, 3, 2, 1},
24-
[]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, "Reversed"},
25+
{[]int{10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, -1, -2, -3, -4, -5, -6, -7, -8, -9, -10},
26+
[]int{-10, -9, -8, -7, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, "Reversed"},
27+
28+
//Reversed slice, even length
29+
{[]int{10, 9, 8, 7, 6, 5, 4, 3, 2, 1, -1, -2, -3, -4, -5, -6, -7, -8, -9, -10},
30+
[]int{-10, -9, -8, -7, -6, -5, -4, -3, -2, -1, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, "Reversed Even"},
31+
32+
//Random order with repetitions
33+
{[]int{-5, 7, 4, -2, 6, 5, 8, 3, 2, -7, -1, 0, -3, 9, -6, -4, 10, 9, 1, -8, -9, -10},
34+
[]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 with repetitions"},
35+
2536
//Empty slice
2637
{[]int{}, []int{}, "Empty"},
2738
//Single-entry slice
2839
{[]int{1}, []int{1}, "Singleton"},
2940

30-
//500k values sort
31-
{arr, getSortedVersion(arr), "Large Random"},
41+
//500k non negative int values sort
42+
{uarr, getSortedVersion(uarr), "Large Random"},
43+
44+
//500k int values sort
45+
{arr, getSortedVersion(arr), "Large Random2"},
3246
}
3347

34-
func makeRandArray(size int) []int {
48+
func makeRandNonNegativeArray(size int) []int {
3549
vals := make([]int, size)
3650
for i := 0; i < size; i++ {
3751
temp, _ := rand.Int(rand.Reader, big.NewInt(int64(size)))
@@ -40,6 +54,15 @@ func makeRandArray(size int) []int {
4054
return vals
4155
}
4256

57+
func makeRandArray(size int) []int {
58+
vals := make([]int, size)
59+
for i := 0; i < size; i++ {
60+
temp, _ := rand.Int(rand.Reader, big.NewInt(int64(size)))
61+
vals[i] = int(temp.Int64()) - 250_000
62+
}
63+
return vals
64+
}
65+
4366
func getSortedVersion(a []int) []int {
4467
sort.Slice(a, func(i, j int) bool { return a[i] < a[j] })
4568
return a

sorts/sorts_test.go

Lines changed: 36 additions & 98 deletions
Original file line numberDiff line numberDiff line change
@@ -1,125 +1,63 @@
11
package sorts
22

3-
import "testing"
3+
import (
4+
"fmt"
5+
"testing"
6+
)
47

5-
//BEGIN TESTS
6-
7-
func TestBubble(t *testing.T) {
8+
func testFramework(t *testing.T, sortingFunction func([]int) []int) {
89
for _, test := range sortTests {
9-
actual := bubbleSort(test.input)
10-
pos, sorted := compareSlices(actual, test.expected)
11-
if !sorted {
12-
if pos == -1 {
13-
t.Errorf("test %s failed due to slice length changing", test.name)
10+
t.Run(test.name, func(t *testing.T) {
11+
actual := sortingFunction(test.input)
12+
pos, sorted := compareSlices(actual, test.expected)
13+
if !sorted {
14+
if pos == -1 {
15+
t.Errorf("test %s failed due to slice length changing", test.name)
16+
}
17+
18+
for i := pos - 10; i < pos+10; i++ {
19+
fmt.Print(actual[i], " ")
20+
}
21+
t.Errorf("test %s failed at index %d", test.name, pos)
22+
1423
}
15-
t.Errorf("test %s failed at index %d", test.name, pos)
16-
}
24+
})
1725
}
1826
}
1927

20-
func TestSelection(t *testing.T) {
21-
for _, test := range sortTests {
22-
actual := selectionSort(test.input)
23-
pos, sorted := compareSlices(actual, test.expected)
24-
if !sorted {
25-
if pos == -1 {
26-
t.Errorf("test %s failed due to slice length changing", test.name)
27-
}
28-
t.Errorf("test %s failed at index %d", test.name, pos)
29-
}
30-
}
28+
//BEGIN TESTS
29+
30+
func TestBubble(t *testing.T) {
31+
testFramework(t, bubbleSort)
3132
}
3233

3334
func TestInsertion(t *testing.T) {
34-
for _, test := range sortTests {
35-
actual := insertionSort(test.input)
36-
pos, sorted := compareSlices(actual, test.expected)
37-
if !sorted {
38-
if pos == -1 {
39-
t.Errorf("test %s failed due to slice length changing", test.name)
40-
}
41-
t.Errorf("test %s failed at index %d", test.name, pos)
42-
}
43-
}
35+
testFramework(t, InsertionSort)
4436
}
4537

4638
func TestMerge(t *testing.T) {
47-
for _, test := range sortTests {
48-
actual := Mergesort(test.input)
49-
pos, sorted := compareSlices(actual, test.expected)
50-
if !sorted {
51-
if pos == -1 {
52-
t.Errorf("test %s failed due to slice length changing", test.name)
53-
}
54-
t.Errorf("test %s failed at index %d", test.name, pos)
55-
}
56-
}
39+
testFramework(t, Mergesort)
5740
}
5841

5942
func TestHeap(t *testing.T) {
60-
for _, test := range sortTests {
61-
actual := heapSort(test.input)
62-
pos, sorted := compareSlices(actual, test.expected)
63-
if !sorted {
64-
if pos == -1 {
65-
t.Errorf("test %s failed due to slice length changing", test.name)
66-
}
67-
t.Errorf("test %s failed at index %d", test.name, pos)
68-
}
69-
}
43+
testFramework(t, HeapSort)
7044
}
7145

7246
func TestQuick(t *testing.T) {
73-
for _, test := range sortTests {
74-
actual := quickSort(test.input)
75-
pos, sorted := compareSlices(actual, test.expected)
76-
if !sorted {
77-
if pos == -1 {
78-
t.Errorf("test %s failed due to slice length changing", test.name)
79-
}
80-
t.Errorf("test %s failed at index %d", test.name, pos)
81-
}
82-
}
47+
testFramework(t, QuickSort)
8348
}
8449

8550
func TestShell(t *testing.T) {
86-
for _, test := range sortTests {
87-
actual := shellSort(test.input)
88-
pos, sorted := compareSlices(actual, test.expected)
89-
if !sorted {
90-
if pos == -1 {
91-
t.Errorf("test %s failed due to slice length changing", test.name)
92-
}
93-
t.Errorf("test %s failed at index %d", test.name, pos)
94-
}
95-
}
51+
testFramework(t, ShellSort)
9652
}
9753

9854
func TestRadix(t *testing.T) {
99-
for _, test := range sortTests {
100-
actual := RadixSort(test.input)
101-
pos, sorted := compareSlices(actual, test.expected)
102-
if !sorted {
103-
if pos == -1 {
104-
t.Errorf("test %s failed due to slice length changing", test.name)
105-
}
106-
t.Errorf("test %s failed at index %d", test.name, pos)
107-
}
108-
}
55+
testFramework(t, RadixSort)
10956
}
11057

111-
/*func TestTopological(t *testing.T) {
112-
for _, test := range sortTests {
113-
actual := topologicalSort(test.input)
114-
pos, sorted := compareSlices(actual, test.expected)
115-
if !sorted {
116-
if pos == -1 {
117-
t.Errorf("test %s failed due to slice length changing", test.name)
118-
}
119-
t.Errorf("test %s failed at index %d", test.name, pos)
120-
}
121-
}
122-
}*/
58+
/* func TestTopological(t *testing.T) {
59+
testFramework(t, topologicalSort)
60+
} */
12361

12462
//END TESTS
12563

@@ -143,7 +81,7 @@ func BenchmarkSelection(b *testing.B) {
14381
func BenchmarkInsertion(b *testing.B) {
14482
for i := 0; i < b.N; i++ {
14583
for _, test := range sortTests {
146-
insertionSort(test.input)
84+
InsertionSort(test.input)
14785
}
14886
}
14987
}
@@ -159,23 +97,23 @@ func BenchmarkMerge(b *testing.B) {
15997
func BenchmarkHeap(b *testing.B) {
16098
for i := 0; i < b.N; i++ {
16199
for _, test := range sortTests {
162-
heapSort(test.input)
100+
HeapSort(test.input)
163101
}
164102
}
165103
}
166104

167105
func BenchmarkQuick(b *testing.B) {
168106
for i := 0; i < b.N; i++ {
169107
for _, test := range sortTests {
170-
quickSort(test.input)
108+
QuickSort(test.input)
171109
}
172110
}
173111
}
174112

175113
func BenchmarkShell(b *testing.B) {
176114
for i := 0; i < b.N; i++ {
177115
for _, test := range sortTests {
178-
shellSort(test.input)
116+
ShellSort(test.input)
179117
}
180118
}
181119
}

0 commit comments

Comments
 (0)