From 1f81f4cb45fe3ad94869c241787080d028adc47d Mon Sep 17 00:00:00 2001 From: Gregory Date: Wed, 29 Dec 2021 23:59:09 +0200 Subject: [PATCH] quick sort --- sorting/quick.go | 63 ++++++++++++++++++++++++++++++++++++++++++++ sorting/sort_test.go | 10 +++++++ 2 files changed, 73 insertions(+) create mode 100644 sorting/quick.go diff --git a/sorting/quick.go b/sorting/quick.go new file mode 100644 index 0000000..e3e602d --- /dev/null +++ b/sorting/quick.go @@ -0,0 +1,63 @@ +package sorting + +import ( + "math/rand" + "time" +) + +func exch[T any](items []T, a int, b int) { + items[a], items[b] = items[b], items[a] +} + +func partition[T any](items []T, lo int, hi int, less func(a, b T) bool) int { + i, j := lo, hi+1 + v := items[lo] + + for { + for i++; less(items[i], v); i++ { + if i == hi { + break + } + } + + for j--; less(v, items[j]); j-- { + if j == lo { + break + } + } + + if i >= j { + break + } + + exch(items, i, j) + } + exch(items, j, lo) + + return j +} + +func doQuickSort[T any](items []T, lo int, hi int, less func(a, b T) bool) { + if hi-lo <= 15 { + Insertion(items[lo:hi+1], less) + return + } + + if lo >= hi { + return + } + mi := partition(items, lo, hi, less) + doQuickSort(items, lo, mi-1, less) + doQuickSort(items, mi+1, hi, less) + +} + +func Quick[T any](items []T, less func(a, b T) bool) { + + // We shuffle array to prevent worst case scenario when array already sorted. + // Without shuffling we get O(n^2) time. Another variant how to prevent + // such performance drop is to compute median element in partition function. + rand.Seed(time.Now().UnixNano()) + rand.Shuffle(len(items), func(i, j int) { items[i], items[j] = items[j], items[i] }) + doQuickSort(items, 0, len(items)-1, less) +} diff --git a/sorting/sort_test.go b/sorting/sort_test.go index 2513cfb..5c85147 100644 --- a/sorting/sort_test.go +++ b/sorting/sort_test.go @@ -63,3 +63,13 @@ func BenchmarkBottomUpMerge(b *testing.B) { BenchmarkSort(10000, BottomUpMerge[int]) } } + +func TestQuick(t *testing.T) { + CheckSliceSorter(Quick[int]) +} + +func BenchmarkQuick(b *testing.B) { + for i := 0; i < b.N; i++ { + BenchmarkSort(10000, Quick[int]) + } +}