| // 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" |
| ) |
| |
| type myHeap []int |
| |
| func (h *myHeap) Less(i, j int) bool { |
| return (*h)[i] < (*h)[j] |
| } |
| |
| func (h *myHeap) Swap(i, j int) { |
| (*h)[i], (*h)[j] = (*h)[j], (*h)[i] |
| } |
| |
| func (h *myHeap) Len() int { |
| return len(*h) |
| } |
| |
| func (h *myHeap) Pop() (v interface{}) { |
| *h, v = (*h)[:h.Len()-1], (*h)[h.Len()-1] |
| return |
| } |
| |
| func (h *myHeap) Push(v interface{}) { |
| *h = append(*h, v.(int)) |
| } |
| |
| func (h myHeap) 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] = %d > [%d] = %d", 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] = %d > [%d] = %d", i, h[i], j1, h[j2]) |
| return |
| } |
| h.verify(t, j2) |
| } |
| } |
| |
| func TestInit0(t *testing.T) { |
| h := new(myHeap) |
| for i := 20; i > 0; i-- { |
| h.Push(0) // all elements are the same |
| } |
| Init(h) |
| h.verify(t, 0) |
| |
| for i := 1; h.Len() > 0; i++ { |
| x := Pop(h).(int) |
| 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) |
| for i := 20; i > 0; i-- { |
| h.Push(i) // all elements are different |
| } |
| Init(h) |
| h.verify(t, 0) |
| |
| for i := 1; h.Len() > 0; i++ { |
| x := Pop(h).(int) |
| 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) |
| h.verify(t, 0) |
| |
| for i := 20; i > 10; i-- { |
| h.Push(i) |
| } |
| Init(h) |
| h.verify(t, 0) |
| |
| for i := 10; i > 0; i-- { |
| Push(h, i) |
| h.verify(t, 0) |
| } |
| |
| for i := 1; h.Len() > 0; i++ { |
| x := Pop(h).(int) |
| if i < 20 { |
| Push(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) |
| for i := 0; i < 10; i++ { |
| h.Push(i) |
| } |
| h.verify(t, 0) |
| |
| for h.Len() > 0 { |
| i := h.Len() - 1 |
| x := Remove(h, i).(int) |
| 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) |
| for i := 0; i < 10; i++ { |
| h.Push(i) |
| } |
| h.verify(t, 0) |
| |
| for i := 0; h.Len() > 0; i++ { |
| x := Remove(h, 0).(int) |
| 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) |
| for i := 0; i < N; i++ { |
| h.Push(i) |
| } |
| h.verify(t, 0) |
| |
| m := make(map[int]bool) |
| for h.Len() > 0 { |
| m[Remove(h, (h.Len()-1)/2).(int)] = 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, 0, n) |
| for i := 0; i < b.N; i++ { |
| for j := 0; j < n; j++ { |
| Push(&h, 0) // all elements are the same |
| } |
| for h.Len() > 0 { |
| Pop(&h) |
| } |
| } |
| } |
| |
| func TestFix(t *testing.T) { |
| h := new(myHeap) |
| h.verify(t, 0) |
| |
| for i := 200; i > 0; i -= 10 { |
| Push(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(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(h, elem) |
| h.verify(t, 0) |
| } |
| } |