generic sorting
This commit is contained in:
parent
323fd70370
commit
c0dc901168
7 changed files with 41 additions and 66 deletions
|
@ -2,15 +2,11 @@ package sorting
|
||||||
|
|
||||||
type insertion struct{}
|
type insertion struct{}
|
||||||
|
|
||||||
func (*insertion) Sort(items Sortable) {
|
func Insertion[T any](items []T, less func(a, b T) bool) {
|
||||||
len := items.Len()
|
len := len(items)
|
||||||
for i := 1; i < len; i++ {
|
for i := 1; i < len; i++ {
|
||||||
for j := i; j > 0 && items.Less(j, j-1); j-- {
|
for j := i; j > 0 && less(items[j], items[j-1]); j-- {
|
||||||
items.Swap(j, j-1)
|
items[j], items[j-1] = items[j-1], items[j]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewInsertion() Sorter {
|
|
||||||
return &insertion{}
|
|
||||||
}
|
|
||||||
|
|
|
@ -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]
|
|
||||||
}
|
|
|
@ -1,20 +1,14 @@
|
||||||
package sorting
|
package sorting
|
||||||
|
|
||||||
type selection struct{}
|
func Selection[T any](items []T, less func(a, b T) bool) {
|
||||||
|
len := len(items)
|
||||||
func (*selection) Sort(items Sortable) {
|
|
||||||
len := items.Len()
|
|
||||||
for i := 0; i < len; i++ {
|
for i := 0; i < len; i++ {
|
||||||
min := i
|
min := i
|
||||||
for j := i + 1; j < len; j++ {
|
for j := i + 1; j < len; j++ {
|
||||||
if items.Less(j, min) {
|
if less(items[j], items[min]) {
|
||||||
min = j
|
min = j
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
items.Swap(min, i)
|
items[min], items[i] = items[i], items[min]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewSelection() Sorter {
|
|
||||||
return &selection{}
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,9 +1,7 @@
|
||||||
package sorting
|
package sorting
|
||||||
|
|
||||||
type shell struct{}
|
func Shell[T any](items []T, less func(a, b T) bool) {
|
||||||
|
len := len(items)
|
||||||
func (*shell) Sort(items Sortable) {
|
|
||||||
len := items.Len()
|
|
||||||
gap := 1
|
gap := 1
|
||||||
|
|
||||||
// Calculating gap maximum value.
|
// Calculating gap maximum value.
|
||||||
|
@ -13,7 +11,7 @@ func (*shell) Sort(items Sortable) {
|
||||||
gap = gap*3 + 1
|
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
|
// sort will be used
|
||||||
for gap >= 1 {
|
for gap >= 1 {
|
||||||
|
|
||||||
|
@ -22,8 +20,8 @@ func (*shell) Sort(items Sortable) {
|
||||||
|
|
||||||
// Instead of comparing adjacent elements we compare
|
// Instead of comparing adjacent elements we compare
|
||||||
// gap distance elements and swap them
|
// gap distance elements and swap them
|
||||||
for j := i; j >= gap && items.Less(j, j-gap); j -= gap {
|
for j := i; j >= gap && less(items[j], items[j-gap]); j -= gap {
|
||||||
items.Swap(j, j-gap)
|
items[j], items[j-gap] = items[j-gap], items[j]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -31,7 +29,3 @@ func (*shell) Sort(items Sortable) {
|
||||||
gap = gap / 3
|
gap = gap / 3
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewShell() Sorter {
|
|
||||||
return &shell{}
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,13 +1,3 @@
|
||||||
package sorting
|
package sorting
|
||||||
|
|
||||||
type Sortable interface {
|
type SliceSorter[T any] func([]T, func(T, T) bool)
|
||||||
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)
|
|
||||||
}
|
|
||||||
|
|
|
@ -4,32 +4,32 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestSelection(t *testing.T) {
|
func TestSelectionSlice(t *testing.T) {
|
||||||
CheckSorter(NewSelection())
|
CheckSliceSorter(Selection[int])
|
||||||
}
|
}
|
||||||
|
|
||||||
func BenchmarkSelection(b *testing.B) {
|
func BenchmarkSelection(b *testing.B) {
|
||||||
for i := 0; i < b.N; i++ {
|
for i := 0; i < b.N; i++ {
|
||||||
BenchmarkSort(10000, NewSelection())
|
BenchmarkSort(10000, Selection[int])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestInsertion(t *testing.T) {
|
func TestInsertion(t *testing.T) {
|
||||||
CheckSorter(NewInsertion())
|
CheckSliceSorter(Insertion[int])
|
||||||
}
|
}
|
||||||
|
|
||||||
func BenchmarkInsertion(b *testing.B) {
|
func BenchmarkInsertion(b *testing.B) {
|
||||||
for i := 0; i < b.N; i++ {
|
for i := 0; i < b.N; i++ {
|
||||||
BenchmarkSort(10000, NewInsertion())
|
BenchmarkSort(10000, Insertion[int])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestShell(t *testing.T) {
|
func TestShell(t *testing.T) {
|
||||||
CheckSorter(NewShell())
|
CheckSliceSorter(Shell[int])
|
||||||
}
|
}
|
||||||
|
|
||||||
func BenchmarkShell(b *testing.B) {
|
func BenchmarkShell(b *testing.B) {
|
||||||
for i := 0; i < b.N; i++ {
|
for i := 0; i < b.N; i++ {
|
||||||
BenchmarkSort(10000, NewShell())
|
BenchmarkSort(10000, Shell[int])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,6 +7,20 @@ import (
|
||||||
"time"
|
"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 {
|
func SameInts(a, b []int) bool {
|
||||||
if len(a) != len(b) {
|
if len(a) != len(b) {
|
||||||
return false
|
return false
|
||||||
|
@ -21,14 +35,16 @@ func SameInts(a, b []int) bool {
|
||||||
return true
|
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())
|
rand.Seed(time.Now().Unix())
|
||||||
|
|
||||||
actual := rand.Perm(1000)
|
actual := rand.Perm(1000)
|
||||||
expected := make([]int, len(actual))
|
expected := make([]int, len(actual))
|
||||||
copy(expected, actual)
|
copy(expected, actual)
|
||||||
|
|
||||||
s.Sort(IntSort(actual))
|
sorter(actual, intCmp)
|
||||||
sort.Sort(IntSort(expected))
|
sort.Sort(IntSort(expected))
|
||||||
|
|
||||||
if !SameInts(actual, 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())
|
rand.Seed(time.Now().Unix())
|
||||||
items := rand.Perm(numItems)
|
items := rand.Perm(numItems)
|
||||||
s.Sort(IntSort(items))
|
sorter(items, intCmp)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue