From e8c78f89f049155c7e3ce3dcf32aa3b093f1af89 Mon Sep 17 00:00:00 2001 From: krahets Date: Thu, 9 Feb 2023 04:45:06 +0800 Subject: [PATCH] Add build script for Go and update Go codes. --- .../worst_best_time_complexity.go | 12 -- .../worst_best_time_complexity_test.go | 2 +- codes/go/chapter_hashing/array_hash_map.go | 1 + codes/go/chapter_searching/linear_search.go | 2 +- codes/go/chapter_sorting/insertion_sort.go | 1 + codes/go/chapter_sorting/merge_sort.go | 3 +- .../go/chapter_stack_and_queue/array_queue.go | 14 +- .../go/chapter_stack_and_queue/array_stack.go | 17 +- .../linkedlist_deque.go | 23 +-- .../linkedlist_queue.go | 14 +- .../linkedlist_stack.go | 14 +- codes/go/chapter_tree/avl_tree.go | 88 ++++----- codes/go/chapter_tree/avl_tree_test.go | 4 +- codes/go/chapter_tree/binary_search_tree.go | 38 ++-- codes/go/chapter_tree/binary_tree_bfs.go | 2 +- codes/go/chapter_tree/binary_tree_bfs_test.go | 4 +- docs/chapter_array_and_linkedlist/array.md | 64 +----- .../linked_list.md | 117 ++--------- docs/chapter_array_and_linkedlist/list.md | 98 +--------- .../space_complexity.md | 74 +------ .../space_time_tradeoff.md | 26 +-- .../time_complexity.md | 126 ++---------- docs/chapter_hashing/hash_map.md | 49 +---- docs/chapter_heap/heap.md | 109 +---------- docs/chapter_searching/binary_search.md | 38 +--- docs/chapter_searching/hashing_search.md | 22 +-- docs/chapter_searching/linear_search.md | 27 +-- docs/chapter_sorting/bubble_sort.md | 33 +--- docs/chapter_sorting/insertion_sort.md | 15 +- docs/chapter_sorting/quick_sort.md | 69 +------ docs/chapter_stack_and_queue/queue.md | 116 +---------- docs/chapter_stack_and_queue/stack.md | 95 +-------- docs/chapter_tree/avl_tree.md | 175 ++--------------- docs/chapter_tree/binary_search_tree.md | 118 +---------- docs/chapter_tree/binary_tree_traversal.md | 61 +----- docs/utils/build_markdown.py | 2 + docs/utils/deploy.sh | 2 +- docs/utils/extract_code_go.py | 183 ++++++++++++++++++ docs/utils/extract_code_java.py | 1 - 39 files changed, 391 insertions(+), 1468 deletions(-) create mode 100644 docs/utils/extract_code_go.py diff --git a/codes/go/chapter_computational_complexity/worst_best_time_complexity.go b/codes/go/chapter_computational_complexity/worst_best_time_complexity.go index 64ad4dc9..75b74c8e 100644 --- a/codes/go/chapter_computational_complexity/worst_best_time_complexity.go +++ b/codes/go/chapter_computational_complexity/worst_best_time_complexity.go @@ -5,7 +5,6 @@ package chapter_computational_complexity import ( - "fmt" "math/rand" ) @@ -34,14 +33,3 @@ func findOne(nums []int) int { } return -1 } - -/* Driver Code */ -func main() { - for i := 0; i < 10; i++ { - n := 100 - nums := randomNumbers(n) - index := findOne(nums) - fmt.Println("\n数组 [ 1, 2, ..., n ] 被打乱后 =", nums) - fmt.Println("数字 1 的索引为", index) - } -} diff --git a/codes/go/chapter_computational_complexity/worst_best_time_complexity_test.go b/codes/go/chapter_computational_complexity/worst_best_time_complexity_test.go index a7aa988f..ccbcb039 100644 --- a/codes/go/chapter_computational_complexity/worst_best_time_complexity_test.go +++ b/codes/go/chapter_computational_complexity/worst_best_time_complexity_test.go @@ -14,7 +14,7 @@ func TestWorstBestTimeComplexity(t *testing.T) { n := 100 nums := randomNumbers(n) index := findOne(nums) - fmt.Println("打乱后的数组为", nums) + fmt.Println("\n数组 [ 1, 2, ..., n ] 被打乱后 =", nums) fmt.Println("数字 1 的索引为", index) } } diff --git a/codes/go/chapter_hashing/array_hash_map.go b/codes/go/chapter_hashing/array_hash_map.go index 5fb1480c..67838528 100644 --- a/codes/go/chapter_hashing/array_hash_map.go +++ b/codes/go/chapter_hashing/array_hash_map.go @@ -17,6 +17,7 @@ type arrayHashMap struct { bucket []*entry } +/* 初始化哈希表 */ func newArrayHashMap() *arrayHashMap { // 初始化一个长度为 100 的桶(数组) bucket := make([]*entry, 100) diff --git a/codes/go/chapter_searching/linear_search.go b/codes/go/chapter_searching/linear_search.go index f9cc1a7c..95f29cf8 100644 --- a/codes/go/chapter_searching/linear_search.go +++ b/codes/go/chapter_searching/linear_search.go @@ -25,7 +25,7 @@ func linearSearchArray(nums []int, target int) int { func linearSearchLinkedList(node *ListNode, target int) *ListNode { // 遍历链表 for node != nil { - // 找到目标元素,返回其索引 + // 找到目标结点,返回之 if node.Val == target { return node } diff --git a/codes/go/chapter_sorting/insertion_sort.go b/codes/go/chapter_sorting/insertion_sort.go index 24101e96..49c28005 100644 --- a/codes/go/chapter_sorting/insertion_sort.go +++ b/codes/go/chapter_sorting/insertion_sort.go @@ -4,6 +4,7 @@ package chapter_sorting +/* 插入排序 */ func insertionSort(nums []int) { // 外循环:待排序元素数量为 n-1, n-2, ..., 1 for i := 1; i < len(nums); i++ { diff --git a/codes/go/chapter_sorting/merge_sort.go b/codes/go/chapter_sorting/merge_sort.go index 43aff01a..750b9b3e 100644 --- a/codes/go/chapter_sorting/merge_sort.go +++ b/codes/go/chapter_sorting/merge_sort.go @@ -4,7 +4,7 @@ package chapter_sorting -// 合并左子数组和右子数组 +/* 合并左子数组和右子数组 */ // 左子数组区间 [left, mid] // 右子数组区间 [mid + 1, right] func merge(nums []int, left, mid, right int) { @@ -37,6 +37,7 @@ func merge(nums []int, left, mid, right int) { } } +/* 归并排序 */ func mergeSort(nums []int, left, right int) { // 终止条件 if left >= right { diff --git a/codes/go/chapter_stack_and_queue/array_queue.go b/codes/go/chapter_stack_and_queue/array_queue.go index 5213cb47..226fd53a 100644 --- a/codes/go/chapter_stack_and_queue/array_queue.go +++ b/codes/go/chapter_stack_and_queue/array_queue.go @@ -12,7 +12,7 @@ type arrayQueue struct { queCapacity int // 队列容量(即最大容纳元素数量) } -// newArrayQueue 基于环形数组实现的队列 +/* 初始化队列 */ func newArrayQueue(queCapacity int) *arrayQueue { return &arrayQueue{ nums: make([]int, queCapacity), @@ -22,17 +22,17 @@ func newArrayQueue(queCapacity int) *arrayQueue { } } -// size 获取队列的长度 +/* 获取队列的长度 */ func (q *arrayQueue) size() int { return q.queSize } -// isEmpty 判断队列是否为空 +/* 判断队列是否为空 */ func (q *arrayQueue) isEmpty() bool { return q.queSize == 0 } -// push 入队 +/* 入队 */ func (q *arrayQueue) push(num int) { // 当 rear == queCapacity 表示队列已满 if q.queSize == q.queCapacity { @@ -46,7 +46,7 @@ func (q *arrayQueue) push(num int) { q.queSize++ } -// poll 出队 +/* 出队 */ func (q *arrayQueue) poll() any { num := q.peek() // 队首指针向后移动一位,若越过尾部则返回到数组头部 @@ -55,7 +55,7 @@ func (q *arrayQueue) poll() any { return num } -// peek 访问队首元素 +/* 访问队首元素 */ func (q *arrayQueue) peek() any { if q.isEmpty() { return nil @@ -63,7 +63,7 @@ func (q *arrayQueue) peek() any { return q.nums[q.front] } -// 获取 Slice 用于打印 +/* 获取 Slice 用于打印 */ func (q *arrayQueue) toSlice() []int { rear := (q.front + q.queSize) if rear >= q.queCapacity { diff --git a/codes/go/chapter_stack_and_queue/array_stack.go b/codes/go/chapter_stack_and_queue/array_stack.go index ef32ebe4..ab644e76 100644 --- a/codes/go/chapter_stack_and_queue/array_stack.go +++ b/codes/go/chapter_stack_and_queue/array_stack.go @@ -9,6 +9,7 @@ type arrayStack struct { data []int // 数据 } +/* 初始化栈 */ func newArrayStack() *arrayStack { return &arrayStack{ // 设置栈的长度为 0,容量为 16 @@ -16,34 +17,30 @@ func newArrayStack() *arrayStack { } } -// size 栈的长度 +/* 栈的长度 */ func (s *arrayStack) size() int { return len(s.data) } -// isEmpty 栈是否为空 +/* 栈是否为空 */ func (s *arrayStack) isEmpty() bool { return s.size() == 0 } -// push 入栈 +/* 入栈 */ func (s *arrayStack) push(v int) { // 切片会自动扩容 s.data = append(s.data, v) } -// pop 出栈 +/* 出栈 */ func (s *arrayStack) pop() any { - // 弹出栈前,先判断是否为空 - if s.isEmpty() { - return nil - } val := s.peek() s.data = s.data[:len(s.data)-1] return val } -// peek 获取栈顶元素 +/* 获取栈顶元素 */ func (s *arrayStack) peek() any { if s.isEmpty() { return nil @@ -52,7 +49,7 @@ func (s *arrayStack) peek() any { return val } -// 获取 Slice 用于打印 +/* 获取 Slice 用于打印 */ func (s *arrayStack) toSlice() []int { return s.data } diff --git a/codes/go/chapter_stack_and_queue/linkedlist_deque.go b/codes/go/chapter_stack_and_queue/linkedlist_deque.go index 763ebd94..533c85b0 100644 --- a/codes/go/chapter_stack_and_queue/linkedlist_deque.go +++ b/codes/go/chapter_stack_and_queue/linkedlist_deque.go @@ -8,29 +8,30 @@ import ( "container/list" ) -// linkedListDeque 基于链表实现的双端队列, 使用内置包 list 来实现栈 +/* 基于链表实现的双端队列 */ type linkedListDeque struct { + // 使用内置包 list 来实现栈 data *list.List } -// newLinkedListDeque 初始化双端队列 +/* 初始化双端队列 */ func newLinkedListDeque() *linkedListDeque { return &linkedListDeque{ data: list.New(), } } -// pushFirst 队首元素入队 +/* 队首元素入队 */ func (s *linkedListDeque) pushFirst(value any) { s.data.PushFront(value) } -// pushLast 队尾元素入队 +/* 队尾元素入队 */ func (s *linkedListDeque) pushLast(value any) { s.data.PushBack(value) } -// pollFirst 队首元素出队 +/* 队首元素出队 */ func (s *linkedListDeque) pollFirst() any { if s.isEmpty() { return nil @@ -40,7 +41,7 @@ func (s *linkedListDeque) pollFirst() any { return e.Value } -// pollLast 队尾元素出队 +/* 队尾元素出队 */ func (s *linkedListDeque) pollLast() any { if s.isEmpty() { return nil @@ -50,7 +51,7 @@ func (s *linkedListDeque) pollLast() any { return e.Value } -// peekFirst 访问队首元素 +/* 访问队首元素 */ func (s *linkedListDeque) peekFirst() any { if s.isEmpty() { return nil @@ -59,7 +60,7 @@ func (s *linkedListDeque) peekFirst() any { return e.Value } -// peekLast 访问队尾元素 +/* 访问队尾元素 */ func (s *linkedListDeque) peekLast() any { if s.isEmpty() { return nil @@ -68,17 +69,17 @@ func (s *linkedListDeque) peekLast() any { return e.Value } -// size 获取队列的长度 +/* 获取队列的长度 */ func (s *linkedListDeque) size() int { return s.data.Len() } -// isEmpty 判断队列是否为空 +/* 判断队列是否为空 */ func (s *linkedListDeque) isEmpty() bool { return s.data.Len() == 0 } -// 获取 List 用于打印 +/* 获取 List 用于打印 */ func (s *linkedListDeque) toList() *list.List { return s.data } diff --git a/codes/go/chapter_stack_and_queue/linkedlist_queue.go b/codes/go/chapter_stack_and_queue/linkedlist_queue.go index 303674cd..ecb732ae 100644 --- a/codes/go/chapter_stack_and_queue/linkedlist_queue.go +++ b/codes/go/chapter_stack_and_queue/linkedlist_queue.go @@ -14,19 +14,19 @@ type linkedListQueue struct { data *list.List } -// newLinkedListQueue 初始化链表 +/* 初始化队列 */ func newLinkedListQueue() *linkedListQueue { return &linkedListQueue{ data: list.New(), } } -// push 入队 +/* 入队 */ func (s *linkedListQueue) push(value any) { s.data.PushBack(value) } -// poll 出队 +/* 出队 */ func (s *linkedListQueue) poll() any { if s.isEmpty() { return nil @@ -36,7 +36,7 @@ func (s *linkedListQueue) poll() any { return e.Value } -// peek 访问队首元素 +/* 访问队首元素 */ func (s *linkedListQueue) peek() any { if s.isEmpty() { return nil @@ -45,17 +45,17 @@ func (s *linkedListQueue) peek() any { return e.Value } -// size 获取队列的长度 +/* 获取队列的长度 */ func (s *linkedListQueue) size() int { return s.data.Len() } -// isEmpty 判断队列是否为空 +/* 判断队列是否为空 */ func (s *linkedListQueue) isEmpty() bool { return s.data.Len() == 0 } -// 获取 List 用于打印 +/* 获取 List 用于打印 */ func (s *linkedListQueue) toList() *list.List { return s.data } diff --git a/codes/go/chapter_stack_and_queue/linkedlist_stack.go b/codes/go/chapter_stack_and_queue/linkedlist_stack.go index 8509c2b8..53fd7112 100644 --- a/codes/go/chapter_stack_and_queue/linkedlist_stack.go +++ b/codes/go/chapter_stack_and_queue/linkedlist_stack.go @@ -14,19 +14,19 @@ type linkedListStack struct { data *list.List } -// newLinkedListStack 初始化链表 +/* 初始化栈 */ func newLinkedListStack() *linkedListStack { return &linkedListStack{ data: list.New(), } } -// push 入栈 +/* 入栈 */ func (s *linkedListStack) push(value int) { s.data.PushBack(value) } -// pop 出栈 +/* 出栈 */ func (s *linkedListStack) pop() any { if s.isEmpty() { return nil @@ -36,7 +36,7 @@ func (s *linkedListStack) pop() any { return e.Value } -// peek 访问栈顶元素 +/* 访问栈顶元素 */ func (s *linkedListStack) peek() any { if s.isEmpty() { return nil @@ -45,17 +45,17 @@ func (s *linkedListStack) peek() any { return e.Value } -// size 获取栈的长度 +/* 获取栈的长度 */ func (s *linkedListStack) size() int { return s.data.Len() } -// isEmpty 判断栈是否为空 +/* 判断栈是否为空 */ func (s *linkedListStack) isEmpty() bool { return s.data.Len() == 0 } -// 获取 List 用于打印 +/* 获取 List 用于打印 */ func (s *linkedListStack) toList() *list.List { return s.data } diff --git a/codes/go/chapter_tree/avl_tree.go b/codes/go/chapter_tree/avl_tree.go index 9f1e5134..46356c4e 100644 --- a/codes/go/chapter_tree/avl_tree.go +++ b/codes/go/chapter_tree/avl_tree.go @@ -7,17 +7,17 @@ package chapter_tree import . "github.com/krahets/hello-algo/pkg" /* AVL 树 */ -type avlTree struct { +type aVLTree struct { // 根结点 root *TreeNode } -func newAVLTree() *avlTree { - return &avlTree{root: nil} +func newAVLTree() *aVLTree { + return &aVLTree{root: nil} } /* 获取结点高度 */ -func height(node *TreeNode) int { +func (t *aVLTree) height(node *TreeNode) int { // 空结点高度为 -1 ,叶结点高度为 0 if node != nil { return node.Height @@ -26,9 +26,9 @@ func height(node *TreeNode) int { } /* 更新结点高度 */ -func updateHeight(node *TreeNode) { - lh := height(node.Left) - rh := height(node.Right) +func (t *aVLTree) updateHeight(node *TreeNode) { + lh := t.height(node.Left) + rh := t.height(node.Right) // 结点高度等于最高子树高度 + 1 if lh > rh { node.Height = lh + 1 @@ -38,68 +38,68 @@ func updateHeight(node *TreeNode) { } /* 获取平衡因子 */ -func balanceFactor(node *TreeNode) int { +func (t *aVLTree) balanceFactor(node *TreeNode) int { // 空结点平衡因子为 0 if node == nil { return 0 } // 结点平衡因子 = 左子树高度 - 右子树高度 - return height(node.Left) - height(node.Right) + return t.height(node.Left) - t.height(node.Right) } /* 右旋操作 */ -func rightRotate(node *TreeNode) *TreeNode { +func (t *aVLTree) rightRotate(node *TreeNode) *TreeNode { child := node.Left grandChild := child.Right // 以 child 为原点,将 node 向右旋转 child.Right = node node.Left = grandChild // 更新结点高度 - updateHeight(node) - updateHeight(child) + t.updateHeight(node) + t.updateHeight(child) // 返回旋转后子树的根结点 return child } /* 左旋操作 */ -func leftRotate(node *TreeNode) *TreeNode { +func (t *aVLTree) leftRotate(node *TreeNode) *TreeNode { child := node.Right grandChild := child.Left // 以 child 为原点,将 node 向左旋转 child.Left = node node.Right = grandChild // 更新结点高度 - updateHeight(node) - updateHeight(child) + t.updateHeight(node) + t.updateHeight(child) // 返回旋转后子树的根结点 return child } /* 执行旋转操作,使该子树重新恢复平衡 */ -func rotate(node *TreeNode) *TreeNode { +func (t *aVLTree) rotate(node *TreeNode) *TreeNode { // 获取结点 node 的平衡因子 - // Go 推荐短变量,这里 bf 指代 balanceFactor - bf := balanceFactor(node) + // Go 推荐短变量,这里 bf 指代 t.balanceFactor + bf := t.balanceFactor(node) // 左偏树 if bf > 1 { - if balanceFactor(node.Left) >= 0 { + if t.balanceFactor(node.Left) >= 0 { // 右旋 - return rightRotate(node) + return t.rightRotate(node) } else { // 先左旋后右旋 - node.Left = leftRotate(node.Left) - return rightRotate(node) + node.Left = t.leftRotate(node.Left) + return t.rightRotate(node) } } // 右偏树 if bf < -1 { - if balanceFactor(node.Right) <= 0 { + if t.balanceFactor(node.Right) <= 0 { // 左旋 - return leftRotate(node) + return t.leftRotate(node) } else { // 先右旋后左旋 - node.Right = rightRotate(node.Right) - return leftRotate(node) + node.Right = t.rightRotate(node.Right) + return t.leftRotate(node) } } // 平衡树,无需旋转,直接返回 @@ -107,49 +107,49 @@ func rotate(node *TreeNode) *TreeNode { } /* 插入结点 */ -func (t *avlTree) insert(val int) *TreeNode { - t.root = insertHelper(t.root, val) +func (t *aVLTree) insert(val int) *TreeNode { + t.root = t.insertHelper(t.root, val) return t.root } /* 递归插入结点(辅助函数) */ -func insertHelper(node *TreeNode, val int) *TreeNode { +func (t *aVLTree) insertHelper(node *TreeNode, val int) *TreeNode { if node == nil { return NewTreeNode(val) } /* 1. 查找插入位置,并插入结点 */ if val < node.Val { - node.Left = insertHelper(node.Left, val) + node.Left = t.insertHelper(node.Left, val) } else if val > node.Val { - node.Right = insertHelper(node.Right, val) + node.Right = t.insertHelper(node.Right, val) } else { // 重复结点不插入,直接返回 return node } // 更新结点高度 - updateHeight(node) + t.updateHeight(node) /* 2. 执行旋转操作,使该子树重新恢复平衡 */ - node = rotate(node) + node = t.rotate(node) // 返回子树的根结点 return node } /* 删除结点 */ -func (t *avlTree) remove(val int) *TreeNode { - root := removeHelper(t.root, val) +func (t *aVLTree) remove(val int) *TreeNode { + root := t.removeHelper(t.root, val) return root } /* 递归删除结点(辅助函数) */ -func removeHelper(node *TreeNode, val int) *TreeNode { +func (t *aVLTree) removeHelper(node *TreeNode, val int) *TreeNode { if node == nil { return nil } /* 1. 查找结点,并删除之 */ if val < node.Val { - node.Left = removeHelper(node.Left, val) + node.Left = t.removeHelper(node.Left, val) } else if val > node.Val { - node.Right = removeHelper(node.Right, val) + node.Right = t.removeHelper(node.Right, val) } else { if node.Left == nil || node.Right == nil { child := node.Left @@ -165,21 +165,21 @@ func removeHelper(node *TreeNode, val int) *TreeNode { } } else { // 子结点数量 = 2 ,则将中序遍历的下个结点删除,并用该结点替换当前结点 - temp := getInOrderNext(node.Right) - node.Right = removeHelper(node.Right, temp.Val) + temp := t.getInOrderNext(node.Right) + node.Right = t.removeHelper(node.Right, temp.Val) node.Val = temp.Val } } // 更新结点高度 - updateHeight(node) + t.updateHeight(node) /* 2. 执行旋转操作,使该子树重新恢复平衡 */ - node = rotate(node) + node = t.rotate(node) // 返回子树的根结点 return node } /* 获取中序遍历中的下一个结点(仅适用于 root 有左子结点的情况) */ -func getInOrderNext(node *TreeNode) *TreeNode { +func (t *aVLTree) getInOrderNext(node *TreeNode) *TreeNode { if node == nil { return node } @@ -191,7 +191,7 @@ func getInOrderNext(node *TreeNode) *TreeNode { } /* 查找结点 */ -func (t *avlTree) search(val int) *TreeNode { +func (t *aVLTree) search(val int) *TreeNode { cur := t.root // 循环查找,越过叶结点后跳出 for cur != nil { diff --git a/codes/go/chapter_tree/avl_tree_test.go b/codes/go/chapter_tree/avl_tree_test.go index c02b8013..8c419bbc 100644 --- a/codes/go/chapter_tree/avl_tree_test.go +++ b/codes/go/chapter_tree/avl_tree_test.go @@ -41,13 +41,13 @@ func TestAVLTree(t *testing.T) { fmt.Printf("\n查找到的结点对象为 %#v ,结点值 = %d \n", node, node.Val) } -func testInsert(tree *avlTree, val int) { +func testInsert(tree *aVLTree, val int) { tree.insert(val) fmt.Printf("\n插入结点 %d 后,AVL 树为 \n", val) PrintTree(tree.root) } -func testRemove(tree *avlTree, val int) { +func testRemove(tree *aVLTree, val int) { tree.remove(val) fmt.Printf("\n删除结点 %d 后,AVL 树为 \n", val) PrintTree(tree.root) diff --git a/codes/go/chapter_tree/binary_search_tree.go b/codes/go/chapter_tree/binary_search_tree.go index 923c5520..b671db1e 100644 --- a/codes/go/chapter_tree/binary_search_tree.go +++ b/codes/go/chapter_tree/binary_search_tree.go @@ -15,12 +15,26 @@ type binarySearchTree struct { } func newBinarySearchTree(nums []int) *binarySearchTree { - // sorting array + // 排序数组 sort.Ints(nums) - root := buildBinarySearchTree(nums, 0, len(nums)-1) - return &binarySearchTree{ - root: root, + // 构建二叉搜索树 + bst := &binarySearchTree{} + bst.root = bst.buildTree(nums, 0, len(nums)-1) + return bst +} + +/* 构建二叉搜索树 */ +func (bst *binarySearchTree) buildTree(nums []int, left, right int) *TreeNode { + if left > right { + return nil } + // 将数组中间结点作为根结点 + middle := left + (right-left)>>1 + root := NewTreeNode(nums[middle]) + // 递归构建左子树和右子树 + root.Left = bst.buildTree(nums, left, middle-1) + root.Right = bst.buildTree(nums, middle+1, right) + return root } /* 获取根结点 */ @@ -146,21 +160,7 @@ func (bst *binarySearchTree) remove(num int) *TreeNode { 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_tree_bfs.go b/codes/go/chapter_tree/binary_tree_bfs.go index 8ec46fbe..c10f618e 100644 --- a/codes/go/chapter_tree/binary_tree_bfs.go +++ b/codes/go/chapter_tree/binary_tree_bfs.go @@ -11,7 +11,7 @@ import ( ) /* 层序遍历 */ -func levelOrder(root *TreeNode) []int { +func hierOrder(root *TreeNode) []int { // 初始化队列,加入根结点 queue := list.New() queue.PushBack(root) diff --git a/codes/go/chapter_tree/binary_tree_bfs_test.go b/codes/go/chapter_tree/binary_tree_bfs_test.go index 7b1bbf1f..eafd51bc 100644 --- a/codes/go/chapter_tree/binary_tree_bfs_test.go +++ b/codes/go/chapter_tree/binary_tree_bfs_test.go @@ -11,7 +11,7 @@ import ( . "github.com/krahets/hello-algo/pkg" ) -func TestLevelOrder(t *testing.T) { +func TestHierOrder(t *testing.T) { /* 初始化二叉树 */ // 这里借助了一个从数组直接生成二叉树的函数 root := ArrToTree([]any{1, 2, 3, 4, 5, 6, 7}) @@ -19,6 +19,6 @@ func TestLevelOrder(t *testing.T) { PrintTree(root) // 层序遍历 - nums := levelOrder(root) + nums := hierOrder(root) fmt.Println("\n层序遍历的结点打印序列 =", nums) } diff --git a/docs/chapter_array_and_linkedlist/array.md b/docs/chapter_array_and_linkedlist/array.md index d9a702d8..6412c964 100755 --- a/docs/chapter_array_and_linkedlist/array.md +++ b/docs/chapter_array_and_linkedlist/array.md @@ -135,14 +135,7 @@ elementAddr = firtstElementAddr + elementLength * elementIndex === "Go" ```go title="array.go" - /* 随机返回一个数组元素 */ - func randomAccess(nums []int) (randomNum int) { - // 在区间 [0, nums.length) 中随机抽取一个数字 - randomIndex := rand.Intn(len(nums)) - // 获取并返回随机元素 - randomNum = nums[randomIndex] - return - } + [class]{}-[func]{randomAccess} ``` === "JavaScript" @@ -213,17 +206,7 @@ elementAddr = firtstElementAddr + elementLength * elementIndex === "Go" ```go title="array.go" - /* 扩展数组长度 */ - func extend(nums []int, enlarge int) []int { - // 初始化一个扩展长度后的数组 - res := make([]int, len(nums)+enlarge) - // 将原数组中的所有元素复制到新数组 - for i, num := range nums { - res[i] = num - } - // 返回扩展后的新数组 - return res - } + [class]{}-[func]{extend} ``` === "JavaScript" @@ -308,23 +291,9 @@ elementAddr = firtstElementAddr + elementLength * elementIndex === "Go" ```go title="array.go" - /* 在数组的索引 index 处插入元素 num */ - func insert(nums []int, num int, index int) { - // 把索引 index 以及之后的所有元素向后移动一位 - for i := len(nums) - 1; i > index; i-- { - nums[i] = nums[i-1] - } - // 将 num 赋给 index 处元素 - nums[index] = num - } + [class]{}-[func]{insert} - /* 删除索引 index 处元素 */ - func remove(nums []int, index int) { - // 把索引 index 之后的所有元素向前移动一位 - for i := index; i < len(nums)-1; i++ { - nums[i] = nums[i+1] - } - } + [class]{}-[func]{remove} ``` === "JavaScript" @@ -414,18 +383,7 @@ elementAddr = firtstElementAddr + elementLength * elementIndex === "Go" ```go title="array.go" - /* 遍历数组 */ - func traverse(nums []int) { - count := 0 - // 通过索引遍历数组 - for i := 0; i < len(nums); i++ { - count++ - } - // 直接遍历数组 - for range nums { - count++ - } - } + [class]{}-[func]{traverse} ``` === "JavaScript" @@ -500,17 +458,7 @@ elementAddr = firtstElementAddr + elementLength * elementIndex === "Go" ```go title="array.go" - /* 在数组中查找指定元素 */ - func find(nums []int, target int) (index int) { - index = -1 - for i := 0; i < len(nums); i++ { - if nums[i] == target { - index = i - break - } - } - return - } + [class]{}-[func]{find} ``` === "JavaScript" diff --git a/docs/chapter_array_and_linkedlist/linked_list.md b/docs/chapter_array_and_linkedlist/linked_list.md index 50fdd609..7a760186 100755 --- a/docs/chapter_array_and_linkedlist/linked_list.md +++ b/docs/chapter_array_and_linkedlist/linked_list.md @@ -333,24 +333,9 @@ comments: true === "C++" ```cpp title="linked_list.cpp" - /* 在链表的结点 n0 之后插入结点 P */ - void insert(ListNode* n0, ListNode* P) { - ListNode* n1 = n0->next; - n0->next = P; - P->next = n1; - } + [class]{}-[func]{insert} - /* 删除链表的结点 n0 之后的首个结点 */ - void remove(ListNode* n0) { - if (n0->next == nullptr) - return; - // n0 -> P -> n1 - ListNode* P = n0->next; - ListNode* n1 = P->next; - n0->next = n1; - // 释放内存 - delete P; - } + [class]{}-[func]{remove} ``` === "Python" @@ -364,66 +349,25 @@ comments: true === "Go" ```go title="linked_list.go" - /* 在链表的结点 n0 之后插入结点 P */ - func insert(n0 *ListNode, P *ListNode) { - n1 := n0.Next - n0.Next = P - P.Next = n1 - } + [class]{}-[func]{insertNode} - /* 删除链表的结点 n0 之后的首个结点 */ - func removeNode(n0 *ListNode) { - if n0.Next == nil { - return - } - // n0 -> P -> n1 - P := n0.Next - n1 := P.Next - n0.Next = n1 - } + [class]{}-[func]{removeNode} ``` === "JavaScript" ```javascript title="linked_list.js" - /* 在链表的结点 n0 之后插入结点 P */ - function insert(n0, P) { - let n1 = n0.next; - n0.next = P; - P.next = n1; - } + [class]{}-[func]{insert} - /* 删除链表的结点 n0 之后的首个结点 */ - function remove(n0) { - if (!n0.next) - return; - // n0 -> P -> n1 - let P = n0.next; - let n1 = P.next; - n0.next = n1; - } + [class]{}-[func]{remove} ``` === "TypeScript" ```typescript title="linked_list.ts" - /* 在链表的结点 n0 之后插入结点 P */ - function insert(n0: ListNode, P: ListNode): void { - const n1 = n0.next; - n0.next = P; - P.next = n1; - } - - /* 删除链表的结点 n0 之后的首个结点 */ - function remove(n0: ListNode): void { - if (!n0.next) { - return; - } - // n0 -> P -> n1 - const P = n0.next; - const n1 = P.next; - n0.next = n1; - } + [class]{}-[func]{insert} + + [class]{}-[func]{remove} ``` === "C" @@ -443,24 +387,9 @@ comments: true === "Swift" ```swift title="linked_list.swift" - /* 在链表的结点 n0 之后插入结点 P */ - func insert(n0: ListNode, P: ListNode) { - let n1 = n0.next - n0.next = P - P.next = n1 - } + [class]{}-[func]{insert} - /* 删除链表的结点 n0 之后的首个结点 */ - func remove(n0: ListNode) { - if n0.next == nil { - return - } - // n0 -> P -> n1 - let P = n0.next - let n1 = P?.next - n0.next = n1 - P?.next = nil - } + [class]{}-[func]{remove} ``` === "Zig" @@ -508,16 +437,7 @@ comments: true === "Go" ```go title="linked_list.go" - /* 访问链表中索引为 index 的结点 */ - func access(head *ListNode, index int) *ListNode { - for i := 0; i < index; i++ { - if head == nil { - return nil - } - head = head.Next - } - return head - } + [class]{}-[func]{access} ``` === "JavaScript" @@ -592,18 +512,7 @@ comments: true === "Go" ```go title="linked_list.go" - /* 在链表中查找值为 target 的首个结点 */ - func find(head *ListNode, target int) int { - index := 0 - for head != nil { - if head.Val == target { - return index - } - head = head.Next - index++ - } - return -1 - } + [class]{}-[func]{findNode} ``` === "JavaScript" diff --git a/docs/chapter_array_and_linkedlist/list.md b/docs/chapter_array_and_linkedlist/list.md index 798c6bf9..d20d37b5 100755 --- a/docs/chapter_array_and_linkedlist/list.md +++ b/docs/chapter_array_and_linkedlist/list.md @@ -734,103 +734,7 @@ comments: true === "Go" ```go title="my_list.go" - /* 列表类简易实现 */ - type myList struct { - numsCapacity int - nums []int - numsSize int - extendRatio int - } - - /* 构造函数 */ - func newMyList() *myList { - return &myList{ - numsCapacity: 10, // 列表容量 - nums: make([]int, 10), // 数组(存储列表元素) - numsSize: 0, // 列表长度(即当前元素数量) - extendRatio: 2, // 每次列表扩容的倍数 - } - } - - /* 获取列表长度(即当前元素数量) */ - func (l *myList) size() int { - return l.numsSize - } - - /* 获取列表容量 */ - func (l *myList) capacity() int { - return l.numsCapacity - } - - /* 访问元素 */ - func (l *myList) get(index int) int { - // 索引如果越界则抛出异常,下同 - if index < 0 || index >= l.numsSize { - panic("索引越界") - } - return l.nums[index] - } - - /* 更新元素 */ - func (l *myList) set(num, index int) { - if index < 0 || index >= l.numsSize { - panic("索引越界") - } - l.nums[index] = num - } - - /* 尾部添加元素 */ - func (l *myList) add(num int) { - // 元素数量超出容量时,触发扩容机制 - if l.numsSize == l.numsCapacity { - l.extendCapacity() - } - l.nums[l.numsSize] = num - // 更新元素数量 - l.numsSize++ - } - - /* 中间插入元素 */ - func (l *myList) insert(num, index int) { - if index < 0 || index >= l.numsSize { - panic("索引越界") - } - // 元素数量超出容量时,触发扩容机制 - if l.numsSize == l.numsCapacity { - l.extendCapacity() - } - // 索引 i 以及之后的元素都向后移动一位 - for j := l.numsSize - 1; j >= index; j-- { - l.nums[j+1] = l.nums[j] - } - l.nums[index] = num - // 更新元素数量 - l.numsSize++ - } - - /* 删除元素 */ - func (l *myList) remove(index int) int { - if index < 0 || index >= l.numsSize { - panic("索引越界") - } - num := l.nums[index] - // 索引 i 之后的元素都向前移动一位 - for j := index; j < l.numsSize-1; j++ { - l.nums[j] = l.nums[j+1] - } - // 更新元素数量 - l.numsSize-- - // 返回被删除元素 - return num - } - - /* 列表扩容 */ - func (l *myList) extendCapacity() { - // 新建一个长度为 self.__size 的数组,并将原数组拷贝到新数组 - l.nums = append(l.nums, make([]int, l.numsCapacity*(l.extendRatio-1))...) - // 更新列表容量 - l.numsCapacity = len(l.nums) - } + [class]{myList}-[func]{} ``` === "JavaScript" diff --git a/docs/chapter_computational_complexity/space_complexity.md b/docs/chapter_computational_complexity/space_complexity.md index e375994d..90406e95 100755 --- a/docs/chapter_computational_complexity/space_complexity.md +++ b/docs/chapter_computational_complexity/space_complexity.md @@ -600,24 +600,7 @@ $$ === "Go" ```go title="space_complexity.go" - /* 常数阶 */ - func spaceConstant(n int) { - // 常量、变量、对象占用 O(1) 空间 - const a = 0 - b := 0 - nums := make([]int, 10000) - ListNode := newNode(0) - // 循环中的变量占用 O(1) 空间 - var c int - for i := 0; i < n; i++ { - c = 0 - } - // 循环中的函数占用 O(1) 空间 - for i := 0; i < n; i++ { - function() - } - fmt.Println(a, b, nums, c, ListNode) - } + [class]{}-[func]{spaceConstant} ``` === "JavaScript" @@ -703,21 +686,7 @@ $$ === "Go" ```go title="space_complexity.go" - /* 线性阶 */ - func spaceLinear(n int) { - // 长度为 n 的数组占用 O(n) 空间 - _ = make([]int, n) - // 长度为 n 的列表占用 O(n) 空间 - var nodes []*node - for i := 0; i < n; i++ { - nodes = append(nodes, newNode(i)) - } - // 长度为 n 的哈希表占用 O(n) 空间 - m := make(map[int]string, n) - for i := 0; i < n; i++ { - m[i] = strconv.Itoa(i) - } - } + [class]{}-[func]{spaceLinear} ``` === "JavaScript" @@ -800,14 +769,7 @@ $$ === "Go" ```go title="space_complexity.go" - /* 线性阶(递归实现) */ - func spaceLinearRecur(n int) { - fmt.Println("递归 n =", n) - if n == 1 { - return - } - spaceLinearRecur(n - 1) - } + [class]{}-[func]{spaceLinearRecur} ``` === "JavaScript" @@ -880,14 +842,7 @@ $$ === "Go" ```go title="space_complexity.go" - /* 平方阶 */ - func spaceQuadratic(n int) { - // 矩阵占用 O(n^2) 空间 - numMatrix := make([][]int, n) - for i := 0; i < n; i++ { - numMatrix[i] = make([]int, n) - } - } + [class]{}-[func]{spaceQuadratic} ``` === "JavaScript" @@ -964,15 +919,7 @@ $$ === "Go" ```go title="space_complexity.go" - /* 平方阶(递归实现) */ - func spaceQuadraticRecur(n int) int { - if n <= 0 { - return 0 - } - // 数组 nums 长度为 n, n-1, ..., 2, 1 - nums := make([]int, n) - return spaceQuadraticRecur(n - 1) - } + [class]{}-[func]{spaceQuadraticRecur} ``` === "JavaScript" @@ -1046,16 +993,7 @@ $$ === "Go" ```go title="space_complexity.go" - /* 指数阶(建立满二叉树) */ - func buildTree(n int) *treeNode { - if n == 0 { - return nil - } - root := newTreeNode(0) - root.left = buildTree(n - 1) - root.right = buildTree(n - 1) - return root - } + [class]{}-[func]{buildTree} ``` === "JavaScript" diff --git a/docs/chapter_computational_complexity/space_time_tradeoff.md b/docs/chapter_computational_complexity/space_time_tradeoff.md index da84f069..3a69adda 100755 --- a/docs/chapter_computational_complexity/space_time_tradeoff.md +++ b/docs/chapter_computational_complexity/space_time_tradeoff.md @@ -51,18 +51,7 @@ comments: true === "Go" ```go title="leetcode_two_sum.go" - func twoSumBruteForce(nums []int, target int) []int { - size := len(nums) - // 两层循环,时间复杂度 O(n^2) - for i := 0; i < size-1; i++ { - for j := i + 1; i < size; j++ { - if nums[i]+nums[j] == target { - return []int{i, j} - } - } - } - return nil - } + [class]{}-[func]{twoSumBruteForce} ``` === "JavaScript" @@ -144,18 +133,7 @@ comments: true === "Go" ```go title="leetcode_two_sum.go" - func twoSumHashTable(nums []int, target int) []int { - // 辅助哈希表,空间复杂度 O(n) - hashTable := map[int]int{} - // 单层循环,时间复杂度 O(n) - for idx, val := range nums { - if preIdx, ok := hashTable[target-val]; ok { - return []int{preIdx, idx} - } - hashTable[val] = idx - } - return nil - } + [class]{}-[func]{twoSumHashTable} ``` === "JavaScript" diff --git a/docs/chapter_computational_complexity/time_complexity.md b/docs/chapter_computational_complexity/time_complexity.md index f8340a06..a1ccb62d 100755 --- a/docs/chapter_computational_complexity/time_complexity.md +++ b/docs/chapter_computational_complexity/time_complexity.md @@ -813,15 +813,7 @@ $$ === "Go" ```go title="time_complexity.go" - /* 常数阶 */ - func constant(n int) int { - count := 0 - size := 100000 - for i := 0; i < size; i++ { - count ++ - } - return count - } + [class]{}-[func]{constant} ``` === "JavaScript" @@ -904,14 +896,7 @@ $$ === "Go" ```go title="time_complexity.go" - /* 线性阶 */ - func linear(n int) int { - count := 0 - for i := 0; i < n; i++ { - count++ - } - return count - } + [class]{}-[func]{linear} ``` === "JavaScript" @@ -992,15 +977,7 @@ $$ === "Go" ```go title="time_complexity.go" - /* 线性阶(遍历数组) */ - func arrayTraversal(nums []int) int { - count := 0 - // 循环次数与数组长度成正比 - for range nums { - count++ - } - return count - } + [class]{}-[func]{arrayTraversal} ``` === "JavaScript" @@ -1080,17 +1057,7 @@ $$ === "Go" ```go title="time_complexity.go" - /* 平方阶 */ - func quadratic(n int) int { - count := 0 - // 循环次数与数组长度成平方关系 - for i := 0; i < n; i++ { - for j := 0; j < n; j++ { - count++ - } - } - return count - } + [class]{}-[func]{quadratic} ``` === "JavaScript" @@ -1182,24 +1149,7 @@ $$ === "Go" ```go title="time_complexity.go" - /* 平方阶(冒泡排序) */ - func bubbleSort(nums []int) int { - count := 0 // 计数器 - // 外循环:待排序元素数量为 n-1, n-2, ..., 1 - for i := len(nums) - 1; i > 0; i-- { - // 内循环:冒泡操作 - for j := 0; j < i; j++ { - if nums[j] > nums[j+1] { - // 交换 nums[j] 与 nums[j + 1] - tmp := nums[j] - nums[j] = nums[j+1] - nums[j+1] = tmp - count += 3 // 元素交换包含 3 个单元操作 - } - } - } - return count - } + [class]{}-[func]{bubbleSort} ``` === "JavaScript" @@ -1305,19 +1255,7 @@ $$ === "Go" ```go title="time_complexity.go" - /* 指数阶(循环实现)*/ - func exponential(n int) int { - count, base := 0, 1 - // cell 每轮一分为二,形成数列 1, 2, 4, 8, ..., 2^(n-1) - for i := 0; i < n; i++ { - for j := 0; j < base; j++ { - count++ - } - base *= 2 - } - // count = 1 + 2 + 4 + 8 + .. + 2^(n-1) = 2^n - 1 - return count - } + [class]{}-[func]{exponential} ``` === "JavaScript" @@ -1411,13 +1349,7 @@ $$ === "Go" ```go title="time_complexity.go" - /* 指数阶(递归实现)*/ - func expRecur(n int) int { - if n == 1 { - return 1 - } - return expRecur(n-1) + expRecur(n-1) + 1 - } + [class]{}-[func]{expRecur} ``` === "JavaScript" @@ -1493,15 +1425,7 @@ $$ === "Go" ```go title="time_complexity.go" - /* 对数阶(循环实现)*/ - func logarithmic(n float64) int { - count := 0 - for n > 1 { - n = n / 2 - count++ - } - return count - } + [class]{}-[func]{logarithmic} ``` === "JavaScript" @@ -1586,13 +1510,7 @@ $$ === "Go" ```go title="time_complexity.go" - /* 对数阶(递归实现)*/ - func logRecur(n float64) int { - if n <= 1 { - return 0 - } - return logRecur(n/2) + 1 - } + [class]{}-[func]{logRecur} ``` === "JavaScript" @@ -1667,18 +1585,7 @@ $$ === "Go" ```go title="time_complexity.go" - /* 线性对数阶 */ - func linearLogRecur(n float64) int { - if n <= 1 { - return 1 - } - count := linearLogRecur(n/2) + - linearLogRecur(n/2) - for i := 0.0; i < n; i++ { - count++ - } - return count - } + [class]{}-[func]{linearLogRecur} ``` === "JavaScript" @@ -1772,18 +1679,7 @@ $$ === "Go" ```go title="time_complexity.go" - /* 阶乘阶(递归实现) */ - func factorialRecur(n int) int { - if n == 0 { - return 1 - } - count := 0 - // 从 1 个分裂出 n 个 - for i := 0; i < n; i++ { - count += factorialRecur(n - 1) - } - return count - } + [class]{}-[func]{factorialRecur} ``` === "JavaScript" diff --git a/docs/chapter_hashing/hash_map.md b/docs/chapter_hashing/hash_map.md index 739a8eff..a6e9c1a6 100755 --- a/docs/chapter_hashing/hash_map.md +++ b/docs/chapter_hashing/hash_map.md @@ -440,52 +440,9 @@ $$ === "Go" ```go title="array_hash_map.go" - /* 键值对 int->String */ - type entry struct { - key int - val string - } - - /* 基于数组简易实现的哈希表 */ - type arrayHashMap struct { - bucket []*entry - } - - func newArrayHashMap() *arrayHashMap { - // 初始化一个长度为 100 的桶(数组) - bucket := make([]*entry, 100) - return &arrayHashMap{bucket: bucket} - } - - /* 哈希函数 */ - func (a *arrayHashMap) hashFunc(key int) int { - index := key % 100 - return index - } - - /* 查询操作 */ - func (a *arrayHashMap) get(key int) string { - index := a.hashFunc(key) - pair := a.bucket[index] - if pair == nil { - return "Not Found" - } - return pair.val - } - - /* 添加操作 */ - func (a *arrayHashMap) put(key int, val string) { - pair := &entry{key: key, val: val} - index := a.hashFunc(key) - a.bucket[index] = pair - } - - /* 删除操作 */ - func (a *arrayHashMap) remove(key int) { - index := a.hashFunc(key) - // 置为 nil ,代表删除 - a.bucket[index] = nil - } + [class]{entry}-[func]{} + + [class]{arrayHashMap}-[func]{} ``` === "JavaScript" diff --git a/docs/chapter_heap/heap.md b/docs/chapter_heap/heap.md index 988e5fd4..ef244b57 100644 --- a/docs/chapter_heap/heap.md +++ b/docs/chapter_heap/heap.md @@ -286,33 +286,11 @@ comments: true === "Go" ```go title="my_heap.go" - type maxHeap struct { - // 使用切片而非数组,这样无需考虑扩容问题 - data []any - } + [class]{maxHeap}-[func]{left} - /* 构造函数,建立空堆 */ - func newHeap() *maxHeap { - return &maxHeap{ - data: make([]any, 0), - } - } + [class]{maxHeap}-[func]{right} - /* 获取左子结点索引 */ - func (h *maxHeap) left(i int) int { - return 2*i + 1 - } - - /* 获取右子结点索引 */ - func (h *maxHeap) right(i int) int { - return 2*i + 2 - } - - /* 获取父结点索引 */ - func (h *maxHeap) parent(i int) int { - // 向下整除 - return (i - 1) / 2 - } + [class]{maxHeap}-[func]{parent} ``` === "JavaScript" @@ -392,10 +370,7 @@ comments: true === "Go" ```go title="my_heap.go" - /* 访问堆顶元素 */ - func (h *maxHeap) peek() any { - return h.data[0] - } + [class]{maxHeap}-[func]{peek} ``` === "JavaScript" @@ -485,29 +460,9 @@ comments: true === "Go" ```go title="my_heap.go" - /* 元素入堆 */ - func (h *maxHeap) push(val any) { - // 添加结点 - h.data = append(h.data, val) - // 从底至顶堆化 - h.siftUp(len(h.data) - 1) - } + [class]{maxHeap}-[func]{push} - /* 从结点 i 开始,从底至顶堆化 */ - func (h *maxHeap) siftUp(i int) { - for true { - // 获取结点 i 的父结点 - p := h.parent(i) - // 当“越过根结点”或“结点无需修复”时,结束堆化 - if p < 0 || h.data[i].(int) <= h.data[p].(int) { - break - } - // 交换两结点 - h.swap(i, p) - // 循环向上堆化 - i = p - } - } + [class]{maxHeap}-[func]{siftUp} ``` === "JavaScript" @@ -621,46 +576,9 @@ comments: true === "Go" ```go title="my_heap.go" - /* 元素出堆 */ - func (h *maxHeap) poll() any { - // 判空处理 - if h.isEmpty() { - fmt.Println("error") - return nil - } - // 交换根结点与最右叶结点(即交换首元素与尾元素) - h.swap(0, h.size()-1) - // 删除结点 - val := h.data[len(h.data)-1] - h.data = h.data[:len(h.data)-1] - // 从顶至底堆化 - h.siftDown(0) + [class]{maxHeap}-[func]{poll} - // 返回堆顶元素 - return val - } - - /* 从结点 i 开始,从顶至底堆化 */ - func (h *maxHeap) siftDown(i int) { - for true { - // 判断结点 i, l, r 中值最大的结点,记为 max - l, r, max := h.left(i), h.right(i), i - if l < h.size() && h.data[l].(int) > h.data[max].(int) { - max = l - } - if r < h.size() && h.data[r].(int) > h.data[max].(int) { - max = r - } - // 若结点 i 最大或索引 l, r 越界,则无需继续堆化,跳出 - if max == i { - break - } - // 交换两结点 - h.swap(i, max) - // 循环向下堆化 - i = max - } - } + [class]{maxHeap}-[func]{siftDown} ``` === "JavaScript" @@ -734,16 +652,7 @@ comments: true === "Go" ```go title="my_heap.go" - /* 构造函数,根据切片建堆 */ - func newMaxHeap(nums []any) *maxHeap { - // 将列表元素原封不动添加进堆 - h := &maxHeap{data: nums} - // 堆化除叶结点以外的其他所有结点 - for i := len(h.data) - 1; i >= 0; i-- { - h.siftDown(i) - } - return h - } + [class]{maxHeap}-[func]{newMaxHeap} ``` === "JavaScript" diff --git a/docs/chapter_searching/binary_search.md b/docs/chapter_searching/binary_search.md index 759b18fc..ec48b21d 100755 --- a/docs/chapter_searching/binary_search.md +++ b/docs/chapter_searching/binary_search.md @@ -72,24 +72,7 @@ $$ === "Go" ```go title="binary_search.go" - /* 二分查找(双闭区间) */ - func binarySearch(nums []int, target int) int { - // 初始化双闭区间 [0, n-1] ,即 i, j 分别指向数组首元素、尾元素 - i, j := 0, len(nums)-1 - // 循环,当搜索区间为空时跳出(当 i > j 时为空) - for i <= j { - m := (i + j) / 2 // 计算中点索引 m - if nums[m] < target { // 此情况说明 target 在区间 [m+1, j] 中 - i = m + 1 - } else if nums[m] > target { // 此情况说明 target 在区间 [i, m-1] 中 - j = m - 1 - } else { // 找到目标元素,返回其索引 - return m - } - } - // 未找到目标元素,返回 -1 - return -1 - } + [class]{}-[func]{binarySearch} ``` === "JavaScript" @@ -153,24 +136,7 @@ $$ === "Go" ```go title="binary_search.go" - /* 二分查找(左闭右开) */ - func binarySearch1(nums []int, target int) int { - // 初始化左闭右开 [0, n) ,即 i, j 分别指向数组首元素、尾元素+1 - i, j := 0, len(nums) - // 循环,当搜索区间为空时跳出(当 i = j 时为空) - for i < j { - m := (i + j) / 2 // 计算中点索引 m - if nums[m] < target { // 此情况说明 target 在区间 [m+1, j) 中 - i = m + 1 - } else if nums[m] > target { // 此情况说明 target 在区间 [i, m) 中 - j = m - } else { // 找到目标元素,返回其索引 - return m - } - } - // 未找到目标元素,返回 -1 - return -1 - } + [class]{}-[func]{binarySearch1} ``` === "JavaScript" diff --git a/docs/chapter_searching/hashing_search.md b/docs/chapter_searching/hashing_search.md index 89d865ae..1fc1410d 100755 --- a/docs/chapter_searching/hashing_search.md +++ b/docs/chapter_searching/hashing_search.md @@ -37,16 +37,7 @@ comments: true === "Go" ```go title="hashing_search.go" - /* 哈希查找(数组) */ - func hashingSearchArray(m map[int]int, target int) int { - // 哈希表的 key: 目标元素,value: 索引 - // 若哈希表中无此 key ,返回 -1 - if index, ok := m[target]; ok { - return index - } else { - return -1 - } - } + [class]{}-[func]{hashingSearchArray} ``` === "JavaScript" @@ -110,16 +101,7 @@ comments: true === "Go" ```go title="hashing_search.go" - /* 哈希查找(链表) */ - func hashingSearchLinkedList(m map[int]*ListNode, target int) *ListNode { - // 哈希表的 key: 目标结点值,value: 结点对象 - // 若哈希表中无此 key ,返回 nil - if node, ok := m[target]; ok { - return node - } else { - return nil - } - } + [class]{}-[func]{hashingSearchLinkedList} ``` === "JavaScript" diff --git a/docs/chapter_searching/linear_search.md b/docs/chapter_searching/linear_search.md index 11591e30..dac32b89 100755 --- a/docs/chapter_searching/linear_search.md +++ b/docs/chapter_searching/linear_search.md @@ -33,18 +33,7 @@ comments: true === "Go" ```go title="linear_search.go" - /* 线性查找(数组) */ - func linearSearchArray(nums []int, target int) int { - // 遍历数组 - for i := 0; i < len(nums); i++ { - // 找到目标元素,返回其索引 - if nums[i] == target { - return i - } - } - // 未找到目标元素,返回 -1 - return -1 - } + [class]{}-[func]{linearSearchArray} ``` === "JavaScript" @@ -106,19 +95,7 @@ comments: true === "Go" ```go title="linear_search.go" - /* 线性查找(链表)*/ - func linerSearchLinkedList(node *ListNode, target int) *ListNode { - // 遍历链表 - for node != nil { - // 找到目标结点,返回之 - if node.Val == target { - return node - } - node = node.Next - } - // 未找到目标元素,返回 nil - return nil - } + [class]{}-[func]{linearSearchLinkedList} ``` === "JavaScript" diff --git a/docs/chapter_sorting/bubble_sort.md b/docs/chapter_sorting/bubble_sort.md index 8512c6fc..1f02d0c6 100755 --- a/docs/chapter_sorting/bubble_sort.md +++ b/docs/chapter_sorting/bubble_sort.md @@ -68,19 +68,7 @@ comments: true === "Go" ```go title="bubble_sort.go" - /* 冒泡排序 */ - func bubbleSort(nums []int) { - // 外循环:待排序元素数量为 n-1, n-2, ..., 1 - for i := len(nums) - 1; i > 0; i-- { - // 内循环:冒泡操作 - for j := 0; j < i; j++ { - if nums[j] > nums[j+1] { - // 交换 nums[j] 与 nums[j + 1] - nums[j], nums[j+1] = nums[j+1], nums[j] - } - } - } - } + [class]{}-[func]{bubbleSort} ``` === "JavaScript" @@ -174,24 +162,7 @@ comments: true === "Go" ```go title="bubble_sort.go" - /* 冒泡排序(标志优化)*/ - func bubbleSortWithFlag(nums []int) { - // 外循环:待排序元素数量为 n-1, n-2, ..., 1 - for i := len(nums) - 1; i > 0; i-- { - flag := false // 初始化标志位 - // 内循环:冒泡操作 - for j := 0; j < i; j++ { - if nums[j] > nums[j+1] { - // 交换 nums[j] 与 nums[j + 1] - nums[j], nums[j+1] = nums[j+1], nums[j] - flag = true // 记录交换元素 - } - } - if flag == false { // 此轮冒泡未交换任何元素,直接跳出 - break - } - } - } + [class]{}-[func]{bubbleSortWithFlag} ``` === "JavaScript" diff --git a/docs/chapter_sorting/insertion_sort.md b/docs/chapter_sorting/insertion_sort.md index 0281fd27..f35f8bd4 100755 --- a/docs/chapter_sorting/insertion_sort.md +++ b/docs/chapter_sorting/insertion_sort.md @@ -45,20 +45,7 @@ comments: true === "Go" ```go title="insertion_sort.go" - /* 插入排序 */ - func insertionSort(nums []int) { - // 外循环:待排序元素数量为 n-1, n-2, ..., 1 - for i := 1; i < len(nums); i++ { - base := nums[i] - j := i - 1 - // 内循环:将 base 插入到左边的正确位置 - for j >= 0 && nums[j] > base { - nums[j+1] = nums[j] // 1. 将 nums[j] 向右移动一位 - j-- - } - nums[j+1] = base // 2. 将 base 赋值到正确位置 - } - } + [class]{}-[func]{insertionSort} ``` === "JavaScript" diff --git a/docs/chapter_sorting/quick_sort.md b/docs/chapter_sorting/quick_sort.md index fdc84726..5e43221b 100755 --- a/docs/chapter_sorting/quick_sort.md +++ b/docs/chapter_sorting/quick_sort.md @@ -68,24 +68,7 @@ comments: true === "Go" ```go title="quick_sort.go" - /* 哨兵划分 */ - func partition(nums []int, left, right int) int { - // 以 nums[left] 作为基准数 - i, j := left, right - for i < j { - for i < j && nums[j] >= nums[left] { - j-- // 从右向左找首个小于基准数的元素 - } - for i < j && nums[i] <= nums[left] { - i++ // 从左向右找首个大于基准数的元素 - } - //元素交换 - nums[i], nums[j] = nums[j], nums[i] - } - // 将基准数交换至两子数组的分界线 - nums[i], nums[left] = nums[left], nums[i] - return i // 返回基准数的索引 - } + [class]{quickSort}-[func]{partition} ``` === "JavaScript" @@ -169,18 +152,7 @@ comments: true === "Go" ```go title="quick_sort.go" - /* 快速排序 */ - func quickSort(nums []int, left, right int) { - // 子数组长度为 1 时终止递归 - if left >= right { - return - } - // 哨兵划分 - pivot := partition(nums, left, right) - // 递归左子数组、右子数组 - quickSort(nums, left, pivot-1) - quickSort(nums, pivot+1, right) - } + [class]{quickSort}-[func]{quickSort} ``` === "JavaScript" @@ -276,25 +248,9 @@ comments: true === "Go" ```go title="quick_sort.go" - /* 选取三个元素的中位数 */ - func medianThree(nums []int, left, mid, right int) int { - if (nums[left] < nums[mid]) != (nums[left] < nums[right]) { - return left - } else if (nums[mid] > nums[left]) != (nums[mid] > nums[right]) { - return mid - } - return right - } + [class]{quickSortMedian}-[func]{medianThree} - /* 哨兵划分(三数取中值)*/ - func partition(nums []int, left, right int) int { - // 以 nums[left] 作为基准数 - med := medianThree(nums, left, (left+right)/2, right) - // 将中位数交换至数组最左端 - nums[left], nums[med] = nums[med], nums[left] - // 以 nums[left] 作为基准数 - // 下同省略... - } + [class]{quickSortMedian}-[func]{partition} ``` === "JavaScript" @@ -368,22 +324,7 @@ comments: true === "Go" ```go title="quick_sort.go" - /* 快速排序(尾递归优化)*/ - func quickSort(nums []int, left, right int) { - // 子数组长度为 1 时终止 - for left < right { - // 哨兵划分操作 - pivot := partition(nums, left, right) - // 对两个子数组中较短的那个执行快排 - if pivot-left < right-pivot { - quickSort(nums, left, pivot-1) // 递归排序左子数组 - left = pivot + 1 // 剩余待排序区间为 [pivot + 1, right] - } else { - quickSort(nums, pivot+1, right) // 递归排序右子数组 - right = pivot - 1 // 剩余待排序区间为 [left, pivot - 1] - } - } - } + [class]{quickSortTailCall}-[func]{quickSort} ``` === "JavaScript" diff --git a/docs/chapter_stack_and_queue/queue.md b/docs/chapter_stack_and_queue/queue.md index 71ef6c75..e6664e82 100755 --- a/docs/chapter_stack_and_queue/queue.md +++ b/docs/chapter_stack_and_queue/queue.md @@ -302,52 +302,7 @@ comments: true === "Go" ```go title="linkedlist_queue.go" - /* 基于链表实现的队列 */ - type linkedListQueue struct { - // 使用内置包 list 来实现队列 - data *list.List - } - - // newLinkedListQueue 初始化链表 - func newLinkedListQueue() *linkedListQueue { - return &linkedListQueue{ - data: list.New(), - } - } - - // push 入队 - func (s *linkedListQueue) push(value any) { - s.data.PushBack(value) - } - - // poll 出队 - func (s *linkedListQueue) poll() any { - if s.isEmpty() { - return nil - } - e := s.data.Front() - s.data.Remove(e) - return e.Value - } - - // peek 访问队首元素 - func (s *linkedListQueue) peek() any { - if s.isEmpty() { - return nil - } - e := s.data.Front() - return e.Value - } - - // size 获取队列的长度 - func (s *linkedListQueue) size() int { - return s.data.Len() - } - - // isEmpty 判断队列是否为空 - func (s *linkedListQueue) isEmpty() bool { - return s.data.Len() == 0 - } + [class]{linkedListQueue}-[func]{} ``` === "JavaScript" @@ -424,74 +379,7 @@ comments: true === "Go" ```go title="array_queue.go" - /* 基于环形数组实现的队列 */ - type arrayQueue struct { - nums []int // 用于存储队列元素的数组 - front int // 队首指针,指向队首元素 - queSize int // 队列长度 - queCapacity int // 队列容量(即最大容纳元素数量) - } - - // newArrayQueue 基于环形数组实现的队列 - func newArrayQueue(queCapacity int) *arrayQueue { - return &arrayQueue{ - nums: make([]int, queCapacity), - queCapacity: queCapacity, - front: 0, - queSize: 0, - } - } - - // size 获取队列的长度 - func (q *arrayQueue) size() int { - return q.queSize - } - - // isEmpty 判断队列是否为空 - func (q *arrayQueue) isEmpty() bool { - return q.queSize == 0 - } - - // push 入队 - func (q *arrayQueue) push(num int) { - // 当 rear == queCapacity 表示队列已满 - if q.queSize == q.queCapacity { - return - } - // 计算尾指针,指向队尾索引 + 1 - // 通过取余操作,实现 rear 越过数组尾部后回到头部 - rear := (q.front + q.queSize) % q.queCapacity - // 尾结点后添加 num - q.nums[rear] = num - q.queSize++ - } - - // poll 出队 - func (q *arrayQueue) poll() any { - num := q.peek() - // 队首指针向后移动一位,若越过尾部则返回到数组头部 - q.front = (q.front + 1) % q.queCapacity - q.queSize-- - return num - } - - // peek 访问队首元素 - func (q *arrayQueue) peek() any { - if q.isEmpty() { - return nil - } - return q.nums[q.front] - } - - // 获取 Slice 用于打印 - func (q *arrayQueue) toSlice() []int { - rear := (q.front + q.queSize) - if rear >= q.queCapacity { - rear %= q.queCapacity - return append(q.nums[q.front:], q.nums[:rear]...) - } - return q.nums[q.front:rear] - } + [class]{arrayQueue}-[func]{} ``` === "JavaScript" diff --git a/docs/chapter_stack_and_queue/stack.md b/docs/chapter_stack_and_queue/stack.md index 7d7c9300..0b13e732 100755 --- a/docs/chapter_stack_and_queue/stack.md +++ b/docs/chapter_stack_and_queue/stack.md @@ -305,52 +305,7 @@ comments: true === "Go" ```go title="linkedlist_stack.go" - /* 基于链表实现的栈 */ - type linkedListStack struct { - // 使用内置包 list 来实现栈 - data *list.List - } - - // newLinkedListStack 初始化链表 - func newLinkedListStack() *linkedListStack { - return &linkedListStack{ - data: list.New(), - } - } - - // push 入栈 - func (s *linkedListStack) push(value int) { - s.data.PushBack(value) - } - - // pop 出栈 - func (s *linkedListStack) pop() any { - if s.isEmpty() { - return nil - } - e := s.data.Back() - s.data.Remove(e) - return e.Value - } - - // peek 访问栈顶元素 - func (s *linkedListStack) peek() any { - if s.isEmpty() { - return nil - } - e := s.data.Back() - return e.Value - } - - // size 获取栈的长度 - func (s *linkedListStack) size() int { - return s.data.Len() - } - - // isEmpty 判断栈是否为空 - func (s *linkedListStack) isEmpty() bool { - return s.data.Len() == 0 - } + [class]{linkedListStack}-[func]{} ``` === "JavaScript" @@ -425,53 +380,7 @@ comments: true === "Go" ```go title="array_stack.go" - /* 基于数组实现的栈 */ - type arrayStack struct { - data []int // 数据 - } - - func newArrayStack() *arrayStack { - return &arrayStack{ - // 设置栈的长度为 0,容量为 16 - data: make([]int, 0, 16), - } - } - - // size 栈的长度 - func (s *arrayStack) size() int { - return len(s.data) - } - - // isEmpty 栈是否为空 - func (s *arrayStack) isEmpty() bool { - return s.size() == 0 - } - - // push 入栈 - func (s *arrayStack) push(v int) { - // 切片会自动扩容 - s.data = append(s.data, v) - } - - // pop 出栈 - func (s *arrayStack) pop() any { - // 弹出栈前,先判断是否为空 - if s.isEmpty() { - return nil - } - val := s.peek() - s.data = s.data[:len(s.data)-1] - return val - } - - // peek 获取栈顶元素 - func (s *arrayStack) peek() any { - if s.isEmpty() { - return nil - } - val := s.data[len(s.data)-1] - return val - } + [class]{arrayStack}-[func]{} ``` === "JavaScript" diff --git a/docs/chapter_tree/avl_tree.md b/docs/chapter_tree/avl_tree.md index 9ea12a75..51e5d4b6 100644 --- a/docs/chapter_tree/avl_tree.md +++ b/docs/chapter_tree/avl_tree.md @@ -182,26 +182,9 @@ G. M. Adelson-Velsky 和 E. M. Landis 在其 1962 年发表的论文 "An algorit === "Go" ```go title="avl_tree.go" - /* 获取结点高度 */ - func height(node *TreeNode) int { - // 空结点高度为 -1 ,叶结点高度为 0 - if node != nil { - return node.Height - } - return -1 - } + [class]{aVLTree}-[func]{height} - /* 更新结点高度 */ - func updateHeight(node *TreeNode) { - lh := height(node.Left) - rh := height(node.Right) - // 结点高度等于最高子树高度 + 1 - if lh > rh { - node.Height = lh + 1 - } else { - node.Height = rh + 1 - } - } + [class]{aVLTree}-[func]{updateHeight} ``` === "JavaScript" @@ -273,15 +256,7 @@ G. M. Adelson-Velsky 和 E. M. Landis 在其 1962 年发表的论文 "An algorit === "Go" ```go title="avl_tree.go" - /* 获取平衡因子 */ - func balanceFactor(node *TreeNode) int { - // 空结点平衡因子为 0 - if node == nil { - return 0 - } - // 结点平衡因子 = 左子树高度 - 右子树高度 - return height(node.Left) - height(node.Right) - } + [class]{aVLTree}-[func]{balanceFactor} ``` === "JavaScript" @@ -375,19 +350,7 @@ AVL 树的独特之处在于「旋转 Rotation」的操作,其可 **在不影 === "Go" ```go title="avl_tree.go" - /* 右旋操作 */ - func rightRotate(node *TreeNode) *TreeNode { - child := node.Left - grandChild := child.Right - // 以 child 为原点,将 node 向右旋转 - child.Right = node - node.Left = grandChild - // 更新结点高度 - updateHeight(node) - updateHeight(child) - // 返回旋转后子树的根结点 - return child - } + [class]{aVLTree}-[func]{rightRotate} ``` === "JavaScript" @@ -459,19 +422,7 @@ AVL 树的独特之处在于「旋转 Rotation」的操作,其可 **在不影 === "Go" ```go title="avl_tree.go" - /* 左旋操作 */ - func leftRotate(node *TreeNode) *TreeNode { - child := node.Right - grandChild := child.Left - // 以 child 为原点,将 node 向左旋转 - child.Left = node - node.Right = grandChild - // 更新结点高度 - updateHeight(node) - updateHeight(child) - // 返回旋转后子树的根结点 - return child - } + [class]{aVLTree}-[func]{leftRotate} ``` === "JavaScript" @@ -566,36 +517,7 @@ AVL 树的独特之处在于「旋转 Rotation」的操作,其可 **在不影 === "Go" ```go title="avl_tree.go" - /* 执行旋转操作,使该子树重新恢复平衡 */ - func rotate(node *TreeNode) *TreeNode { - // 获取结点 node 的平衡因子 - // Go 推荐短变量,这里 bf 指代 balanceFactor - bf := balanceFactor(node) - // 左偏树 - if bf > 1 { - if balanceFactor(node.Left) >= 0 { - // 右旋 - return rightRotate(node) - } else { - // 先左旋后右旋 - node.Left = leftRotate(node.Left) - return rightRotate(node) - } - } - // 右偏树 - if bf < -1 { - if balanceFactor(node.Right) <= 0 { - // 左旋 - return leftRotate(node) - } else { - // 先右旋后左旋 - node.Right = rightRotate(node.Right) - return leftRotate(node) - } - } - // 平衡树,无需旋转,直接返回 - return node - } + [class]{aVLTree}-[func]{rotate} ``` === "JavaScript" @@ -667,32 +589,9 @@ AVL 树的独特之处在于「旋转 Rotation」的操作,其可 **在不影 === "Go" ```go title="avl_tree.go" - /* 插入结点 */ - func (t *avlTree) insert(val int) *TreeNode { - t.root = insertHelper(t.root, val) - return t.root - } - /* 递归插入结点(辅助函数) */ - func insertHelper(node *TreeNode, val int) *TreeNode { - if node == nil { - return NewTreeNode(val) - } - /* 1. 查找插入位置,并插入结点 */ - if val < node.Val { - node.Left = insertHelper(node.Left, val) - } else if val > node.Val { - node.Right = insertHelper(node.Right, val) - } else { - // 重复结点不插入,直接返回 - return node - } - // 更新结点高度 - updateHeight(node) - /* 2. 执行旋转操作,使该子树重新恢复平衡 */ - node = rotate(node) - // 返回子树的根结点 - return node - } + [class]{aVLTree}-[func]{insert} + + [class]{aVLTree}-[func]{insertHelper} ``` === "JavaScript" @@ -778,61 +677,11 @@ AVL 树的独特之处在于「旋转 Rotation」的操作,其可 **在不影 === "Go" ```go title="avl_tree.go" - /* 删除结点 */ - func (t *avlTree) remove(val int) *TreeNode { - root := removeHelper(t.root, val) - return root - } + [class]{aVLTree}-[func]{remove} - /* 递归删除结点(辅助函数) */ - func removeHelper(node *TreeNode, val int) *TreeNode { - if node == nil { - return nil - } - /* 1. 查找结点,并删除之 */ - if val < node.Val { - node.Left = removeHelper(node.Left, val) - } else if val > node.Val { - node.Right = removeHelper(node.Right, val) - } else { - if node.Left == nil || node.Right == nil { - child := node.Left - if node.Right != nil { - child = node.Right - } - // 子结点数量 = 0 ,直接删除 node 并返回 - if child == nil { - return nil - } else { - // 子结点数量 = 1 ,直接删除 node - node = child - } - } else { - // 子结点数量 = 2 ,则将中序遍历的下个结点删除,并用该结点替换当前结点 - temp := getInOrderNext(node.Right) - node.Right = removeHelper(node.Right, temp.Val) - node.Val = temp.Val - } - } - // 更新结点高度 - updateHeight(node) - /* 2. 执行旋转操作,使该子树重新恢复平衡 */ - node = rotate(node) - // 返回子树的根结点 - return node - } + [class]{aVLTree}-[func]{removeHelper} - /* 获取中序遍历中的下一个结点(仅适用于 root 有左子结点的情况) */ - func getInOrderNext(node *TreeNode) *TreeNode { - if node == nil { - return node - } - // 循环访问左子结点,直到叶结点时为最小结点,跳出 - for node.Left != nil { - node = node.Left - } - return node - } + [class]{aVLTree}-[func]{getInOrderNext} ``` === "JavaScript" diff --git a/docs/chapter_tree/binary_search_tree.md b/docs/chapter_tree/binary_search_tree.md index 814d04bb..613a7f22 100755 --- a/docs/chapter_tree/binary_search_tree.md +++ b/docs/chapter_tree/binary_search_tree.md @@ -56,25 +56,7 @@ comments: true === "Go" ```go title="binary_search_tree.go" - /* 查找结点 */ - func (bst *binarySearchTree) search(num int) *TreeNode { - node := bst.root - // 循环查找,越过叶结点后跳出 - for node != nil { - if node.Val < num { - // 目标结点在 cur 的右子树中 - node = node.Right - } else if node.Val > num { - // 目标结点在 cur 的左子树中 - node = node.Left - } else { - // 找到目标结点,跳出循环 - break - } - } - // 返回目标结点 - return node - } + [class]{binarySearchTree}-[func]{search} ``` === "JavaScript" @@ -145,36 +127,7 @@ comments: true === "Go" ```go title="binary_search_tree.go" - /* 插入结点 */ - func (bst *binarySearchTree) insert(num int) *TreeNode { - cur := bst.root - // 若树为空,直接提前返回 - if cur == nil { - return nil - } - // 待插入结点之前的结点位置 - var pre *TreeNode = nil - // 循环查找,越过叶结点后跳出 - for cur != nil { - if cur.Val == num { - return nil - } - pre = cur - if cur.Val < num { - cur = cur.Right - } else { - cur = cur.Left - } - } - // 插入结点 - node := NewTreeNode(num) - if pre.Val < num { - pre.Right = node - } else { - pre.Left = node - } - return cur - } + [class]{binarySearchTree}-[func]{insert} ``` === "JavaScript" @@ -276,72 +229,9 @@ comments: true === "Go" ```go title="binary_search_tree.go" - /* 删除结点 */ - func (bst *binarySearchTree) remove(num int) *TreeNode { - cur := bst.root - // 若树为空,直接提前返回 - if cur == nil { - return nil - } - // 待删除结点之前的结点位置 - var pre *TreeNode = nil - // 循环查找,越过叶结点后跳出 - for cur != nil { - if cur.Val == num { - break - } - pre = 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 pre.Left == cur { - pre.Left = child - } else { - pre.Right = child - } - // 子结点数为 2 - } else { - // 获取中序遍历中待删除结点 cur 的下一个结点 - next := bst.getInOrderNext(cur) - temp := next.Val - // 递归删除结点 next - bst.remove(next.Val) - // 将 next 的值复制给 cur - cur.Val = temp - } - return cur - } + [class]{binarySearchTree}-[func]{remove} - /* 获取中序遍历的下一个结点(仅适用于 root 有左子结点的情况) */ - func (bst *binarySearchTree) getInOrderNext(node *TreeNode) *TreeNode { - if node == nil { - return node - } - // 循环访问左子结点,直到叶结点时为最小结点,跳出 - for node.Left != nil { - node = node.Left - } - return node - } + [class]{binarySearchTree}-[func]{getInOrderNext} ``` === "JavaScript" diff --git a/docs/chapter_tree/binary_tree_traversal.md b/docs/chapter_tree/binary_tree_traversal.md index d5640327..01347724 100755 --- a/docs/chapter_tree/binary_tree_traversal.md +++ b/docs/chapter_tree/binary_tree_traversal.md @@ -39,29 +39,7 @@ comments: true === "Go" ```go title="binary_tree_bfs.go" - /* 层序遍历 */ - func levelOrder(root *TreeNode) []int { - // 初始化队列,加入根结点 - queue := list.New() - queue.PushBack(root) - // 初始化一个切片,用于保存遍历序列 - nums := make([]int, 0) - for queue.Len() > 0 { - // poll - node := queue.Remove(queue.Front()).(*TreeNode) - // 保存结点值 - nums = append(nums, node.Val) - if node.Left != nil { - // 左子结点入队 - queue.PushBack(node.Left) - } - if node.Right != nil { - // 右子结点入队 - queue.PushBack(node.Right) - } - } - return nums - } + [class]{}-[func]{hierOrder} ``` === "JavaScript" @@ -153,38 +131,11 @@ comments: true === "Go" ```go title="binary_tree_dfs.go" - /* 前序遍历 */ - func preOrder(node *TreeNode) { - if node == nil { - return - } - // 访问优先级:根结点 -> 左子树 -> 右子树 - nums = append(nums, node.Val) - preOrder(node.Left) - preOrder(node.Right) - } - - /* 中序遍历 */ - func inOrder(node *TreeNode) { - if node == nil { - return - } - // 访问优先级:左子树 -> 根结点 -> 右子树 - inOrder(node.Left) - nums = append(nums, node.Val) - inOrder(node.Right) - } - - /* 后序遍历 */ - func postOrder(node *TreeNode) { - if node == nil { - return - } - // 访问优先级:左子树 -> 右子树 -> 根结点 - postOrder(node.Left) - postOrder(node.Right) - nums = append(nums, node.Val) - } + [class]{}-[func]{preOrder} + + [class]{}-[func]{inOrder} + + [class]{}-[func]{postOrder} ``` === "JavaScript" diff --git a/docs/utils/build_markdown.py b/docs/utils/build_markdown.py index 65c6828d..480d2700 100755 --- a/docs/utils/build_markdown.py +++ b/docs/utils/build_markdown.py @@ -16,6 +16,7 @@ from docs.utils.extract_code_cpp import ExtractCodeBlocksCpp from docs.utils.extract_code_jsts import ExtractCodeBlocksJSTS from docs.utils.extract_code_swift import ExtractCodeBlocksSwift from docs.utils.extract_code_csharp import ExtractCodeBlocksCSharp +from docs.utils.extract_code_go import ExtractCodeBlocksGo def build_markdown(md_path): @@ -92,6 +93,7 @@ extractor_dict = { "java": ExtractCodeBlocksJava(), "python": ExtractCodeBlocksPython(), "cpp": ExtractCodeBlocksCpp(), + "go": ExtractCodeBlocksGo(), "javascript": ExtractCodeBlocksJSTS(), "typescript": ExtractCodeBlocksJSTS(), "swift": ExtractCodeBlocksSwift(), diff --git a/docs/utils/deploy.sh b/docs/utils/deploy.sh index 280d9511..214b7575 100644 --- a/docs/utils/deploy.sh +++ b/docs/utils/deploy.sh @@ -24,4 +24,4 @@ cd site git add . git commit -m "deploy" git push -u origin gh-pages -cd.. +cd .. diff --git a/docs/utils/extract_code_go.py b/docs/utils/extract_code_go.py new file mode 100644 index 00000000..f09b4e4a --- /dev/null +++ b/docs/utils/extract_code_go.py @@ -0,0 +1,183 @@ +""" +File: extract_code_go.py +Created Time: 2023-02-07 +Author: Krahets (krahets@163.com) +""" + +import re +import glob +import sys, os.path as osp +sys.path.append(osp.dirname(osp.dirname(osp.dirname(osp.abspath(__file__))))) +from docs.utils.extract_code_java import ExtractCodeBlocksJava + + +class ExtractCodeBlocksGo(ExtractCodeBlocksJava): + def __init__(self) -> None: + super().__init__() + + # Pattern to match function names and class names + self.func_pattern = r'(\s*)func\s+(\(.+\))*\s*(\w+)\((.*)\)\s*(\S*)\s*{\n' + self.class_pattern = r'(\s*)type\s+(\w+)' + + self.func_pattern_keys = ["total", "ind", "class", "label", "params", "return"] + self.class_pattern_keys = ["total", "ind", "label"] + + # Pattern to match the start and end of a block + self.block_end_pattern = '^\s{ind}\}' + self.block_start_pattern = '^\s{ind}\/\*.+\*\/' + self.block_start_shift = 0 + self.block_end_shift = 0 + + def extract(self, file_path): + """ + Extract classes and functions from a markdown document + """ + if not osp.isfile(file_path): + return None + + self.file_path = file_path + with open(file_path) as f: + self.lines = f.readlines() + self.content = "".join(self.lines) + + # Detect and extract all the classes and fucntions + classes = self.extract_class_blocks() + funcs = self.extract_function_blocks(classes=classes) + + self.post_process(classes, funcs) + + return { + "classes": classes, + "funcs": funcs, + } + + def extract_function_blocks(self, classes=None, class_label="", indentation=0): + """ + Extract all the functions with given indentation + """ + + funcs = {} + func_pattern = re.compile(self.func_pattern) + + for line_num in range(len(self.lines)): + # Search the function header + func_match = func_pattern.match(self.lines[line_num]) + if func_match is None: + continue + header_line = line_num + + func_label = func_match.group(self.func_pattern_keys.index("label")) + func_cls_label = func_match.group(self.func_pattern_keys.index("class")) + func_return = func_match.group(self.func_pattern_keys.index("return")) + + if classes: + # The function should not blong to any class + flag = False + for label in classes: + # Match the target class label + class_label_pattern = re.compile(f".*\*{label}\).*") + func_return_pattern = re.compile(f".*\*{label}.*") + constructor_pattern = re.compile(f".*new.*") + + class_label_match = class_label_pattern.match(f"{func_cls_label}") + func_return_match = func_return_pattern.match(f"{func_return}") + constructor_match = constructor_pattern.match(func_label) + + if class_label_match is not None or \ + func_return_match is not None and constructor_match is not None: + flag = True + if flag: + continue + + elif class_label: + # Match the target class label + class_label_pattern = re.compile(f".*\*{class_label}\).*") + func_return_pattern = re.compile(f".*\*{class_label}.*") + constructor_pattern = re.compile(f".*new.*") + + class_label_match = class_label_pattern.match(f"{func_cls_label}") + func_return_match = func_return_pattern.match(f"{func_return}") + constructor_match = constructor_pattern.match(func_label) + + if class_label_match is None and func_return_match is None: + continue + if func_return_match is not None and constructor_match is None: + continue + + # Search the block from the header line + start_line, end_line, func_block = self.search_block( + header_line, indentation) + # Construct the funcs dict + funcs[func_label] = { + "indentation": indentation, + "line_number": { + "start": start_line, + "end": end_line, + "header": header_line, + }, + "block": func_block, + } + + return funcs + + def extract_class_blocks(self): + """ + Extract all the classes with given indentation + """ + classes = {} + class_pattern = re.compile(self.class_pattern) + + for line_num, line in enumerate(self.lines): + # Search the class header + class_match = class_pattern.match(line) + if class_match is None: + continue + header_line = line_num + + # Search the block from the header line + _, _, class_block = self.search_block( + header_line, 0) + # Construct the classes dict + class_label = class_match.group(self.class_pattern_keys.index("label")) + funcs = self.extract_function_blocks(class_label=class_label) + # Merge function blocks to class_block + for func in funcs.values(): + class_block.append('\n') + class_block += func["block"] + + classes[class_label] = { + "indentation": 0, + "line_number": { + "header": header_line, + }, + "block": class_block, + "funcs": funcs, + } + + return classes + + def post_process(self, classes, funcs): + """ + Process the classes and functions + """ + def replace_tabs(x): + for i, line in enumerate(x["block"]): + x["block"][i] = line.replace("\t"," " * self.ind) + + def add_inds(x): + for i, line in enumerate(x["block"]): + if line != "\n": + x["block"][i] = " " * self.ind + line + + for clas in classes.values(): + replace_tabs(clas) + for func in clas["funcs"].values(): + replace_tabs(func) + add_inds(func) + for func in funcs.values(): + replace_tabs(func) + +for code_path in glob.glob("codes/go/chapter_*/array_hash_map.go"): + ext = ExtractCodeBlocksGo() + res = ext.extract(code_path) + pass diff --git a/docs/utils/extract_code_java.py b/docs/utils/extract_code_java.py index d86a27d1..41b09b6a 100644 --- a/docs/utils/extract_code_java.py +++ b/docs/utils/extract_code_java.py @@ -119,7 +119,6 @@ class ExtractCodeBlocksJava: Extract all the classes with given indentation """ classes = {} - class_pattern = re.compile(self.class_pattern) for line_num, line in enumerate(self.lines):