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…
	
	Add table
		
		Reference in a new issue