go.charczuk.com@v0.0.0-20240327042549-bc490516bd1a/sdk/collections/binary_search_tree_test.go (about)

     1  /*
     2  
     3  Copyright (c) 2023 - Present. Will Charczuk. All rights reserved.
     4  Use of this source code is governed by a MIT license that can be found in the LICENSE file at the root of the repository.
     5  
     6  */
     7  
     8  package collections
     9  
    10  import (
    11  	"cmp"
    12  	"fmt"
    13  	"strings"
    14  	"testing"
    15  
    16  	. "go.charczuk.com/sdk/assert"
    17  )
    18  
    19  func Test_BinarySearchTree_basic(t *testing.T) {
    20  	bst := new(BinarySearchTree[int, string])
    21  	for x := 0; x < 100; x++ {
    22  		bst.Insert(makeKeyValue(x)())
    23  	}
    24  
    25  	minKey, minValue, ok := bst.Min()
    26  	ItsEqual(t, true, ok)
    27  	ItsEqual(t, 0, minKey)
    28  	ItsEqual(t, "value-0", minValue)
    29  
    30  	maxKey, maxValue, ok := bst.Max()
    31  	ItsEqual(t, true, ok)
    32  	ItsEqual(t, 99, maxKey)
    33  	ItsEqual(t, "value-99", maxValue)
    34  
    35  	for x := 0; x < 100; x++ {
    36  		value, ok := bst.Search(x)
    37  		ItsEqual(t, true, ok)
    38  		ItsEqual(t, fmt.Sprintf("value-%d", x), value)
    39  	}
    40  
    41  	_, ok = bst.Search(-1)
    42  	ItsEqual(t, false, ok)
    43  
    44  	_, ok = bst.Search(101)
    45  	ItsEqual(t, false, ok)
    46  
    47  	for x := 0; x < 100; x++ {
    48  		bst.Delete(x)
    49  	}
    50  
    51  	for x := 0; x < 100; x++ {
    52  		_, ok = bst.Search(x)
    53  		ItsEqual(t, false, ok)
    54  	}
    55  
    56  	// test insert overwrite
    57  	bst.Insert(makeKeyValue(10)())
    58  	bst.Insert(makeKeyValue(20)())
    59  
    60  	bst.Insert(10, "not-value-10")
    61  
    62  	value, ok := bst.Search(10)
    63  	ItsEqual(t, true, ok)
    64  	ItsEqual(t, "not-value-10", value)
    65  
    66  	value, ok = bst.Search(20)
    67  	ItsEqual(t, true, ok)
    68  	ItsEqual(t, "value-20", value)
    69  }
    70  
    71  func Test_BinarySearchTree_acceptance(t *testing.T) {
    72  	inputs := []int{
    73  		81, 87, 47, 59, 83,
    74  		18, 25, 40, 56, 0,
    75  		94, 11, 62, 89, 28,
    76  		74, 12, 45, 37, 6,
    77  		95, 66, 29, 58, 101,
    78  	}
    79  
    80  	bst := new(BinarySearchTree[int, string])
    81  	for _, x := range inputs {
    82  		bst.Insert(makeKeyValue(x)())
    83  	}
    84  
    85  	node := func(k, height int, left, right *BinarySearchTreeNode[int, string]) *BinarySearchTreeNode[int, string] {
    86  		return &BinarySearchTreeNode[int, string]{
    87  			Key:    k,
    88  			Height: height,
    89  			Left:   left,
    90  			Right:  right,
    91  		}
    92  	}
    93  
    94  	goldenBST := &BinarySearchTree[int, string]{
    95  		root: node(47, 5,
    96  			node(25, 4,
    97  				node(11, 3,
    98  					node(0, 2, nil, node(6, 1, nil, nil)),
    99  					node(18, 2, node(12, 1, nil, nil), nil),
   100  				),
   101  				node(40, 3,
   102  					node(29, 2, node(28, 1, nil, nil), node(37, 1, nil, nil)),
   103  					node(45, 1, nil, nil),
   104  				),
   105  			),
   106  			node(81, 4,
   107  				node(59, 3,
   108  					node(56, 2, nil, node(58, 1, nil, nil)),
   109  					node(66, 2,
   110  						node(62, 1, nil, nil),
   111  						node(74, 1, nil, nil),
   112  					),
   113  				),
   114  				node(94, 3,
   115  					node(87, 2,
   116  						node(83, 1, nil, nil),
   117  						node(89, 1, nil, nil),
   118  					),
   119  					node(95, 2, nil, node(101, 1, nil, nil)),
   120  				),
   121  			),
   122  		),
   123  	}
   124  	ItsEqual(t, printTree(goldenBST), printTree(bst))
   125  	ItsEqual(t, true, goldenBST.KeysEqual(bst), fmt.Sprintf("%s vs. %s", printTree(bst), printTree(goldenBST)))
   126  
   127  	// delete 3 nodes, causing a rotation on the right side
   128  
   129  	bst.Delete(94)
   130  	bst.Delete(95)
   131  
   132  	bst.Delete(89)
   133  	bst.Delete(101)
   134  	bst.Delete(83)
   135  
   136  	goldenBST2 := &BinarySearchTree[int, string]{
   137  		root: node(47, 5,
   138  			node(25, 4,
   139  				node(11, 3,
   140  					node(0, 2, nil, node(6, 1, nil, nil)),
   141  					node(18, 2, node(12, 1, nil, nil), nil),
   142  				),
   143  				node(40, 3,
   144  					node(29, 2, node(28, 1, nil, nil), node(37, 1, nil, nil)),
   145  					node(45, 1, nil, nil),
   146  				),
   147  			),
   148  			node(59, 4,
   149  				node(56, 2,
   150  					nil,
   151  					node(58, 1, nil, nil),
   152  				),
   153  				node(81, 3,
   154  					node(66, 2,
   155  						node(62, 1, nil, nil),
   156  						node(74, 1, nil, nil),
   157  					),
   158  					node(87, 1, nil, nil),
   159  				),
   160  			),
   161  		),
   162  	}
   163  
   164  	ItsEqual(t, printTree(goldenBST2), printTree(bst))
   165  	ItsEqual(t, true, goldenBST2.KeysEqual(bst), fmt.Sprintf("%s vs. %s", printTree(bst), printTree(goldenBST2)))
   166  }
   167  
   168  func Test_BinarySearchTree_InOrder(t *testing.T) {
   169  	bst := new(BinarySearchTree[int, string])
   170  	for x := 0; x < 5; x++ {
   171  		bst.Insert(makeKeyValue(x)())
   172  	}
   173  	ItsEqual(t, 1, bst.root.Key)
   174  
   175  	var keys []int
   176  	bst.InOrder(func(k int, _ string) {
   177  		keys = append(keys, k)
   178  	})
   179  	ItsEqual(t, []int{0, 1, 2, 3, 4}, keys)
   180  }
   181  
   182  func Test_BinarySearchTree_PreOrder(t *testing.T) {
   183  	bst := new(BinarySearchTree[int, string])
   184  	for x := 0; x < 5; x++ {
   185  		bst.Insert(makeKeyValue(x)())
   186  	}
   187  	ItsEqual(t, 1, bst.root.Key)
   188  
   189  	var keys []int
   190  	bst.PreOrder(func(k int, _ string) {
   191  		keys = append(keys, k)
   192  	})
   193  	ItsEqual(t, []int{1, 0, 3, 2, 4}, keys)
   194  }
   195  
   196  func Test_BinarySearchTree_PostOrder(t *testing.T) {
   197  	bst := new(BinarySearchTree[int, string])
   198  	for x := 0; x < 5; x++ {
   199  		bst.Insert(makeKeyValue(x)())
   200  	}
   201  	ItsEqual(t, 1, bst.root.Key)
   202  
   203  	var keys []int
   204  	bst.PostOrder(func(k int, _ string) {
   205  		keys = append(keys, k)
   206  	})
   207  	ItsEqual(t, []int{0, 2, 4, 3, 1}, keys)
   208  }
   209  
   210  func Test_BinarySearchTree_unbalancedLeft(t *testing.T) {
   211  	bst := new(BinarySearchTree[int, string])
   212  	for x := 0; x < 100; x++ {
   213  		bst.Insert(makeKeyValue(x)())
   214  	}
   215  
   216  	for x := 0; x < 50; x++ {
   217  		bst.Delete(x)
   218  	}
   219  
   220  	ItsEqual(t, 79, bst.root.Key)
   221  }
   222  
   223  func Test_BinarySearchTree_reverse(t *testing.T) {
   224  	bst := new(BinarySearchTree[int, string])
   225  	for x := 99; x >= 0; x-- {
   226  		bst.Insert(makeKeyValue(x)())
   227  	}
   228  	ItsEqual(t, nil, verify(bst.root))
   229  	ItsEqual(t, 36, bst.root.Key)
   230  }
   231  
   232  //
   233  // bst test helpers
   234  //
   235  
   236  func makeKeyValue(x int) func() (int, string) {
   237  	return func() (int, string) {
   238  		return x, fmt.Sprintf("value-%d", x)
   239  	}
   240  }
   241  
   242  func printTree[K cmp.Ordered, V any](bst *BinarySearchTree[K, V]) string {
   243  	var keys []string
   244  	bst.InOrder(func(k K, _ V) {
   245  		keys = append(keys, fmt.Sprint(k))
   246  	})
   247  	return "[ " + strings.Join(keys, " ") + " ]"
   248  }
   249  
   250  func verify[K cmp.Ordered, V any](n *BinarySearchTreeNode[K, V]) error {
   251  	if n.Left != nil {
   252  		min := verifyMin(n)
   253  		if min.Key >= n.Key {
   254  			return fmt.Errorf("invalid min; %v is greater than parent %v", min.Key, n.Key)
   255  		}
   256  		if err := verify(n.Left); err != nil {
   257  			return err
   258  		}
   259  	}
   260  	if n.Right != nil {
   261  		max := verifyMax(n)
   262  		if max.Key <= n.Key {
   263  			return fmt.Errorf("invalid max; %v is less than parent %v", max.Key, n.Key)
   264  		}
   265  		if err := verify(n.Right); err != nil {
   266  			return err
   267  		}
   268  	}
   269  	return nil
   270  }
   271  
   272  func verifyMin[K cmp.Ordered, V any](n *BinarySearchTreeNode[K, V]) (min *BinarySearchTreeNode[K, V]) {
   273  	min = n
   274  	for min.Left != nil {
   275  		min = min.Left
   276  	}
   277  	return
   278  }
   279  
   280  func verifyMax[K cmp.Ordered, V any](n *BinarySearchTreeNode[K, V]) (max *BinarySearchTreeNode[K, V]) {
   281  	max = n
   282  	for max.Right != nil {
   283  		max = max.Right
   284  	}
   285  	return
   286  }
   287  
   288  func Test_max(t *testing.T) {
   289  	v := max[int]()
   290  	ItsEqual(t, 0, v)
   291  
   292  	v = max(1)
   293  	ItsEqual(t, 1, v)
   294  
   295  	v = max(1, 2, 3, 4)
   296  	ItsEqual(t, 4, v)
   297  }
   298  
   299  func Test_keysEqual(t *testing.T) {
   300  	bst := new(BinarySearchTree[int, func()])
   301  	ItsEqual(t, true, bst._keysEqual(nil, nil))
   302  
   303  	a := &BinarySearchTreeNode[int, func()]{
   304  		Key: 1,
   305  	}
   306  
   307  	ItsEqual(t, false, bst._keysEqual(a, nil))
   308  	ItsEqual(t, false, bst._keysEqual(nil, a))
   309  
   310  	b := &BinarySearchTreeNode[int, func()]{
   311  		Key: 2,
   312  	}
   313  	ItsEqual(t, false, bst._keysEqual(a, b))
   314  
   315  	a1 := &BinarySearchTreeNode[int, func()]{
   316  		Key:    1,
   317  		Height: 10,
   318  	}
   319  	ItsEqual(t, false, bst._keysEqual(a, a1))
   320  
   321  	a0 := &BinarySearchTreeNode[int, func()]{
   322  		Key: 1,
   323  	}
   324  	ItsEqual(t, true, bst._keysEqual(a, a0))
   325  }