github.com/code-reading/golang@v0.0.0-20220303082512-ba5bc0e589a3/go/src/container/heap/heap_test.go (about)

     1  // Copyright 2009 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package heap
     6  
     7  import (
     8  	"math/rand"
     9  	"testing"
    10  )
    11  
    12  type myHeap []int
    13  
    14  func (h *myHeap) Less(i, j int) bool {
    15  	return (*h)[i] < (*h)[j]
    16  }
    17  
    18  func (h *myHeap) Swap(i, j int) {
    19  	(*h)[i], (*h)[j] = (*h)[j], (*h)[i]
    20  }
    21  
    22  func (h *myHeap) Len() int {
    23  	return len(*h)
    24  }
    25  
    26  // push 和 pop 都是操作的最后一个元素
    27  func (h *myHeap) Pop() (v interface{}) {
    28  	// Pop 删除并返回最后一个元素, 并且更新heap 为前h.Len()-1的元素数组
    29  	*h, v = (*h)[:h.Len()-1], (*h)[h.Len()-1]
    30  	return
    31  }
    32  
    33  // Push 是从数组后面添加元素
    34  func (h *myHeap) Push(v interface{}) {
    35  	*h = append(*h, v.(int))
    36  }
    37  
    38  func (h myHeap) verify(t *testing.T, i int) {
    39  	t.Helper()
    40  	n := h.Len()
    41  	j1 := 2*i + 1
    42  	j2 := 2*i + 2
    43  	if j1 < n { // 存在左子树节点
    44  		if h.Less(j1, i) { // 如果左节点小于i节点,表示 子节点小于父节点值, 不满足最小堆
    45  			t.Errorf("heap invariant invalidated [%d] = %d > [%d] = %d", i, h[i], j1, h[j1])
    46  			return
    47  		}
    48  		h.verify(t, j1)
    49  	}
    50  	if j2 < n { // 存在右子树节点
    51  		if h.Less(j2, i) {
    52  			t.Errorf("heap invariant invalidated [%d] = %d > [%d] = %d", i, h[i], j1, h[j2])
    53  			return
    54  		}
    55  		h.verify(t, j2)
    56  	}
    57  }
    58  
    59  func TestInit0(t *testing.T) {
    60  	h := new(myHeap) // 初始化
    61  	// 装填数据
    62  	for i := 20; i > 0; i-- {
    63  		h.Push(0) // all elements are the same
    64  	}
    65  	Init(h)        // 构建最小堆
    66  	h.verify(t, 0) // 验证最小堆
    67  
    68  	// 出去值 并验证最小堆
    69  	for i := 1; h.Len() > 0; i++ {
    70  		x := Pop(h).(int)
    71  		h.verify(t, 0)
    72  		if x != 0 {
    73  			t.Errorf("%d.th pop got %d; want %d", i, x, 0)
    74  		}
    75  	}
    76  }
    77  
    78  func TestInit1(t *testing.T) {
    79  	h := new(myHeap)
    80  	for i := 20; i > 0; i-- {
    81  		h.Push(i) // all elements are different
    82  	}
    83  	Init(h)
    84  	h.verify(t, 0)
    85  
    86  	for i := 1; h.Len() > 0; i++ {
    87  		x := Pop(h).(int)
    88  		h.verify(t, 0)
    89  		if x != i {
    90  			t.Errorf("%d.th pop got %d; want %d", i, x, i)
    91  		}
    92  	}
    93  }
    94  
    95  func Test(t *testing.T) {
    96  	h := new(myHeap) // 初始化一个空数组
    97  	h.verify(t, 0)   // 堆化验证
    98  
    99  	for i := 20; i > 10; i-- {
   100  		h.Push(i)
   101  	}
   102  	Init(h)
   103  	h.verify(t, 0)
   104  
   105  	for i := 10; i > 0; i-- {
   106  		Push(h, i)
   107  		h.verify(t, 0)
   108  	}
   109  
   110  	for i := 1; h.Len() > 0; i++ {
   111  		x := Pop(h).(int)
   112  		if i < 20 {
   113  			Push(h, 20+i)
   114  		}
   115  		h.verify(t, 0)
   116  		if x != i {
   117  			t.Errorf("%d.th pop got %d; want %d", i, x, i)
   118  		}
   119  	}
   120  }
   121  
   122  func TestRemove0(t *testing.T) {
   123  	h := new(myHeap)
   124  	for i := 0; i < 10; i++ {
   125  		h.Push(i)
   126  	}
   127  	h.verify(t, 0)
   128  
   129  	for h.Len() > 0 {
   130  		i := h.Len() - 1
   131  		x := Remove(h, i).(int) // 删除第i位 堆化调整最小堆
   132  		if x != i {
   133  			t.Errorf("Remove(%d) got %d; want %d", i, x, i)
   134  		}
   135  		h.verify(t, 0)
   136  	}
   137  }
   138  
   139  func TestRemove1(t *testing.T) {
   140  	h := new(myHeap)
   141  	for i := 0; i < 10; i++ {
   142  		h.Push(i)
   143  	}
   144  	h.verify(t, 0)
   145  
   146  	for i := 0; h.Len() > 0; i++ {
   147  		x := Remove(h, 0).(int) // 每次都是删除堆顶调整最小堆
   148  		if x != i {
   149  			t.Errorf("Remove(0) got %d; want %d", x, i)
   150  		}
   151  		h.verify(t, 0)
   152  	}
   153  }
   154  
   155  func TestRemove2(t *testing.T) {
   156  	N := 10
   157  
   158  	h := new(myHeap)
   159  	for i := 0; i < N; i++ {
   160  		h.Push(i)
   161  	}
   162  	h.verify(t, 0)
   163  
   164  	m := make(map[int]bool)
   165  	for h.Len() > 0 {
   166  		m[Remove(h, (h.Len()-1)/2).(int)] = true
   167  		h.verify(t, 0)
   168  	}
   169  
   170  	if len(m) != N {
   171  		t.Errorf("len(m) = %d; want %d", len(m), N)
   172  	}
   173  	for i := 0; i < len(m); i++ {
   174  		if !m[i] {
   175  			t.Errorf("m[%d] doesn't exist", i)
   176  		}
   177  	}
   178  }
   179  
   180  func BenchmarkDup(b *testing.B) {
   181  	const n = 10000
   182  	h := make(myHeap, 0, n)
   183  	for i := 0; i < b.N; i++ {
   184  		for j := 0; j < n; j++ {
   185  			Push(&h, 0) // all elements are the same
   186  		}
   187  		for h.Len() > 0 {
   188  			Pop(&h)
   189  		}
   190  	}
   191  }
   192  
   193  func TestFix(t *testing.T) { // 测试修复值之后 堆化调整最小堆, 这个比删除这个值 再插入一个新元素效率更高
   194  	h := new(myHeap)
   195  	h.verify(t, 0)
   196  
   197  	for i := 200; i > 0; i -= 10 {
   198  		Push(h, i)
   199  	}
   200  	h.verify(t, 0)
   201  
   202  	if (*h)[0] != 10 {
   203  		t.Fatalf("Expected head to be 10, was %d", (*h)[0])
   204  	}
   205  	(*h)[0] = 210 // 修改堆顶元素
   206  	Fix(h, 0)     // 调整堆顶0 位置, 堆化最小堆
   207  	h.verify(t, 0)
   208  
   209  	for i := 100; i > 0; i-- {
   210  		elem := rand.Intn(h.Len()) // 随机调整,随机堆化并验证
   211  		if i&1 == 0 {
   212  			(*h)[elem] *= 2
   213  		} else {
   214  			(*h)[elem] /= 2
   215  		}
   216  		Fix(h, elem)
   217  		h.verify(t, 0)
   218  	}
   219  }