mirror of
https://github.com/teivah/100-go-mistakes.git
synced 2026-06-20 16:45:56 +08:00
Merge sort
This commit is contained in:
parent
cd4dfc7519
commit
8e2f2cb83d
4 changed files with 187 additions and 0 deletions
91
concurrency/mergesort.go
Normal file
91
concurrency/mergesort.go
Normal 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++
|
||||
}
|
||||
}
|
||||
96
concurrency/mergesort_test.go
Normal file
96
concurrency/mergesort_test.go
Normal 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
|
||||
}
|
||||
Loading…
Reference in a new issue