diff options
| -rw-r--r-- | ds/arraylist.go | 8 | ||||
| -rw-r--r-- | ds/comparer.go | 10 | ||||
| -rw-r--r-- | ds/elem.go | 10 | ||||
| -rw-r--r-- | ds/integer.go | 26 | ||||
| -rw-r--r-- | sort/insertion.go | 4 | ||||
| -rw-r--r-- | sort/merge.go | 49 | ||||
| -rw-r--r-- | sort/merge2.go | 37 | ||||
| -rw-r--r-- | sort/merge3.go | 26 | ||||
| -rw-r--r-- | sort/shuffle.go | 3 | ||||
| -rw-r--r-- | sort/sort_test.go | 41 |
10 files changed, 181 insertions, 33 deletions
diff --git a/ds/arraylist.go b/ds/arraylist.go index 243efe1..d3feef5 100644 --- a/ds/arraylist.go +++ b/ds/arraylist.go @@ -5,7 +5,7 @@ import ( "strings" ) -type ArrayList []Comparer +type ArrayList []Elem func (a ArrayList) FirstN(n int) string { var sb strings.Builder @@ -37,7 +37,7 @@ func (a ArrayList) Sorted() bool { } func (a ArrayList) Swap(i, j int) { - tmp := a[i] - a[i] = a[j] - a[j] = tmp + tmp := a[i] + a[i] = a[j] + a[j] = tmp } diff --git a/ds/comparer.go b/ds/comparer.go deleted file mode 100644 index 8fb3727..0000000 --- a/ds/comparer.go +++ /dev/null @@ -1,10 +0,0 @@ -package ds - -type Comparer interface { - Equal(a Comparer) bool - Lower(a Comparer) bool - LowerEqual(a Comparer) bool - Higher(a Comparer) bool - HigherEqual(a Comparer) bool - Int() int -} diff --git a/ds/elem.go b/ds/elem.go new file mode 100644 index 0000000..0589e81 --- /dev/null +++ b/ds/elem.go @@ -0,0 +1,10 @@ +package ds + +type Elem interface { + Equal(a Elem) bool + Lower(a Elem) bool + LowerEqual(a Elem) bool + Higher(a Elem) bool + HigherEqual(a Elem) bool + Int() int +} diff --git a/ds/integer.go b/ds/integer.go index 04fee3e..4abb349 100644 --- a/ds/integer.go +++ b/ds/integer.go @@ -6,7 +6,7 @@ import ( ) type Integer struct { - val int + Val int } func RandomIntegers(length, max int) ArrayList { @@ -36,29 +36,29 @@ func ReverseSortedIntegers(length int) ArrayList { } func (i Integer) String() string { - return fmt.Sprintf("%d", i.val) + return fmt.Sprintf("%d", i.Val) } func (i Integer) Int() int { - return i.val + return i.Val } -func (i Integer) Equal(j Comparer) bool { - return i.val == j.Int() +func (i Integer) Equal(j Elem) bool { + return i.Val == j.Int() } -func (i Integer) Lower(j Comparer) bool { - return i.val < j.Int() +func (i Integer) Lower(j Elem) bool { + return i.Val < j.Int() } -func (i Integer) LowerEqual(j Comparer) bool { - return i.val <= j.Int() +func (i Integer) LowerEqual(j Elem) bool { + return i.Val <= j.Int() } -func (i Integer) Higher(j Comparer) bool { - return i.val > j.Int() +func (i Integer) Higher(j Elem) bool { + return i.Val > j.Int() } -func (i Integer) HigherEqual(j Comparer) bool { - return i.val >= j.Int() +func (i Integer) HigherEqual(j Elem) bool { + return i.Val >= j.Int() } diff --git a/sort/insertion.go b/sort/insertion.go index 465e8b4..3e271b0 100644 --- a/sort/insertion.go +++ b/sort/insertion.go @@ -12,9 +12,7 @@ func Insertion(a ds.ArrayList) ds.ArrayList { if a[j].Higher(a[j-1]) { break } - tmp := a[j] - a[j] = a[j-1] - a[j-1] = tmp + a.Swap(j, j-1) } } diff --git a/sort/merge.go b/sort/merge.go new file mode 100644 index 0000000..e57ea6d --- /dev/null +++ b/sort/merge.go @@ -0,0 +1,49 @@ +package sort + +import ( + "algorithms/ds" +) + +func Merge(a ds.ArrayList) ds.ArrayList { + aux := make(ds.ArrayList, len(a)) + mergeSort(a, aux, 0, len(a)-1) + + return a +} + +func mergeSort(a, aux ds.ArrayList, lo, hi int) { + if lo >= hi { + return + } + mid := lo + (hi-lo)/2 + + mergeSort(a, aux, lo, mid) + mergeSort(a, aux, mid+1, hi) + merge(a, aux, lo, mid, hi) +} + +func merge(a, aux ds.ArrayList, lo, mid, hi int) { + for i := lo; i <= hi; i++ { + aux[i] = a[i] + } + + i := lo + j := mid + 1 + + for k := lo; k <= hi; k++ { + switch { + case i > mid: + a[k] = aux[j] + j++ + case j > hi: + a[k] = aux[i] + i++ + case aux[i].Higher(aux[j]): + a[k] = aux[j] + j++ + default: + a[k] = aux[i] + i++ + } + } +} diff --git a/sort/merge2.go b/sort/merge2.go new file mode 100644 index 0000000..774c3c5 --- /dev/null +++ b/sort/merge2.go @@ -0,0 +1,37 @@ +package sort + +import ( + "algorithms/ds" + "sync" +) + +// Merge2 is a parallelized version of Merge +func Merge2(a ds.ArrayList) ds.ArrayList { + aux := make(ds.ArrayList, len(a)) + mergeSort2(a, aux, 0, len(a)-1) + + return a +} + +func mergeSort2(a, aux ds.ArrayList, lo, hi int) { + mid := lo + (hi-lo)/2 + defer merge(a, aux, lo, mid, hi) + + if hi-lo <= 1000 { + mergeSort(a, aux, lo, mid) + mergeSort(a, aux, mid+1, hi) + return + } + + var wg sync.WaitGroup + wg.Add(2) + go func() { + mergeSort2(a, aux, lo, mid) + wg.Done() + }() + go func() { + mergeSort2(a, aux, mid+1, hi) + wg.Done() + }() + wg.Wait() +} diff --git a/sort/merge3.go b/sort/merge3.go new file mode 100644 index 0000000..fbc1650 --- /dev/null +++ b/sort/merge3.go @@ -0,0 +1,26 @@ +package sort + +import ( + "algorithms/ds" +) + +// Merge3 is the bottom up version of merge sort. +func Merge3(a ds.ArrayList) ds.ArrayList { + length := len(a) + aux := make(ds.ArrayList, length) + + for sz := 1; sz < length; sz = sz + sz { + for lo := 0; lo < length-sz; lo += sz + sz { + merge(a, aux, lo, lo+sz-1, min(lo+sz+sz-1, length-1)) + } + } + + return a +} + +func min(a, b int) int { + if a <= b { + return a + } + return b +} diff --git a/sort/shuffle.go b/sort/shuffle.go index 9c6f5b9..26db8c4 100644 --- a/sort/shuffle.go +++ b/sort/shuffle.go @@ -10,9 +10,6 @@ func Shuffle(a ds.ArrayList) ds.ArrayList { for i := 0; i < length; i++ { r := length - rand.Intn(length-i) - 1 - if r == i { - continue - } tmp := a[i] a[i] = a[r] a[r] = tmp diff --git a/sort/sort_test.go b/sort/sort_test.go index bd9db9b..a0e4729 100644 --- a/sort/sort_test.go +++ b/sort/sort_test.go @@ -33,6 +33,29 @@ func TestShellSort(t *testing.T) { } } +func TestMergeSort(t *testing.T) { + for i := 1; i <= maxLength; i *= 10 { + test(Merge, i, t) + } + test(Merge, maxLength*2, t) +} + +func TestMerge2Sort(t *testing.T) { + t.Log("Parallel merge sort") + for i := 1; i <= maxLength; i *= 10 { + test(Merge2, i, t) + } + test(Merge2, maxLength*2, t) +} + +func TestMerge3Sort(t *testing.T) { + t.Log("Bottom-up merge sort") + for i := 1; i <= maxLength; i *= 10 { + test(Merge3, i, t) + } + test(Merge3, maxLength*2, t) +} + func TestQuickSort(t *testing.T) { for i := 1; i <= maxLength; i *= 10 { test(Quick, i, t) @@ -63,6 +86,24 @@ func BenchmarkShellSort(b *testing.B) { } } +func BenchmarkMergeSort(b *testing.B) { + for i := 1; i <= maxLength; i *= 10 { + benchmark(Merge, i, b) + } +} + +func BenchmarkMerge2Sort(b *testing.B) { + for i := 1; i <= maxLength; i *= 10 { + benchmark(Merge2, i, b) + } +} + +func BenchmarkMerge3Sort(b *testing.B) { + for i := 1; i <= maxLength; i *= 10 { + benchmark(Merge3, i, b) + } +} + func BenchmarkQuickSort(b *testing.B) { for i := 1; i <= maxLength; i *= 10 { benchmark(Quick, i, b) |
