forked from krahets/hello-algo
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(tree): add binary search tree in golang
- Loading branch information
Showing
3 changed files
with
208 additions
and
5 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,5 @@ | ||
// File: binary_search_tree.go | ||
// Created Time: 2022-11-25 | ||
// Created Time: 2022-11-26 | ||
// Author: Reanon ([email protected]) | ||
|
||
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) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
// File: binary_search_tree_test.go | ||
// Created Time: 2022-11-26 | ||
// Author: Reanon ([email protected]) | ||
|
||
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() | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters