mirror of
https://github.com/teivah/100-go-mistakes.git
synced 2026-06-24 10:26:54 +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