From d4cbad40c315fb664e85d58dd36b2eb4b255eeb2 Mon Sep 17 00:00:00 2001 From: Gregory Date: Mon, 3 Jan 2022 23:07:11 +0200 Subject: [PATCH] heap sort --- sorting/heap.go | 55 +++++++++++++++++++ .../index_priority_queue_test.go | 2 - sorting/sort.go | 2 + sorting/sort_test.go | 10 ++++ 4 files changed, 67 insertions(+), 2 deletions(-) create mode 100644 sorting/heap.go diff --git a/sorting/heap.go b/sorting/heap.go new file mode 100644 index 0000000..de7c9d3 --- /dev/null +++ b/sorting/heap.go @@ -0,0 +1,55 @@ +package sorting + +func swap[T any](i, j int, items []T) { + items[i], items[j] = items[j], items[i] +} + +func swim[T any](child int, depth int, items []T, less func(T, T) bool) { + for { + parent := (child - 1) / 2 + + if child <= 0 || less(items[child], items[parent]) { + break + } + + swap(parent, child, items) + + child = parent + } +} + +func sink[T any](parent int, depth int, items []T, less func(T, T) bool) { + for { + child := parent*2 + 1 + + if child >= depth { + break + } + + if child+1 < depth && less(items[child], items[child+1]) { + child++ + } + + if !less(items[parent], items[child]) { + break + } + + swap(parent, child, items) + + parent = child + } +} + +func Heap[T any](items []T, less func(T, T) bool) { + len := len(items) + + for k := len / 2; k >= 0; k-- { + sink(k, len, items, less) + } + + for len > 0 { + len-- + swap(0, len, items) + sink(0, len, items, less) + } +} diff --git a/sorting/priority_queue/index_priority_queue_test.go b/sorting/priority_queue/index_priority_queue_test.go index 92a3650..0cc2f73 100644 --- a/sorting/priority_queue/index_priority_queue_test.go +++ b/sorting/priority_queue/index_priority_queue_test.go @@ -15,8 +15,6 @@ func TestNewIPQ(t *testing.T) { assert.Equal(t, 0, q.Size()) assert.Equal(t, true, q.IsEmpty()) assert.Equal(t, -1, q.TopIndex()) - // TODO: maybe should return nil? - // assert.Equal(t, 0, q.Top()) } func TestIPQInsert(t *testing.T) { diff --git a/sorting/sort.go b/sorting/sort.go index 71b3e91..07c77a6 100644 --- a/sorting/sort.go +++ b/sorting/sort.go @@ -1,3 +1,5 @@ package sorting +// TODO: compare function should receive pointers to slice elements +// to prevent unnecessary coping type SliceSorter[T any] func([]T, func(T, T) bool) diff --git a/sorting/sort_test.go b/sorting/sort_test.go index 5c85147..52e2cdf 100644 --- a/sorting/sort_test.go +++ b/sorting/sort_test.go @@ -73,3 +73,13 @@ func BenchmarkQuick(b *testing.B) { BenchmarkSort(10000, Quick[int]) } } + +func TestHeap(t *testing.T) { + CheckSliceSorter(Heap[int]) +} + +func BenchmarkHeap(b *testing.B) { + for i := 0; i < b.N; i++ { + BenchmarkSort(10000, Heap[int]) + } +}