Merge sort

This commit is contained in:
teivah 2020-12-15 00:18:19 +01:00
parent cd4dfc7519
commit 8e2f2cb83d
4 changed files with 187 additions and 0 deletions

91
concurrency/mergesort.go Normal file
View file

@ -0,0 +1,91 @@
package concurrency
import "sync"
func mergesortSequential(s []int) {
if len(s) > 1 {
middle := len(s) / 2
mergesortSequential(s[:middle])
mergesortSequential(s[middle:])
merge(s, middle)
}
}
func mergeSortConcurrentV1(s []int) {
if len(s) > 1 {
middle := len(s) / 2
var wg sync.WaitGroup
wg.Add(2)
go func() {
defer wg.Done()
mergeSortConcurrentV1(s[:middle])
}()
go func() {
defer wg.Done()
mergeSortConcurrentV1(s[middle:])
}()
wg.Wait()
merge(s, middle)
}
}
const max = 1 << 20
func mergeSortConcurrentV2(s []int) {
if len(s) > 1 {
if len(s) <= max {
// Sequential
mergesortSequential(s)
} else {
// Concurrent
middle := len(s) / 2
var wg sync.WaitGroup
wg.Add(2)
go func() {
defer wg.Done()
mergeSortConcurrentV2(s[:middle])
}()
go func() {
defer wg.Done()
mergeSortConcurrentV2(s[middle:])
}()
wg.Wait()
merge(s, middle)
}
}
}
func merge(s []int, middle int) {
helper := make([]int, len(s))
copy(helper, s)
helperLeft := 0
helperRight := middle
current := 0
high := len(s) - 1
for helperLeft <= middle-1 && helperRight <= high {
if helper[helperLeft] <= helper[helperRight] {
s[current] = helper[helperLeft]
helperLeft++
} else {
s[current] = helper[helperRight]
helperRight++
}
current++
}
for helperLeft <= middle-1 {
s[current] = helper[helperLeft]
current++
helperLeft++
}
}

View file

@ -0,0 +1,96 @@
package concurrency
import (
"math/rand"
"testing"
"time"
"github.com/stretchr/testify/assert"
)
const size = 10_000_000
func Test_mergeSort(t *testing.T) {
var (
input = []int{5, 8, 9, 5, 0, 10, 1, 6}
expected = []int{0, 1, 5, 5, 6, 8, 9, 10}
)
type args struct {
f func(s []int)
input []int
}
tests := map[string]struct {
args args
expected []int
}{
"sequential": {
args: args{
f: mergesortSequential,
input: input,
},
expected: expected,
},
"concurrent v1": {
args: args{
f: mergeSortConcurrentV1,
input: input,
},
expected: expected,
},
"concurrent v2": {
args: args{
f: mergeSortConcurrentV2,
input: input,
},
expected: expected,
},
}
for name, tt := range tests {
tt := tt
t.Run(name, func(t *testing.T) {
tt.args.f(tt.args.input)
assert.Equal(t, tt.expected, tt.args.input)
})
}
}
func Benchmark_mergeSortSequential(b *testing.B) {
for i := 0; i < b.N; i++ {
s := random(size)
b.StartTimer()
mergesortSequential(s)
b.StopTimer()
}
}
func Benchmark_mergeSortConcurrentV1(b *testing.B) {
for i := 0; i < b.N; i++ {
s := random(size)
b.StartTimer()
mergeSortConcurrentV1(s)
b.StopTimer()
}
}
func Benchmark_mergeSortConcurrentV2(b *testing.B) {
for i := 0; i < b.N; i++ {
s := random(size)
b.StartTimer()
mergeSortConcurrentV2(s)
b.StopTimer()
}
}
func random(n int) []int {
s := make([]int, n)
src := rand.NewSource(time.Now().UnixNano())
rand := rand.New(src)
for i := 0; i < n; i++ {
s[i] = rand.Intn(n)
}
return s
}