diff --git a/codes/go/chapter_tree/binary_search_tree.go b/codes/go/chapter_tree/binary_search_tree.go index c21dc1444..26eb94d73 100644 --- a/codes/go/chapter_tree/binary_search_tree.go +++ b/codes/go/chapter_tree/binary_search_tree.go @@ -1,5 +1,5 @@ // File: binary_search_tree.go -// Created Time: 2022-11-25 +// Created Time: 2022-11-26 // Author: Reanon (793584285@qq.com) package chapter_tree @@ -14,7 +14,166 @@ type BinarySearchTree struct { } func NewBinarySearchTree(nums []int) *BinarySearchTree { - // 排序数组 + // sorting array sort.Ints(nums) - return nil + root := buildBinarySearchTree(nums, 0, len(nums)-1) + return &BinarySearchTree{ + root: root, + } +} + +// GetRoot Get the root node of binary search tree +func (bst *BinarySearchTree) GetRoot() *TreeNode { + return bst.root +} + +// GetMin Get node with the min value +func (bst *BinarySearchTree) GetMin(node *TreeNode) *TreeNode { + if node == nil { + return node + } + // 循环访问左子结点,直到叶结点时为最小结点,跳出 + for node.Left != nil { + node = node.Left + } + return node +} + +// GetInorderNext Get node inorder next +func (bst *BinarySearchTree) GetInorderNext(node *TreeNode) *TreeNode { + if node == nil || node.Right == nil { + return node + } + node = node.Right + // 循环访问左子结点,直到叶结点时为最小结点,跳出 + for node.Left != nil { + node = node.Left + } + return node +} + +// Search node of binary search tree +func (bst *BinarySearchTree) Search(num int) *TreeNode { + node := bst.root + // 循环查找,越过叶结点后跳出 + for node != nil { + if node.Val < num { + // 目标结点在 root 的右子树中 + node = node.Right + } else if node.Val > num { + // 目标结点在 root 的左子树中 + node = node.Left + } else { + // 找到目标结点,跳出循环 + break + } + } + // 返回目标结点 + return node +} + +// Insert node of binary search tree +func (bst *BinarySearchTree) Insert(num int) *TreeNode { + cur := bst.root + // 若树为空,直接提前返回 + if cur == nil { + return nil + } + // 待插入结点之前的结点位置 + var prev *TreeNode = nil + // 循环查找,越过叶结点后跳出 + for cur != nil { + if cur.Val == num { + return nil + } + prev = cur + if cur.Val < num { + cur = cur.Right + } else { + cur = cur.Left + } + } + // 插入结点 + node := NewTreeNode(num) + if prev.Val < num { + prev.Right = node + } else { + prev.Left = node + } + return cur +} + +// Remove node of binary search tree +func (bst *BinarySearchTree) Remove(num int) *TreeNode { + cur := bst.root + // 若树为空,直接提前返回 + if cur == nil { + return nil + } + // 待删除结点之前的结点位置 + var prev *TreeNode = nil + // 循环查找,越过叶结点后跳出 + for cur != nil { + if cur.Val == num { + break + } + prev = cur + // 待删除结点在右子树中 + if cur.Val < num { + cur = cur.Right + } else { + // 待删除结点在左子树中 + cur = cur.Left + } + } + // 若无待删除结点,则直接返回 + if cur == nil { + return nil + } + // 子结点数为 0 或 1 + if cur.Left == nil || cur.Right == nil { + var child *TreeNode = nil + // 取出待删除结点的子结点 + if cur.Left != nil { + child = cur.Left + } else { + child = cur.Right + } + // 将子结点替换为待删除结点 + if prev.Left == cur { + prev.Left = child + } else { + prev.Right = child + } + + } else { // 子结点数为 2 + // 获取中序遍历中待删除结点 cur 的下一个结点 + next := bst.GetInorderNext(cur) + temp := next.Val + // 递归删除结点 next + bst.Remove(next.Val) + // 将 next 的值复制给 cur + cur.Val = temp + } + // TODO: add error handler, don't return node + return cur +} + +// buildBinarySearchTree Build a binary search tree from array. +func buildBinarySearchTree(nums []int, left, right int) *TreeNode { + if left > right { + return nil + } + // 将数组中间结点作为根结点 + middle := left + (right-left)>>1 + root := NewTreeNode(nums[middle]) + // 递归构建左子树和右子树 + root.Left = buildBinarySearchTree(nums, left, middle-1) + root.Right = buildBinarySearchTree(nums, middle+1, right) + return root +} + +// Print binary search tree +func (bst *BinarySearchTree) Print() { + PrintTree(bst.root) } diff --git a/codes/go/chapter_tree/binary_search_tree_test.go b/codes/go/chapter_tree/binary_search_tree_test.go new file mode 100644 index 000000000..45d59bd8d --- /dev/null +++ b/codes/go/chapter_tree/binary_search_tree_test.go @@ -0,0 +1,44 @@ +// File: binary_search_tree_test.go +// Created Time: 2022-11-26 +// Author: Reanon (793584285@qq.com) + +package chapter_tree + +import "testing" + +func TestBinarySearchTree(t *testing.T) { + nums := []int{8, 9, 10, 11, 12, 13, 14, 15, 1, 2, 3, 4, 5, 6, 7} + bst := NewBinarySearchTree(nums) + t.Log("初始化的二叉树为: ") + bst.Print() + + // 获取根结点 + node := bst.GetRoot() + t.Log("二叉树的根结点为: ", node.Val) + // 获取最小的结点 + node = bst.GetMin(bst.GetRoot()) + t.Log("二叉树的最小结点为: ", node.Val) + + // 查找结点 + node = bst.Search(5) + t.Log("查找到的结点对象为", node, ",结点值 = ", node.Val) + + // 插入结点 + node = bst.Insert(16) + t.Log("插入结点后 16 的二叉树为: ") + bst.Print() + + // 删除结点 + bst.Remove(1) + t.Log("删除结点 1 后的二叉树为: ") + bst.Print() + bst.Remove(12) + t.Log("删除结点 12 后的二叉树为: ") + bst.Print() + bst.Remove(2) + t.Log("删除结点 2 后的二叉树为: ") + bst.Print() + bst.Remove(4) + t.Log("删除结点 4 后的二叉树为: ") + bst.Print() +} diff --git a/docs/chapter_tree/binary_search_tree.md b/docs/chapter_tree/binary_search_tree.md index a59493b25..a9514ec79 100644 --- a/docs/chapter_tree/binary_search_tree.md +++ b/docs/chapter_tree/binary_search_tree.md @@ -63,11 +63,11 @@ comments: true 给定一个待插入元素 `num` ,为了保持二叉搜索树 “左子树 < 根结点 < 右子树” 的性质,插入操作分为两步: -1. **查找插入位置:** 与查找操作类似,我们从根结点出发,根据当前节点值和 `num` 的大小关系循环向下搜索,直到越过叶结点(遍历到 $\text{null}$ )时跳出循环; +1. **查找插入位置:** 与查找操作类似,我们从根结点出发,根据当前结点值和 `num` 的大小关系循环向下搜索,直到越过叶结点(遍历到 $\text{null}$ )时跳出循环; 2. **在该位置插入结点:** 初始化结点 `num` ,将该结点放到 $\text{null}$ 的位置 ; -二叉搜索树不允许存在重复节点,否则将会违背其定义。因此若待插入结点在树中已经存在,则不执行插入,直接返回即可。 +二叉搜索树不允许存在重复结点,否则将会违背其定义。因此若待插入结点在树中已经存在,则不执行插入,直接返回即可。 ![bst_insert](binary_search_tree.assets/bst_insert.png)