|
|
@@ -0,0 +1,216 @@
|
|
|
+// Copyright 2009 The Go Authors. All rights reserved.
|
|
|
+// Use of this source code is governed by a BSD-style
|
|
|
+// license that can be found in the LICENSE file.
|
|
|
+
|
|
|
+package heap
|
|
|
+
|
|
|
+import (
|
|
|
+ "math/rand"
|
|
|
+ "testing"
|
|
|
+
|
|
|
+ "golang.org/x/exp/constraints"
|
|
|
+)
|
|
|
+
|
|
|
+type myHeap[T constraints.Ordered] []T
|
|
|
+
|
|
|
+func (h *myHeap[T]) Less(i, j int) bool {
|
|
|
+ return (*h)[i] < (*h)[j]
|
|
|
+}
|
|
|
+
|
|
|
+func (h *myHeap[T]) Swap(i, j int) {
|
|
|
+ (*h)[i], (*h)[j] = (*h)[j], (*h)[i]
|
|
|
+}
|
|
|
+
|
|
|
+func (h *myHeap[T]) Len() int {
|
|
|
+ return len(*h)
|
|
|
+}
|
|
|
+
|
|
|
+func (h *myHeap[T]) Pop() (v T) {
|
|
|
+ *h, v = (*h)[:h.Len()-1], (*h)[h.Len()-1]
|
|
|
+ return
|
|
|
+}
|
|
|
+
|
|
|
+func (h *myHeap[T]) Push(v T) {
|
|
|
+ *h = append(*h, v)
|
|
|
+}
|
|
|
+
|
|
|
+func (h myHeap[T]) verify(t *testing.T, i int) {
|
|
|
+ t.Helper()
|
|
|
+ n := h.Len()
|
|
|
+ j1 := 2*i + 1
|
|
|
+ j2 := 2*i + 2
|
|
|
+ if j1 < n {
|
|
|
+ if h.Less(j1, i) {
|
|
|
+ t.Errorf("heap invariant invalidated [%d] = %v > [%d] = %v", i, h[i], j1, h[j1])
|
|
|
+ return
|
|
|
+ }
|
|
|
+ h.verify(t, j1)
|
|
|
+ }
|
|
|
+ if j2 < n {
|
|
|
+ if h.Less(j2, i) {
|
|
|
+ t.Errorf("heap invariant invalidated [%d] = %v > [%d] = %v", i, h[i], j1, h[j2])
|
|
|
+ return
|
|
|
+ }
|
|
|
+ h.verify(t, j2)
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+func TestInit0(t *testing.T) {
|
|
|
+ h := new(myHeap[int])
|
|
|
+ for i := 20; i > 0; i-- {
|
|
|
+ h.Push(0) // all elements are the same
|
|
|
+ }
|
|
|
+ Init[int](h)
|
|
|
+ h.verify(t, 0)
|
|
|
+
|
|
|
+ for i := 1; h.Len() > 0; i++ {
|
|
|
+ x := Pop[int](h)
|
|
|
+ h.verify(t, 0)
|
|
|
+ if x != 0 {
|
|
|
+ t.Errorf("%d.th pop got %d; want %d", i, x, 0)
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+func TestInit1(t *testing.T) {
|
|
|
+ h := new(myHeap[int])
|
|
|
+ for i := 20; i > 0; i-- {
|
|
|
+ h.Push(i) // all elements are different
|
|
|
+ }
|
|
|
+ Init[int](h)
|
|
|
+ h.verify(t, 0)
|
|
|
+
|
|
|
+ for i := 1; h.Len() > 0; i++ {
|
|
|
+ x := Pop[int](h)
|
|
|
+ h.verify(t, 0)
|
|
|
+ if x != i {
|
|
|
+ t.Errorf("%d.th pop got %d; want %d", i, x, i)
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+func Test(t *testing.T) {
|
|
|
+ h := new(myHeap[int])
|
|
|
+ h.verify(t, 0)
|
|
|
+
|
|
|
+ for i := 20; i > 10; i-- {
|
|
|
+ h.Push(i)
|
|
|
+ }
|
|
|
+ Init[int](h)
|
|
|
+ h.verify(t, 0)
|
|
|
+
|
|
|
+ for i := 10; i > 0; i-- {
|
|
|
+ Push[int](h, i)
|
|
|
+ h.verify(t, 0)
|
|
|
+ }
|
|
|
+
|
|
|
+ for i := 1; h.Len() > 0; i++ {
|
|
|
+ x := Pop[int](h)
|
|
|
+ if i < 20 {
|
|
|
+ Push[int](h, 20+i)
|
|
|
+ }
|
|
|
+ h.verify(t, 0)
|
|
|
+ if x != i {
|
|
|
+ t.Errorf("%d.th pop got %d; want %d", i, x, i)
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+func TestRemove0(t *testing.T) {
|
|
|
+ h := new(myHeap[int])
|
|
|
+ for i := 0; i < 10; i++ {
|
|
|
+ h.Push(i)
|
|
|
+ }
|
|
|
+ h.verify(t, 0)
|
|
|
+
|
|
|
+ for h.Len() > 0 {
|
|
|
+ i := h.Len() - 1
|
|
|
+ x := Remove[int](h, i)
|
|
|
+ if x != i {
|
|
|
+ t.Errorf("Remove(%d) got %d; want %d", i, x, i)
|
|
|
+ }
|
|
|
+ h.verify(t, 0)
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+func TestRemove1(t *testing.T) {
|
|
|
+ h := new(myHeap[int])
|
|
|
+ for i := 0; i < 10; i++ {
|
|
|
+ h.Push(i)
|
|
|
+ }
|
|
|
+ h.verify(t, 0)
|
|
|
+
|
|
|
+ for i := 0; h.Len() > 0; i++ {
|
|
|
+ x := Remove[int](h, 0)
|
|
|
+ if x != i {
|
|
|
+ t.Errorf("Remove(0) got %d; want %d", x, i)
|
|
|
+ }
|
|
|
+ h.verify(t, 0)
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+func TestRemove2(t *testing.T) {
|
|
|
+ N := 10
|
|
|
+
|
|
|
+ h := new(myHeap[int])
|
|
|
+ for i := 0; i < N; i++ {
|
|
|
+ h.Push(i)
|
|
|
+ }
|
|
|
+ h.verify(t, 0)
|
|
|
+
|
|
|
+ m := make(map[int]bool)
|
|
|
+ for h.Len() > 0 {
|
|
|
+ m[Remove[int](h, (h.Len()-1)/2)] = true
|
|
|
+ h.verify(t, 0)
|
|
|
+ }
|
|
|
+
|
|
|
+ if len(m) != N {
|
|
|
+ t.Errorf("len(m) = %d; want %d", len(m), N)
|
|
|
+ }
|
|
|
+ for i := 0; i < len(m); i++ {
|
|
|
+ if !m[i] {
|
|
|
+ t.Errorf("m[%d] doesn't exist", i)
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+func BenchmarkDup(b *testing.B) {
|
|
|
+ const n = 10000
|
|
|
+ h := make(myHeap[int], 0, n)
|
|
|
+ for i := 0; i < b.N; i++ {
|
|
|
+ for j := 0; j < n; j++ {
|
|
|
+ Push[int](&h, 0) // all elements are the same
|
|
|
+ }
|
|
|
+ for h.Len() > 0 {
|
|
|
+ Pop[int](&h)
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+func TestFix(t *testing.T) {
|
|
|
+ h := new(myHeap[int])
|
|
|
+ h.verify(t, 0)
|
|
|
+
|
|
|
+ for i := 200; i > 0; i -= 10 {
|
|
|
+ Push[int](h, i)
|
|
|
+ }
|
|
|
+ h.verify(t, 0)
|
|
|
+
|
|
|
+ if (*h)[0] != 10 {
|
|
|
+ t.Fatalf("Expected head to be 10, was %d", (*h)[0])
|
|
|
+ }
|
|
|
+ (*h)[0] = 210
|
|
|
+ Fix[int](h, 0)
|
|
|
+ h.verify(t, 0)
|
|
|
+
|
|
|
+ for i := 100; i > 0; i-- {
|
|
|
+ elem := rand.Intn(h.Len())
|
|
|
+ if i&1 == 0 {
|
|
|
+ (*h)[elem] *= 2
|
|
|
+ } else {
|
|
|
+ (*h)[elem] /= 2
|
|
|
+ }
|
|
|
+ Fix[int](h, elem)
|
|
|
+ h.verify(t, 0)
|
|
|
+ }
|
|
|
+}
|