From 4431b6638f8957db0a0d1021acc59c67b5c26722 Mon Sep 17 00:00:00 2001 From: Gregory Date: Thu, 16 Dec 2021 22:23:18 +0200 Subject: [PATCH] bottom up merge sort --- sorting/merge.go | 55 +++++++++++++++++++++++++++++++++++++++++--- sorting/sort_test.go | 20 ++++++++++++++++ 2 files changed, 72 insertions(+), 3 deletions(-) diff --git a/sorting/merge.go b/sorting/merge.go index 144c992..c56595c 100644 --- a/sorting/merge.go +++ b/sorting/merge.go @@ -1,6 +1,8 @@ package sorting -import "sync" +import ( + "sync" +) func merge[T any](items []T, low, mid, hig int, less func(a, b T) bool, aux []T) { i, j := low, mid+1 @@ -42,6 +44,30 @@ func doSort[T any](items []T, low, hig int, less func(a, b T) bool, aux []T) { mid := low + (hig-low)/2 + doSort(items, low, mid, less, aux) + doSort(items, mid+1, hig, less, aux) + + // Optimization 1: if two subarrays already sorted + // we can skip merging them + if less(items[mid], items[mid+1]) { + return + } + + merge(items, low, mid, hig, less, aux) +} + +func doParallelSort[T any](items []T, low, hig int, less func(a, b T) bool, aux []T) { + if hig <= low { + return + } + + if hig-low <= 15 { + Insertion(items[low:hig+1], less) + return + } + + mid := low + (hig-low)/2 + // Optimization 3: we can run sorting in parallel. // This is costly optimization because we increase memory // usage by creating WaitGroup instances @@ -51,8 +77,6 @@ func doSort[T any](items []T, low, hig int, less func(a, b T) bool, aux []T) { go func() { doSort(items, mid+1, hig, less, aux); wg.Done() }() wg.Wait() - // Optimization 1: if two subarrays already sorted - // we can skip merging them if less(items[mid], items[mid+1]) { return } @@ -66,3 +90,28 @@ func Merge[T any](items []T, less func(a, b T) bool) { doSort(items, 0, len-1, less, make([]T, len)) } + +func ParallelMerge[T any](items []T, less func(a, b T) bool) { + + len := len(items) + + doParallelSort(items, 0, len-1, less, make([]T, len)) +} + +func BottomUpMerge[T any](items []T, less func(a, b T) bool) { + + len := len(items) + aux := make([]T, len) + min := func(x, y int) int { + if x < y { + return x + } + return y + } + + for sz := 1; sz < len; sz = sz + sz { + for low := 0; low < len-sz; low += sz + sz { + merge(items, low, low+sz-1, min(low+sz+sz-1, len-1), less, aux) + } + } +} diff --git a/sorting/sort_test.go b/sorting/sort_test.go index 07bafc4..2513cfb 100644 --- a/sorting/sort_test.go +++ b/sorting/sort_test.go @@ -43,3 +43,23 @@ func BenchmarkMerge(b *testing.B) { BenchmarkSort(10000, Merge[int]) } } + +func TestParallelMerge(t *testing.T) { + CheckSliceSorter(ParallelMerge[int]) +} + +func BenchmarkParallelMerge(b *testing.B) { + for i := 0; i < b.N; i++ { + BenchmarkSort(10000, ParallelMerge[int]) + } +} + +func TestBottomUpMerge(t *testing.T) { + CheckSliceSorter(BottomUpMerge[int]) +} + +func BenchmarkBottomUpMerge(b *testing.B) { + for i := 0; i < b.N; i++ { + BenchmarkSort(10000, BottomUpMerge[int]) + } +}