// Copyright 2024 Matthew Rich . All rights reserved. package search import ( "log/slog" "cmp" "math" ) var ( ) const ( BSTDATAOFFSET = 1 BSTROOTNODEID = 0 LEFTOFFSET = 1 RIGHTOFFSET = 2 ) /* * Binary Search Tree using a slice */ type Binary[Key cmp.Ordered] []Key type BinaryTree[Key cmp.Ordered] struct { *Binary[Key] zeroIndex int least, greatest, lastNode int } func NewBinaryTree[Key cmp.Ordered](capacity int) (bst *BinaryTree[Key]) { tree := make(Binary[Key], 1, capacity) bst = &BinaryTree[Key]{ Binary: &tree, least: 0, greatest: 0, lastNode: 0 } return } func (b *Binary[Key]) Empty() Key { return (*b)[0] } func (b *Binary[Key]) IsInternal(index int) bool { childIdx := 2 * index return ! b.IsEmpty(childIdx + LEFTOFFSET) && ! b.IsEmpty(childIdx + RIGHTOFFSET) //return (*b)[leftIdx] != (*b)[0] && (*b)[leftIdx + 1] != (*b)[0] } func (b *Binary[Key]) IsRight(index int) bool { return index % 2 == 0 } func (b *Binary[Key]) Left(index int) int { return (2 * index) + LEFTOFFSET } func (b *Binary[Key]) Right(index int) int { return (2 * index) + RIGHTOFFSET } func (b *Binary[Key]) Get(index int) (Key) { return (*b)[index + BSTDATAOFFSET] } func (b *Binary[Key]) Set(index int, v Key) { (*b)[index + BSTDATAOFFSET] = v } func (b *BinaryTree[Key]) Set(index int, v Key) { b.Binary.Set(index, v) if v == b.Empty() { b.setZeroIndex(index) } b.setLastNode(index) } func (b *Binary[Key]) SetEmpty(index int) { (*b)[index + BSTDATAOFFSET] = b.Empty() } func (b *BinaryTree[Key]) SetEmpty(index int) { b.Binary.SetEmpty(index) if index == b.zeroIndex { b.setZeroIndex(-1) } b.setLastNode(index) } func (b *Binary[Key]) SetEmptyRange(start int, end int) { empty := b.Empty() for i := start; i <= end; i++ { (*b)[i + BSTDATAOFFSET] = empty } } func (b *BinaryTree[Key]) SetEmptyRange(start int, end int) { b.Binary.SetEmptyRange(start, end) if b.zeroIndex >= start && b.zeroIndex <= end { b.setZeroIndex(-1) } b.setLastNode(start) } func (b *BinaryTree[Key]) setZeroIndex(index int) { b.zeroIndex = index } func (b *BinaryTree[Key]) setLastNode(index int) { b.lastNode = max(b.lastNode, index) } func (b *BinaryTree[key]) LastNode() int { return b.lastNode } func (b *BinaryTree[key]) MaxDepth() int { return b.Depth(b.lastNode) } /* func (b *Binary[Key]) Median(index int) { length := len(*b) } */ func (b *Binary[Key]) Copy(from int, to int) { (*b)[to + BSTDATAOFFSET] = (*b)[from + BSTDATAOFFSET] } func (b *BinaryTree[Key]) Copy(from, to int) { b.Binary.Copy(from, to) if b.zeroIndex == from { b.setZeroIndex(to) } slog.Info("Copy()", "from", from, "to", to, "value", b.Get(from), "zero", b.zeroIndex) } func (b *Binary[Key]) LevelRange(index int, treeIndex int) (start int, end int) { treeDepth := b.Depth(treeIndex) depth := b.Depth(index) diff := depth - treeDepth switch diff { case 0: if index == treeIndex { return index, index } case 1: leftIdx := (2 * treeIndex) + 1 if index >= leftIdx && index <= leftIdx + 1 { return leftIdx, leftIdx + 1 } default: exp := int(math.Exp2(float64(diff))) level := exp * treeIndex childOffset := exp - 1 left := level + childOffset right := level + (childOffset * 2) return left, right } return -1, -1 } func (b *Binary[Key]) InSubTree(index, treeIndex int) bool { if treeIndex > index { return false } left, right := b.LevelRange(index, treeIndex) if index >= left && index <= right { return true } return false } func (b *BinaryTree[Key]) MoveSubTree(from, to int) { if ! b.IsLeaf(to) { panic("this move would overwrite the target subtree") } srccursor := b.Left(from) dstcursor := b.Left(to) for srccursor < b.lastNode && srccursor < len(*b.Binary) { srcstart, srcend := b.LevelRange(srccursor, from) dststart, dstend := b.LevelRange(dstcursor, to) slog.Info("MoveSubTree()", "srcstart", srcstart, "srcend", srcend, "dststart", dststart, "dstend", dstend, "source", (*b.Binary)[srcstart + BSTDATAOFFSET:srcend + BSTDATAOFFSET + 1], "dest", (*b.Binary)[dststart + BSTDATAOFFSET:dstend + BSTDATAOFFSET + 1]) copy((*b.Binary)[dststart + BSTDATAOFFSET:dstend + BSTDATAOFFSET + 1], (*b.Binary)[srcstart + BSTDATAOFFSET:srcend + BSTDATAOFFSET + 1]) b.SetEmptyRange(srcstart, srcend) srccursor = b.Left(srccursor) dstcursor = b.Left(dstcursor) slog.Info("MoveSubTree() post-copy", "srcstart", srcstart, "srcend", srcend, "dststart", dststart, "dstend", dstend, "data", b.Binary) } b.Copy(from, to) } func (b *Binary[Key]) IsLeaf(index int) bool { childIdx := 2 * (index) return (*b)[childIdx + LEFTOFFSET + BSTDATAOFFSET] == (*b)[childIdx + RIGHTOFFSET + BSTDATAOFFSET] } func (b *BinaryTree[Key]) IsLeaf(index int) bool { childIdx := 2 * (index) leftIdx := childIdx + LEFTOFFSET rightIdx := childIdx + RIGHTOFFSET return b.Get(leftIdx) == b.Get(rightIdx) && leftIdx != b.zeroIndex && rightIdx != b.zeroIndex } func (b *Binary[Key]) ParentIndex(index int) (parent int) { parent = index if b.IsRight(index) { parent -= RIGHTOFFSET } else { parent -= LEFTOFFSET } parent = parent / 2 return } func (b *Binary[Key]) Depth(index int) int { return int(math.Ceil(math.Log2(float64(index + 2)))) } func (b *Binary[Key]) Width(index int) int { return int(math.Exp2(float64(b.Depth(index) - 1))) } func (b *Binary[Key]) IsFullLevel(index int) bool { width := b.Width(index) start := width - 1 for _, v := range (*b)[start + BSTDATAOFFSET: start + width + BSTDATAOFFSET] { if v == b.Empty() { return false } } return true } func (b *Binary[Key]) IsEmpty(index int) bool { return (*b)[index + BSTDATAOFFSET] == b.Empty() } func (b *Binary[Key]) Ascend(idx int, item Key) int { if item < b.Get(idx) { return b.Left(idx) } return b.Right(idx) } func (b *Binary[Key]) Grow(index int) { size := len(*b) - BSTDATAOFFSET slog.Info("Grow()", "size", size, "index", index, "cap", cap(*b)) if index >= size / 2 { targetSize := (size + (2 * index + 1) * 3) + BSTDATAOFFSET if cap(*b) < targetSize { expandArray := make(Binary[Key], ((targetSize - cap(*b)) * 2) + BSTDATAOFFSET) *b = append(*b, expandArray...) slog.Info("Grow()", "size", size, "index", index, "targetsize", targetSize, "cap", cap(*b), "new", cap(expandArray)) } *b = (*b)[:targetSize] } slog.Info("Grow()", "size", len(*b)) } func (b *BinaryTree[Key]) RotateRight(index, right, left int) int { slog.Info("PreRotateRight", "index", index, "leftindex", left, "rightindex", right, "left", b.Get(left), "node", b.Get(index), "right", b.Get(right)) b.Copy(index, right) b.Copy(left, index) b.SetEmpty(left) slog.Info("RotateRight", "index", index, "leftindex", left, "rightindex", right, "left", b.Get(left), "node", b.Get(index), "right", b.Get(right)) return left } func (b *BinaryTree[Key]) RotateLeft(index, left, right int) int { slog.Info("PreRotateLeft", "index", index, "leftindex", left, "rightindex", right, "left", b.Get(left), "node", b.Get(index), "right", b.Get(right)) b.Copy(index, left) b.Copy(right, index) b.SetEmpty(right) slog.Info("RotateLeft", "index", index, "leftindex", left, "rightindex", right, "left", b.Get(left), "node", b.Get(index), "right", b.Get(right)) return right } /* func (b *Binary[Key]) Insert(item Key) (idx int) { idx = BSTROOTNODEID slog.Info("Insert()", "item", item) for { b.Grow(idx) if b.IsEmpty(idx) { b.Set(idx, item) return } else { rightIdx := b.Right(idx) leftIdx := b.Left(idx) if b.IsInternal(idx) { idx = b.Ascend(idx, item) } else if b.IsLeaf(idx) { idx = b.Ascend(idx, item) } else { slog.Info("Insert()", "item", item, "index", idx) if item < b.Get(idx) { if ! b.IsEmpty(rightIdx) { idx = leftIdx } else { if ! b.IsLeaf(leftIdx) { panic("the left node is not a leaf") } idx = b.RotateRight(idx, rightIdx, leftIdx) } } else { if ! b.IsEmpty(leftIdx) { idx = rightIdx } else { if ! b.IsLeaf(rightIdx) { panic("the right node is not a leaf") } idx = b.RotateLeft(idx, leftIdx, rightIdx) } } } } } } */ func (b *BinaryTree[Key]) Insert(item Key) (idx int) { idx = BSTROOTNODEID slog.Info("Insert()", "item", item) for { b.Grow(idx) if b.IsEmpty(idx) { b.Set(idx, item) return } else { rightIdx := b.Right(idx) leftIdx := b.Left(idx) if b.IsInternal(idx) { idx = b.Ascend(idx, item) } else if b.IsLeaf(idx) {// && b.IsFullLevel(idx) { /* if ! b.IsFullLevel(idx) { parent := b.ParentIndex(idx) if b.IsRight(parent) { idx = b.RotateLeft(parent, b.Left(parent), b.Right(parent)) } else { idx = b.RotateRight(parent, b.Right(parent), b.Left(parent)) } } */ idx = b.Ascend(idx, item) } else { slog.Info("Insert()", "item", item, "index", idx) if item < b.Get(idx) { // left slog.Info("Insert()", "item", item, "index", idx) if ! b.IsEmpty(rightIdx) { idx = leftIdx } else { if ! b.IsLeaf(leftIdx) { panic("the left node is not a leaf") } idx = b.RotateRight(idx, rightIdx, leftIdx) } } else { // right if ! b.IsEmpty(leftIdx) { idx = rightIdx } else { if ! b.IsLeaf(rightIdx) { idx = rightIdx //panic("the right node is not a leaf") } else { idx = b.RotateLeft(idx, leftIdx, rightIdx) } } } } } } } type BinaryBFSItem[Key cmp.Ordered] func(index int, depth int, v Key) func (b *Binary[Key]) BFS(c BinaryBFSItem[Key]) (depth int) { queue := []int{ BSTROOTNODEID } for len(queue) > 0 { x := queue[0] queue = queue[1:] depth = b.Depth(x) c(x, depth, b.Get(x)) leftIdx := b.Left(x) rightIdx := b.Right(x) if ! b.IsEmpty(leftIdx) { queue = append(queue, leftIdx) } if ! b.IsEmpty(rightIdx) { queue = append(queue, b.Right(x)) } } return }