github.com/songzhibin97/go-baseutils@v0.0.2-0.20240302024150-487d8ce9c082/structure/trees/binaryheap/binaryheap_test.go (about)

     1  package binaryheap
     2  
     3  import (
     4  	"encoding/json"
     5  	"math/rand"
     6  	"strings"
     7  	"testing"
     8  )
     9  
    10  func TestBinaryHeapPush(t *testing.T) {
    11  	heap := NewWithIntComparator()
    12  
    13  	if actualValue := heap.Empty(); actualValue != true {
    14  		t.Errorf("Got %v expected %v", actualValue, true)
    15  	}
    16  
    17  	heap.Push(3)
    18  	heap.Push(2)
    19  	heap.Push(1)
    20  
    21  	if actualValue := heap.Values(); actualValue[0] != 1 || actualValue[1] != 2 || actualValue[2] != 3 {
    22  		t.Errorf("Got %v expected %v", actualValue, "[1,2,3]")
    23  	}
    24  	if actualValue := heap.Empty(); actualValue != false {
    25  		t.Errorf("Got %v expected %v", actualValue, false)
    26  	}
    27  	if actualValue := heap.Size(); actualValue != 3 {
    28  		t.Errorf("Got %v expected %v", actualValue, 3)
    29  	}
    30  	if actualValue, ok := heap.Peek(); actualValue != 1 || !ok {
    31  		t.Errorf("Got %v expected %v", actualValue, 1)
    32  	}
    33  }
    34  
    35  func TestBinaryHeapPushBulk(t *testing.T) {
    36  	heap := NewWithIntComparator()
    37  
    38  	heap.Push(15, 20, 3, 1, 2)
    39  
    40  	if actualValue := heap.Values(); actualValue[0] != 1 || actualValue[1] != 2 || actualValue[2] != 3 {
    41  		t.Errorf("Got %v expected %v", actualValue, "[1,2,3]")
    42  	}
    43  	if actualValue, ok := heap.Pop(); actualValue != 1 || !ok {
    44  		t.Errorf("Got %v expected %v", actualValue, 1)
    45  	}
    46  }
    47  
    48  func TestBinaryHeapPop(t *testing.T) {
    49  	heap := NewWithIntComparator()
    50  
    51  	if actualValue := heap.Empty(); actualValue != true {
    52  		t.Errorf("Got %v expected %v", actualValue, true)
    53  	}
    54  
    55  	heap.Push(3)
    56  	heap.Push(2)
    57  	heap.Push(1)
    58  	heap.Pop()
    59  
    60  	if actualValue, ok := heap.Peek(); actualValue != 2 || !ok {
    61  		t.Errorf("Got %v expected %v", actualValue, 2)
    62  	}
    63  	if actualValue, ok := heap.Pop(); actualValue != 2 || !ok {
    64  		t.Errorf("Got %v expected %v", actualValue, 2)
    65  	}
    66  	if actualValue, ok := heap.Pop(); actualValue != 3 || !ok {
    67  		t.Errorf("Got %v expected %v", actualValue, 3)
    68  	}
    69  	if actualValue, ok := heap.Pop(); actualValue != 0 || ok {
    70  		t.Errorf("Got %v expected %v", actualValue, nil)
    71  	}
    72  	if actualValue := heap.Empty(); actualValue != true {
    73  		t.Errorf("Got %v expected %v", actualValue, true)
    74  	}
    75  	if actualValue := heap.Values(); len(actualValue) != 0 {
    76  		t.Errorf("Got %v expected %v", actualValue, "[]")
    77  	}
    78  }
    79  
    80  func TestBinaryHeapRandom(t *testing.T) {
    81  	heap := NewWithIntComparator()
    82  
    83  	rand.Seed(3)
    84  	for i := 0; i < 10000; i++ {
    85  		r := int(rand.Int31n(30))
    86  		heap.Push(r)
    87  	}
    88  
    89  	prev, _ := heap.Pop()
    90  	for !heap.Empty() {
    91  		curr, _ := heap.Pop()
    92  		if prev > curr {
    93  			t.Errorf("Heap property invalidated. prev: %v current: %v", prev, curr)
    94  		}
    95  		prev = curr
    96  	}
    97  }
    98  
    99  func TestBinaryHeapIteratorOnEmpty(t *testing.T) {
   100  	heap := NewWithIntComparator()
   101  	it := heap.Iterator()
   102  	for it.Next() {
   103  		t.Errorf("Shouldn't iterate on empty heap")
   104  	}
   105  }
   106  
   107  func TestBinaryHeapIteratorNext(t *testing.T) {
   108  	heap := NewWithIntComparator()
   109  	heap.Push(3)
   110  	heap.Push(2)
   111  	heap.Push(1)
   112  
   113  	it := heap.Iterator()
   114  	count := 0
   115  	for it.Next() {
   116  		count++
   117  		index := it.Index()
   118  		value := it.Value()
   119  		switch index {
   120  		case 0:
   121  			if actualValue, expectedValue := value, 1; actualValue != expectedValue {
   122  				t.Errorf("Got %v expected %v", actualValue, expectedValue)
   123  			}
   124  		case 1:
   125  			if actualValue, expectedValue := value, 2; actualValue != expectedValue {
   126  				t.Errorf("Got %v expected %v", actualValue, expectedValue)
   127  			}
   128  		case 2:
   129  			if actualValue, expectedValue := value, 3; actualValue != expectedValue {
   130  				t.Errorf("Got %v expected %v", actualValue, expectedValue)
   131  			}
   132  		default:
   133  			t.Errorf("Too many")
   134  		}
   135  		if actualValue, expectedValue := index, count-1; actualValue != expectedValue {
   136  			t.Errorf("Got %v expected %v", actualValue, expectedValue)
   137  		}
   138  	}
   139  	if actualValue, expectedValue := count, 3; actualValue != expectedValue {
   140  		t.Errorf("Got %v expected %v", actualValue, expectedValue)
   141  	}
   142  }
   143  
   144  func TestBinaryHeapIteratorPrev(t *testing.T) {
   145  	heap := NewWithIntComparator()
   146  	heap.Push(3)
   147  	heap.Push(2)
   148  	heap.Push(1)
   149  
   150  	it := heap.Iterator()
   151  	for it.Next() {
   152  	}
   153  	count := 0
   154  	for it.Prev() {
   155  		count++
   156  		index := it.Index()
   157  		value := it.Value()
   158  		switch index {
   159  		case 0:
   160  			if actualValue, expectedValue := value, 1; actualValue != expectedValue {
   161  				t.Errorf("Got %v expected %v", actualValue, expectedValue)
   162  			}
   163  		case 1:
   164  			if actualValue, expectedValue := value, 2; actualValue != expectedValue {
   165  				t.Errorf("Got %v expected %v", actualValue, expectedValue)
   166  			}
   167  		case 2:
   168  			if actualValue, expectedValue := value, 3; actualValue != expectedValue {
   169  				t.Errorf("Got %v expected %v", actualValue, expectedValue)
   170  			}
   171  		default:
   172  			t.Errorf("Too many")
   173  		}
   174  		if actualValue, expectedValue := index, 3-count; actualValue != expectedValue {
   175  			t.Errorf("Got %v expected %v", actualValue, expectedValue)
   176  		}
   177  	}
   178  	if actualValue, expectedValue := count, 3; actualValue != expectedValue {
   179  		t.Errorf("Got %v expected %v", actualValue, expectedValue)
   180  	}
   181  }
   182  
   183  func TestBinaryHeapIteratorBegin(t *testing.T) {
   184  	heap := NewWithIntComparator()
   185  	it := heap.Iterator()
   186  	it.Begin()
   187  	heap.Push(2)
   188  	heap.Push(3)
   189  	heap.Push(1)
   190  	for it.Next() {
   191  	}
   192  	it.Begin()
   193  	it.Next()
   194  	if index, value := it.Index(), it.Value(); index != 0 || value != 1 {
   195  		t.Errorf("Got %v,%v expected %v,%v", index, value, 0, 1)
   196  	}
   197  }
   198  
   199  func TestBinaryHeapIteratorEnd(t *testing.T) {
   200  	heap := NewWithIntComparator()
   201  	it := heap.Iterator()
   202  
   203  	if index := it.Index(); index != -1 {
   204  		t.Errorf("Got %v expected %v", index, -1)
   205  	}
   206  
   207  	it.End()
   208  	if index := it.Index(); index != 0 {
   209  		t.Errorf("Got %v expected %v", index, 0)
   210  	}
   211  
   212  	heap.Push(3)
   213  	heap.Push(2)
   214  	heap.Push(1)
   215  	it.End()
   216  	if index := it.Index(); index != heap.Size() {
   217  		t.Errorf("Got %v expected %v", index, heap.Size())
   218  	}
   219  
   220  	it.Prev()
   221  	if index, value := it.Index(), it.Value(); index != heap.Size()-1 || value != 3 {
   222  		t.Errorf("Got %v,%v expected %v,%v", index, value, heap.Size()-1, 3)
   223  	}
   224  }
   225  
   226  func TestBinaryHeapIteratorFirst(t *testing.T) {
   227  	heap := NewWithIntComparator()
   228  	it := heap.Iterator()
   229  	if actualValue, expectedValue := it.First(), false; actualValue != expectedValue {
   230  		t.Errorf("Got %v expected %v", actualValue, expectedValue)
   231  	}
   232  	heap.Push(3)
   233  	heap.Push(2)
   234  	heap.Push(1)
   235  	if actualValue, expectedValue := it.First(), true; actualValue != expectedValue {
   236  		t.Errorf("Got %v expected %v", actualValue, expectedValue)
   237  	}
   238  	if index, value := it.Index(), it.Value(); index != 0 || value != 1 {
   239  		t.Errorf("Got %v,%v expected %v,%v", index, value, 0, 1)
   240  	}
   241  }
   242  
   243  func TestBinaryHeapIteratorLast(t *testing.T) {
   244  	tree := NewWithIntComparator()
   245  	it := tree.Iterator()
   246  	if actualValue, expectedValue := it.Last(), false; actualValue != expectedValue {
   247  		t.Errorf("Got %v expected %v", actualValue, expectedValue)
   248  	}
   249  	tree.Push(2)
   250  	tree.Push(3)
   251  	tree.Push(1)
   252  	if actualValue, expectedValue := it.Last(), true; actualValue != expectedValue {
   253  		t.Errorf("Got %v expected %v", actualValue, expectedValue)
   254  	}
   255  	if index, value := it.Index(), it.Value(); index != 2 || value != 3 {
   256  		t.Errorf("Got %v,%v expected %v,%v", index, value, 2, 3)
   257  	}
   258  }
   259  
   260  func TestBinaryHeapIteratorNextTo(t *testing.T) {
   261  	// Sample seek function, i.e. string starting with "b"
   262  	seek := func(index int, value string) bool {
   263  		return strings.HasSuffix(value, "b")
   264  	}
   265  
   266  	// NextTo (empty)
   267  	{
   268  		tree := NewWithStringComparator()
   269  		it := tree.Iterator()
   270  		for it.NextTo(seek) {
   271  			t.Errorf("Shouldn't iterate on empty list")
   272  		}
   273  	}
   274  
   275  	// NextTo (not found)
   276  	{
   277  		tree := NewWithStringComparator()
   278  		tree.Push("xx")
   279  		tree.Push("yy")
   280  		it := tree.Iterator()
   281  		for it.NextTo(seek) {
   282  			t.Errorf("Shouldn't iterate on empty list")
   283  		}
   284  	}
   285  
   286  	// NextTo (found)
   287  	{
   288  		tree := NewWithStringComparator()
   289  		tree.Push("aa")
   290  		tree.Push("bb")
   291  		tree.Push("cc")
   292  		it := tree.Iterator()
   293  		it.Begin()
   294  		if !it.NextTo(seek) {
   295  			t.Errorf("Shouldn't iterate on empty list")
   296  		}
   297  		if index, value := it.Index(), it.Value(); index != 1 || value != "bb" {
   298  			t.Errorf("Got %v,%v expected %v,%v", index, value, 1, "bb")
   299  		}
   300  		if !it.Next() {
   301  			t.Errorf("Should go to first element")
   302  		}
   303  		if index, value := it.Index(), it.Value(); index != 2 || value != "cc" {
   304  			t.Errorf("Got %v,%v expected %v,%v", index, value, 2, "cc")
   305  		}
   306  		if it.Next() {
   307  			t.Errorf("Should not go past last element")
   308  		}
   309  	}
   310  }
   311  
   312  func TestBinaryHeapIteratorPrevTo(t *testing.T) {
   313  	// Sample seek function, i.e. string starting with "b"
   314  	seek := func(index int, value string) bool {
   315  		return strings.HasSuffix(value, "b")
   316  	}
   317  
   318  	// PrevTo (empty)
   319  	{
   320  		tree := NewWithStringComparator()
   321  		it := tree.Iterator()
   322  		it.End()
   323  		for it.PrevTo(seek) {
   324  			t.Errorf("Shouldn't iterate on empty list")
   325  		}
   326  	}
   327  
   328  	// PrevTo (not found)
   329  	{
   330  		tree := NewWithStringComparator()
   331  		tree.Push("xx")
   332  		tree.Push("yy")
   333  		it := tree.Iterator()
   334  		it.End()
   335  		for it.PrevTo(seek) {
   336  			t.Errorf("Shouldn't iterate on empty list")
   337  		}
   338  	}
   339  
   340  	// PrevTo (found)
   341  	{
   342  		tree := NewWithStringComparator()
   343  		tree.Push("aa")
   344  		tree.Push("bb")
   345  		tree.Push("cc")
   346  		it := tree.Iterator()
   347  		it.End()
   348  		if !it.PrevTo(seek) {
   349  			t.Errorf("Shouldn't iterate on empty list")
   350  		}
   351  		if index, value := it.Index(), it.Value(); index != 1 || value != "bb" {
   352  			t.Errorf("Got %v,%v expected %v,%v", index, value, 1, "bb")
   353  		}
   354  		if !it.Prev() {
   355  			t.Errorf("Should go to first element")
   356  		}
   357  		if index, value := it.Index(), it.Value(); index != 0 || value != "aa" {
   358  			t.Errorf("Got %v,%v expected %v,%v", index, value, 0, "aa")
   359  		}
   360  		if it.Prev() {
   361  			t.Errorf("Should not go before first element")
   362  		}
   363  	}
   364  }
   365  
   366  func TestBinaryHeapSerialization(t *testing.T) {
   367  	heap := NewWithStringComparator()
   368  
   369  	heap.Push("c")
   370  	heap.Push("b")
   371  	heap.Push("a")
   372  
   373  	var err error
   374  	assert := func() {
   375  		if actualValue := heap.Values(); actualValue[0] != "a" || actualValue[1] != "b" || actualValue[2] != "c" {
   376  			t.Errorf("Got %v expected %v", actualValue, "[1,3,2]")
   377  		}
   378  		if actualValue := heap.Size(); actualValue != 3 {
   379  			t.Errorf("Got %v expected %v", actualValue, 3)
   380  		}
   381  		if actualValue, ok := heap.Peek(); actualValue != "a" || !ok {
   382  			t.Errorf("Got %v expected %v", actualValue, "a")
   383  		}
   384  		if err != nil {
   385  			t.Errorf("Got error %v", err)
   386  		}
   387  	}
   388  
   389  	assert()
   390  
   391  	bytes, err := heap.MarshalJSON()
   392  	assert()
   393  
   394  	err = heap.UnmarshalJSON(bytes)
   395  	assert()
   396  
   397  	bytes, err = json.Marshal([]interface{}{"a", "b", "c", heap})
   398  	if err != nil {
   399  		t.Errorf("Got error %v", err)
   400  	}
   401  
   402  	err = json.Unmarshal([]byte(`["1","2","3"]`), &heap)
   403  	if err != nil {
   404  		t.Errorf("Got error %v", err)
   405  	}
   406  }
   407  
   408  func TestBTreeString(t *testing.T) {
   409  	c := NewWithIntComparator()
   410  	c.Push(1)
   411  	if !strings.HasPrefix(c.String(), "BinaryHeap") {
   412  		t.Errorf("String should start with container name")
   413  	}
   414  }
   415  
   416  func benchmarkPush[E int](b *testing.B, heap *Heap[E], size int) {
   417  	for i := 0; i < b.N; i++ {
   418  		for n := 0; n < size; n++ {
   419  			heap.Push(E(n))
   420  		}
   421  	}
   422  }
   423  
   424  func benchmarkPop[E int](b *testing.B, heap *Heap[E], size int) {
   425  	for i := 0; i < b.N; i++ {
   426  		for n := 0; n < size; n++ {
   427  			heap.Pop()
   428  		}
   429  	}
   430  }
   431  
   432  func BenchmarkBinaryHeapPop100(b *testing.B) {
   433  	b.StopTimer()
   434  	size := 100
   435  	heap := NewWithIntComparator()
   436  	for n := 0; n < size; n++ {
   437  		heap.Push(n)
   438  	}
   439  	b.StartTimer()
   440  	benchmarkPop(b, heap, size)
   441  }
   442  
   443  func BenchmarkBinaryHeapPop1000(b *testing.B) {
   444  	b.StopTimer()
   445  	size := 1000
   446  	heap := NewWithIntComparator()
   447  	for n := 0; n < size; n++ {
   448  		heap.Push(n)
   449  	}
   450  	b.StartTimer()
   451  	benchmarkPop(b, heap, size)
   452  }
   453  
   454  func BenchmarkBinaryHeapPop10000(b *testing.B) {
   455  	b.StopTimer()
   456  	size := 10000
   457  	heap := NewWithIntComparator()
   458  	for n := 0; n < size; n++ {
   459  		heap.Push(n)
   460  	}
   461  	b.StartTimer()
   462  	benchmarkPop(b, heap, size)
   463  }
   464  
   465  func BenchmarkBinaryHeapPop100000(b *testing.B) {
   466  	b.StopTimer()
   467  	size := 100000
   468  	heap := NewWithIntComparator()
   469  	for n := 0; n < size; n++ {
   470  		heap.Push(n)
   471  	}
   472  	b.StartTimer()
   473  	benchmarkPop(b, heap, size)
   474  }
   475  
   476  func BenchmarkBinaryHeapPush100(b *testing.B) {
   477  	b.StopTimer()
   478  	size := 100
   479  	heap := NewWithIntComparator()
   480  	b.StartTimer()
   481  	benchmarkPush(b, heap, size)
   482  }
   483  
   484  func BenchmarkBinaryHeapPush1000(b *testing.B) {
   485  	b.StopTimer()
   486  	size := 1000
   487  	heap := NewWithIntComparator()
   488  	for n := 0; n < size; n++ {
   489  		heap.Push(n)
   490  	}
   491  	b.StartTimer()
   492  	benchmarkPush(b, heap, size)
   493  }
   494  
   495  func BenchmarkBinaryHeapPush10000(b *testing.B) {
   496  	b.StopTimer()
   497  	size := 10000
   498  	heap := NewWithIntComparator()
   499  	for n := 0; n < size; n++ {
   500  		heap.Push(n)
   501  	}
   502  	b.StartTimer()
   503  	benchmarkPush(b, heap, size)
   504  }
   505  
   506  func BenchmarkBinaryHeapPush100000(b *testing.B) {
   507  	b.StopTimer()
   508  	size := 100000
   509  	heap := NewWithIntComparator()
   510  	for n := 0; n < size; n++ {
   511  		heap.Push(n)
   512  	}
   513  	b.StartTimer()
   514  	benchmarkPush(b, heap, size)
   515  }