diff --git a/sorting/insertion.go b/sorting/insertion.go index ee13ad4..7f94e80 100644 --- a/sorting/insertion.go +++ b/sorting/insertion.go @@ -2,15 +2,11 @@ package sorting type insertion struct{} -func (*insertion) Sort(items Sortable) { - len := items.Len() +func Insertion[T any](items []T, less func(a, b T) bool) { + len := len(items) for i := 1; i < len; i++ { - for j := i; j > 0 && items.Less(j, j-1); j-- { - items.Swap(j, j-1) + for j := i; j > 0 && less(items[j], items[j-1]); j-- { + items[j], items[j-1] = items[j-1], items[j] } } } - -func NewInsertion() Sorter { - return &insertion{} -} diff --git a/sorting/int.go b/sorting/int.go deleted file mode 100644 index c85df5a..0000000 --- a/sorting/int.go +++ /dev/null @@ -1,15 +0,0 @@ -package sorting - -type IntSort []int - -func (items IntSort) Len() int { - return len(items) -} - -func (items IntSort) Swap(i, j int) { - items[i], items[j] = items[j], items[i] -} - -func (items IntSort) Less(i, j int) bool { - return items[i] < items[j] -} diff --git a/sorting/selection.go b/sorting/selection.go index 70ca66a..bca4723 100644 --- a/sorting/selection.go +++ b/sorting/selection.go @@ -1,20 +1,14 @@ package sorting -type selection struct{} - -func (*selection) Sort(items Sortable) { - len := items.Len() +func Selection[T any](items []T, less func(a, b T) bool) { + len := len(items) for i := 0; i < len; i++ { min := i for j := i + 1; j < len; j++ { - if items.Less(j, min) { + if less(items[j], items[min]) { min = j } } - items.Swap(min, i) + items[min], items[i] = items[i], items[min] } } - -func NewSelection() Sorter { - return &selection{} -} diff --git a/sorting/shell.go b/sorting/shell.go index 7f192a2..c28e2e4 100644 --- a/sorting/shell.go +++ b/sorting/shell.go @@ -1,9 +1,7 @@ package sorting -type shell struct{} - -func (*shell) Sort(items Sortable) { - len := items.Len() +func Shell[T any](items []T, less func(a, b T) bool) { + len := len(items) gap := 1 // Calculating gap maximum value. @@ -13,7 +11,7 @@ func (*shell) Sort(items Sortable) { gap = gap*3 + 1 } - // This loop needed to progressively degrease gap until siple insertion + // This loop needed to progressively decrease gap until simple insertion // sort will be used for gap >= 1 { @@ -22,8 +20,8 @@ func (*shell) Sort(items Sortable) { // Instead of comparing adjacent elements we compare // gap distance elements and swap them - for j := i; j >= gap && items.Less(j, j-gap); j -= gap { - items.Swap(j, j-gap) + for j := i; j >= gap && less(items[j], items[j-gap]); j -= gap { + items[j], items[j-gap] = items[j-gap], items[j] } } @@ -31,7 +29,3 @@ func (*shell) Sort(items Sortable) { gap = gap / 3 } } - -func NewShell() Sorter { - return &shell{} -} diff --git a/sorting/sort.go b/sorting/sort.go index 970a9e2..71b3e91 100644 --- a/sorting/sort.go +++ b/sorting/sort.go @@ -1,13 +1,3 @@ package sorting -type Sortable interface { - Len() int - Swap(i, j int) - Less(i, j int) bool -} - -type Sorter interface { - Sort(Sortable) - // TODO: add generic slice sort when type variables are landed - // SortSlice[T any](T, func(i, j int) bool) -} +type SliceSorter[T any] func([]T, func(T, T) bool) diff --git a/sorting/sort_test.go b/sorting/sort_test.go index 1973220..3267abe 100644 --- a/sorting/sort_test.go +++ b/sorting/sort_test.go @@ -4,32 +4,32 @@ import ( "testing" ) -func TestSelection(t *testing.T) { - CheckSorter(NewSelection()) +func TestSelectionSlice(t *testing.T) { + CheckSliceSorter(Selection[int]) } func BenchmarkSelection(b *testing.B) { for i := 0; i < b.N; i++ { - BenchmarkSort(10000, NewSelection()) + BenchmarkSort(10000, Selection[int]) } } func TestInsertion(t *testing.T) { - CheckSorter(NewInsertion()) + CheckSliceSorter(Insertion[int]) } func BenchmarkInsertion(b *testing.B) { for i := 0; i < b.N; i++ { - BenchmarkSort(10000, NewInsertion()) + BenchmarkSort(10000, Insertion[int]) } } func TestShell(t *testing.T) { - CheckSorter(NewShell()) + CheckSliceSorter(Shell[int]) } func BenchmarkShell(b *testing.B) { for i := 0; i < b.N; i++ { - BenchmarkSort(10000, NewShell()) + BenchmarkSort(10000, Shell[int]) } } diff --git a/sorting/testing.go b/sorting/testing.go index a7c08b3..ed8b504 100644 --- a/sorting/testing.go +++ b/sorting/testing.go @@ -7,6 +7,20 @@ import ( "time" ) +type IntSort []int + +func (items IntSort) Len() int { + return len(items) +} + +func (items IntSort) Swap(i, j int) { + items[i], items[j] = items[j], items[i] +} + +func (items IntSort) Less(i, j int) bool { + return items[i] < items[j] +} + func SameInts(a, b []int) bool { if len(a) != len(b) { return false @@ -21,14 +35,16 @@ func SameInts(a, b []int) bool { return true } -func CheckSorter(s Sorter) { +func intCmp(a, b int) bool { return a < b } + +func CheckSliceSorter(sorter SliceSorter[int]) { rand.Seed(time.Now().Unix()) actual := rand.Perm(1000) expected := make([]int, len(actual)) copy(expected, actual) - s.Sort(IntSort(actual)) + sorter(actual, intCmp) sort.Sort(IntSort(expected)) if !SameInts(actual, expected) { @@ -36,8 +52,8 @@ func CheckSorter(s Sorter) { } } -func BenchmarkSort(numItems int, s Sorter) { +func BenchmarkSort(numItems int, sorter SliceSorter[int]) { rand.Seed(time.Now().Unix()) items := rand.Perm(numItems) - s.Sort(IntSort(items)) + sorter(items, intCmp) }