diff --git a/codes/go/chapter_backtracking/preorder_traversal_i_compact.go b/codes/go/chapter_backtracking/preorder_traversal_i_compact.go index 2b9226579..f091a3bfc 100644 --- a/codes/go/chapter_backtracking/preorder_traversal_i_compact.go +++ b/codes/go/chapter_backtracking/preorder_traversal_i_compact.go @@ -13,7 +13,7 @@ func preOrderI(root *TreeNode, res *[]*TreeNode) { if root == nil { return } - if int(root.Val) == 7 { + if (root.Val).(int) == 7 { // 记录解 *res = append(*res, root) } diff --git a/codes/go/chapter_backtracking/preorder_traversal_ii_compact.go b/codes/go/chapter_backtracking/preorder_traversal_ii_compact.go index efca58942..d59bfa96c 100644 --- a/codes/go/chapter_backtracking/preorder_traversal_ii_compact.go +++ b/codes/go/chapter_backtracking/preorder_traversal_ii_compact.go @@ -15,7 +15,7 @@ func preOrderII(root *TreeNode, res *[][]*TreeNode, path *[]*TreeNode) { } // 尝试 *path = append(*path, root) - if int(root.Val) == 7 { + if root.Val.(int) == 7 { // 记录解 *res = append(*res, *path) } diff --git a/codes/go/chapter_backtracking/preorder_traversal_iii_compact.go b/codes/go/chapter_backtracking/preorder_traversal_iii_compact.go index a2c860efb..700371cda 100644 --- a/codes/go/chapter_backtracking/preorder_traversal_iii_compact.go +++ b/codes/go/chapter_backtracking/preorder_traversal_iii_compact.go @@ -16,7 +16,7 @@ func preOrderIII(root *TreeNode, res *[][]*TreeNode, path *[]*TreeNode) { } // 尝试 *path = append(*path, root) - if int(root.Val) == 7 { + if root.Val.(int) == 7 { // 记录解 *res = append(*res, *path) *path = (*path)[:len(*path)-1] diff --git a/codes/go/chapter_backtracking/preorder_traversal_test.go b/codes/go/chapter_backtracking/preorder_traversal_test.go index 69f569380..32d8b9621 100644 --- a/codes/go/chapter_backtracking/preorder_traversal_test.go +++ b/codes/go/chapter_backtracking/preorder_traversal_test.go @@ -13,7 +13,7 @@ import ( func TestPreorderTraversalICompact(t *testing.T) { /* 初始化二叉树 */ - root := ArrToTree([]any{1, 7, 3, 4, 5, 6, 7}) + root := SliceToTree([]any{1, 7, 3, 4, 5, 6, 7}) fmt.Println("\n初始化二叉树") PrintTree(root) @@ -30,7 +30,7 @@ func TestPreorderTraversalICompact(t *testing.T) { func TestPreorderTraversalIICompact(t *testing.T) { /* 初始化二叉树 */ - root := ArrToTree([]any{1, 7, 3, 4, 5, 6, 7}) + root := SliceToTree([]any{1, 7, 3, 4, 5, 6, 7}) fmt.Println("\n初始化二叉树") PrintTree(root) @@ -50,7 +50,7 @@ func TestPreorderTraversalIICompact(t *testing.T) { func TestPreorderTraversalIIICompact(t *testing.T) { /* 初始化二叉树 */ - root := ArrToTree([]any{1, 7, 3, 4, 5, 6, 7}) + root := SliceToTree([]any{1, 7, 3, 4, 5, 6, 7}) fmt.Println("\n初始化二叉树") PrintTree(root) @@ -70,7 +70,7 @@ func TestPreorderTraversalIIICompact(t *testing.T) { func TestPreorderTraversalIIITemplate(t *testing.T) { /* 初始化二叉树 */ - root := ArrToTree([]any{1, 7, 3, 4, 5, 6, 7}) + root := SliceToTree([]any{1, 7, 3, 4, 5, 6, 7}) fmt.Println("\n初始化二叉树") PrintTree(root) diff --git a/codes/go/chapter_tree/array_binary_tree.go b/codes/go/chapter_tree/array_binary_tree.go new file mode 100644 index 000000000..6b1131141 --- /dev/null +++ b/codes/go/chapter_tree/array_binary_tree.go @@ -0,0 +1,101 @@ +// File: array_binary_tree.go +// Created Time: 2023-07-24 +// Author: Reanon (793584285@qq.com) + +package chapter_tree + +/* 数组表示下的二叉树类 */ +type arrayBinaryTree struct { + tree []any +} + +/* 构造方法 */ +func newArrayBinaryTree(arr []any) *arrayBinaryTree { + return &arrayBinaryTree{ + tree: arr, + } +} + +/* 节点数量 */ +func (abt *arrayBinaryTree) size() int { + return len(abt.tree) +} + +/* 获取索引为 i 节点的值 */ +func (abt *arrayBinaryTree) val(i int) any { + // 若索引越界,则返回 null ,代表空位 + if i < 0 || i >= abt.size() { + return nil + } + return abt.tree[i] +} + +/* 获取索引为 i 节点的左子节点的索引 */ +func (abt *arrayBinaryTree) left(i int) int { + return 2*i + 1 +} + +/* 获取索引为 i 节点的右子节点的索引 */ +func (abt *arrayBinaryTree) right(i int) int { + return 2*i + 2 +} + +/* 获取索引为 i 节点的父节点的索引 */ +func (abt *arrayBinaryTree) parent(i int) int { + return (i - 1) / 2 +} + +/* 层序遍历 */ +func (abt *arrayBinaryTree) levelOrder() []any { + var res []any + // 直接遍历数组 + for i := 0; i < abt.size(); i++ { + if abt.val(i) != nil { + res = append(res, abt.val(i)) + } + } + return res +} + +/* 深度优先遍历 */ +func (abt *arrayBinaryTree) dfs(i int, order string, res *[]any) { + // 若为空位,则返回 + if abt.val(i) == nil { + return + } + // 前序遍历 + if order == "pre" { + *res = append(*res, abt.val(i)) + } + abt.dfs(abt.left(i), order, res) + // 中序遍历 + if order == "in" { + *res = append(*res, abt.val(i)) + } + abt.dfs(abt.right(i), order, res) + // 后序遍历 + if order == "post" { + *res = append(*res, abt.val(i)) + } +} + +/* 前序遍历 */ +func (abt *arrayBinaryTree) preOrder() []any { + var res []any + abt.dfs(0, "pre", &res) + return res +} + +/* 中序遍历 */ +func (abt *arrayBinaryTree) inOrder() []any { + var res []any + abt.dfs(0, "in", &res) + return res +} + +/* 后序遍历 */ +func (abt *arrayBinaryTree) postOrder() []any { + var res []any + abt.dfs(0, "post", &res) + return res +} diff --git a/codes/go/chapter_tree/array_binary_tree_test.go b/codes/go/chapter_tree/array_binary_tree_test.go new file mode 100644 index 000000000..6ee45a6ab --- /dev/null +++ b/codes/go/chapter_tree/array_binary_tree_test.go @@ -0,0 +1,47 @@ +// File: array_binary_tree_test.go +// Created Time: 2023-07-24 +// Author: Reanon (793584285@qq.com) + +package chapter_tree + +import ( + "fmt" + "testing" + + . "github.com/krahets/hello-algo/pkg" +) + +func TestArrayBinaryTree(t *testing.T) { + // 初始化二叉树 + // 这里借助了一个从数组直接生成二叉树的函数 + arr := []any{1, 2, 3, 4, nil, 6, 7, 8, 9, nil, nil, 12, nil, nil, 15} + root := SliceToTree(arr) + fmt.Println("\n初始化二叉树") + fmt.Println("二叉树的数组表示:") + fmt.Println(arr) + fmt.Println("二叉树的链表表示:") + PrintTree(root) + + // 数组表示下的二叉树类 + abt := newArrayBinaryTree(arr) + + // 访问节点 + i := 1 + l := abt.left(i) + r := abt.right(i) + p := abt.parent(i) + fmt.Println("\n当前节点的索引为", i, ",值为", abt.val(i)) + fmt.Println("其左子节点的索引为", l, ",值为", abt.val(l)) + fmt.Println("其右子节点的索引为", r, ",值为", abt.val(r)) + fmt.Println("其父节点的索引为", p, ",值为", abt.val(p)) + + // 遍历树 + res := abt.levelOrder() + fmt.Println("\n层序遍历为:", res) + res = abt.preOrder() + fmt.Println("前序遍历为:", res) + res = abt.inOrder() + fmt.Println("中序遍历为:", res) + res = abt.postOrder() + fmt.Println("后序遍历为:", res) +} diff --git a/codes/go/chapter_tree/avl_tree.go b/codes/go/chapter_tree/avl_tree.go index 18b5daf2f..244813fe3 100644 --- a/codes/go/chapter_tree/avl_tree.go +++ b/codes/go/chapter_tree/avl_tree.go @@ -117,9 +117,9 @@ func (t *aVLTree) insertHelper(node *TreeNode, val int) *TreeNode { return NewTreeNode(val) } /* 1. 查找插入位置,并插入节点 */ - if val < node.Val { + if val < node.Val.(int) { node.Left = t.insertHelper(node.Left, val) - } else if val > node.Val { + } else if val > node.Val.(int) { node.Right = t.insertHelper(node.Right, val) } else { // 重复节点不插入,直接返回 @@ -144,9 +144,9 @@ func (t *aVLTree) removeHelper(node *TreeNode, val int) *TreeNode { return nil } /* 1. 查找节点,并删除之 */ - if val < node.Val { + if val < node.Val.(int) { node.Left = t.removeHelper(node.Left, val) - } else if val > node.Val { + } else if val > node.Val.(int) { node.Right = t.removeHelper(node.Right, val) } else { if node.Left == nil || node.Right == nil { @@ -167,7 +167,7 @@ func (t *aVLTree) removeHelper(node *TreeNode, val int) *TreeNode { for temp.Left != nil { temp = temp.Left } - node.Right = t.removeHelper(node.Right, temp.Val) + node.Right = t.removeHelper(node.Right, temp.Val.(int)) node.Val = temp.Val } } @@ -184,10 +184,10 @@ func (t *aVLTree) search(val int) *TreeNode { cur := t.root // 循环查找,越过叶节点后跳出 for cur != nil { - if cur.Val < val { + if cur.Val.(int) < val { // 目标节点在 cur 的右子树中 cur = cur.Right - } else if cur.Val > val { + } else if cur.Val.(int) > val { // 目标节点在 cur 的左子树中 cur = cur.Left } else { diff --git a/codes/go/chapter_tree/binary_search_tree.go b/codes/go/chapter_tree/binary_search_tree.go index 442a14732..1a0829883 100644 --- a/codes/go/chapter_tree/binary_search_tree.go +++ b/codes/go/chapter_tree/binary_search_tree.go @@ -47,10 +47,10 @@ func (bst *binarySearchTree) search(num int) *TreeNode { node := bst.root // 循环查找,越过叶节点后跳出 for node != nil { - if node.Val < num { + if node.Val.(int) < num { // 目标节点在 cur 的右子树中 node = node.Right - } else if node.Val > num { + } else if node.Val.(int) > num { // 目标节点在 cur 的左子树中 node = node.Left } else { @@ -77,7 +77,7 @@ func (bst *binarySearchTree) insert(num int) { return } pre = cur - if cur.Val < num { + if cur.Val.(int) < num { cur = cur.Right } else { cur = cur.Left @@ -85,7 +85,7 @@ func (bst *binarySearchTree) insert(num int) { } // 插入节点 node := NewTreeNode(num) - if pre.Val < num { + if pre.Val.(int) < num { pre.Right = node } else { pre.Left = node @@ -107,7 +107,7 @@ func (bst *binarySearchTree) remove(num int) { break } pre = cur - if cur.Val < num { + if cur.Val.(int) < num { // 待删除节点在右子树中 cur = cur.Right } else { @@ -147,7 +147,7 @@ func (bst *binarySearchTree) remove(num int) { tmp = tmp.Left } // 递归删除节点 tmp - bst.remove(tmp.Val) + bst.remove(tmp.Val.(int)) // 用 tmp 覆盖 cur cur.Val = tmp.Val } diff --git a/codes/go/chapter_tree/binary_tree_bfs.go b/codes/go/chapter_tree/binary_tree_bfs.go index 938fb063b..cf554d33e 100644 --- a/codes/go/chapter_tree/binary_tree_bfs.go +++ b/codes/go/chapter_tree/binary_tree_bfs.go @@ -11,12 +11,12 @@ import ( ) /* 层序遍历 */ -func levelOrder(root *TreeNode) []int { +func levelOrder(root *TreeNode) []any { // 初始化队列,加入根节点 queue := list.New() queue.PushBack(root) // 初始化一个切片,用于保存遍历序列 - nums := make([]int, 0) + nums := make([]any, 0) for queue.Len() > 0 { // 队列出队 node := queue.Remove(queue.Front()).(*TreeNode) diff --git a/codes/go/chapter_tree/binary_tree_bfs_test.go b/codes/go/chapter_tree/binary_tree_bfs_test.go index b29c44f3d..8c3d17cc7 100644 --- a/codes/go/chapter_tree/binary_tree_bfs_test.go +++ b/codes/go/chapter_tree/binary_tree_bfs_test.go @@ -14,7 +14,7 @@ import ( func TestLevelOrder(t *testing.T) { /* 初始化二叉树 */ // 这里借助了一个从数组直接生成二叉树的函数 - root := ArrToTree([]any{1, 2, 3, 4, 5, 6, 7}) + root := SliceToTree([]any{1, 2, 3, 4, 5, 6, 7}) fmt.Println("\n初始化二叉树: ") PrintTree(root) diff --git a/codes/go/chapter_tree/binary_tree_dfs.go b/codes/go/chapter_tree/binary_tree_dfs.go index 75486cf72..25211ce96 100644 --- a/codes/go/chapter_tree/binary_tree_dfs.go +++ b/codes/go/chapter_tree/binary_tree_dfs.go @@ -8,7 +8,7 @@ import ( . "github.com/krahets/hello-algo/pkg" ) -var nums []int +var nums []any /* 前序遍历 */ func preOrder(node *TreeNode) { diff --git a/codes/go/chapter_tree/binary_tree_dfs_test.go b/codes/go/chapter_tree/binary_tree_dfs_test.go index dfe822f27..e8404c940 100644 --- a/codes/go/chapter_tree/binary_tree_dfs_test.go +++ b/codes/go/chapter_tree/binary_tree_dfs_test.go @@ -14,7 +14,7 @@ import ( func TestPreInPostOrderTraversal(t *testing.T) { /* 初始化二叉树 */ // 这里借助了一个从数组直接生成二叉树的函数 - root := ArrToTree([]any{1, 2, 3, 4, 5, 6, 7}) + root := SliceToTree([]any{1, 2, 3, 4, 5, 6, 7}) fmt.Println("\n初始化二叉树: ") PrintTree(root) diff --git a/codes/go/pkg/print_utils.go b/codes/go/pkg/print_utils.go index 0e85a189f..688d1ef02 100644 --- a/codes/go/pkg/print_utils.go +++ b/codes/go/pkg/print_utils.go @@ -45,7 +45,7 @@ func PrintHeap(h []any) { fmt.Printf("堆的数组表示:") fmt.Printf("%v", h) fmt.Printf("\n堆的树状表示:\n") - root := ArrToTree(h) + root := SliceToTree(h) PrintTree(root) } diff --git a/codes/go/pkg/tree_node.go b/codes/go/pkg/tree_node.go index 322991687..c5c7434c1 100644 --- a/codes/go/pkg/tree_node.go +++ b/codes/go/pkg/tree_node.go @@ -4,18 +4,14 @@ package pkg -import ( - "container/list" -) - type TreeNode struct { - Val int // 节点值 + Val any // 节点值 Height int // 节点高度 Left *TreeNode // 左子节点引用 Right *TreeNode // 右子节点引用 } -func NewTreeNode(v int) *TreeNode { +func NewTreeNode(v any) *TreeNode { return &TreeNode{ Val: v, Height: 0, @@ -24,56 +20,57 @@ func NewTreeNode(v int) *TreeNode { } } -// ArrToTree Generate a binary tree given an array -func ArrToTree(arr []any) *TreeNode { - if len(arr) <= 0 { +// 序列化编码规则请参考: +// https://www.hello-algo.com/chapter_tree/array_representation_of_tree/ +// 二叉树的数组表示: +// [1, 2, 3, 4, nil, 6, 7, 8, 9, nil, nil, 12, nil, nil, 15] +// 二叉树的链表表示: +// +// /——— 15 +// /——— 7 +// /——— 3 +// | \——— 6 +// | \——— 12 +// +// ——— 1 +// +// \——— 2 +// | /——— 9 +// \——— 4 +// \——— 8 + +// SliceToTreeDFS 将列表反序列化为二叉树:递归 +func SliceToTreeDFS(arr []any, i int) *TreeNode { + if i < 0 || i >= len(arr) || arr[i] == nil { return nil } - // TreeNode only accept integer value for now. - root := NewTreeNode(arr[0].(int)) - // Let container.list as queue - queue := list.New() - queue.PushBack(root) - i := 0 - for queue.Len() > 0 { - // 队首元素出队 - node := queue.Remove(queue.Front()).(*TreeNode) - i++ - if i < len(arr) { - if arr[i] != nil { - node.Left = NewTreeNode(arr[i].(int)) - queue.PushBack(node.Left) - } - } - i++ - if i < len(arr) { - if arr[i] != nil { - node.Right = NewTreeNode(arr[i].(int)) - queue.PushBack(node.Right) - } - } - } + root := NewTreeNode(arr[i]) + root.Left = SliceToTreeDFS(arr, 2*i+1) + root.Right = SliceToTreeDFS(arr, 2*i+2) return root } -// TreeToArray Serialize a binary tree to a list -func TreeToArray(root *TreeNode) []any { +// SliceToTree 将切片反序列化为二叉树 +func SliceToTree(arr []any) *TreeNode { + return SliceToTreeDFS(arr, 0) +} + +// TreeToSliceDFS 将二叉树序列化为切片:递归 +func TreeToSliceDFS(root *TreeNode, i int, res *[]any) { if root == nil { - return []any{} + return } - arr := make([]any, 0) - queue := list.New() - queue.PushBack(root) - for queue.Len() > 0 { - node := queue.Remove(queue.Front()).(*TreeNode) - if node != nil { - arr = append(arr, node.Val) - queue.PushBack(node.Left) - queue.PushBack(node.Right) - } else { - // node don't exist. - arr = append(arr, nil) - } + for i >= len(*res) { + *res = append(*res, nil) } - return arr + (*res)[i] = root.Val + TreeToSliceDFS(root.Left, 2*i+1, res) + TreeToSliceDFS(root.Right, 2*i+2, res) +} + +// TreeToSlice 将二叉树序列化为切片 +func TreeToSlice(root *TreeNode) []any { + var res []any + TreeToSliceDFS(root, 0, &res) + return res } diff --git a/codes/go/pkg/tree_node_test.go b/codes/go/pkg/tree_node_test.go index ec7831bf7..043aab099 100644 --- a/codes/go/pkg/tree_node_test.go +++ b/codes/go/pkg/tree_node_test.go @@ -11,11 +11,11 @@ import ( func TestTreeNode(t *testing.T) { arr := []any{1, 2, 3, nil, 5, 6, nil} - node := ArrToTree(arr) + node := SliceToTree(arr) // print tree PrintTree(node) // tree to arr - fmt.Println(TreeToArray(node)) + fmt.Println(TreeToSlice(node)) }