Add build script for Go and update Go codes.
This commit is contained in:
parent
12c085a088
commit
e8c78f89f0
@ -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)
|
||||
}
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
@ -17,6 +17,7 @@ type arrayHashMap struct {
|
||||
bucket []*entry
|
||||
}
|
||||
|
||||
/* 初始化哈希表 */
|
||||
func newArrayHashMap() *arrayHashMap {
|
||||
// 初始化一个长度为 100 的桶(数组)
|
||||
bucket := make([]*entry, 100)
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -4,6 +4,7 @@
|
||||
|
||||
package chapter_sorting
|
||||
|
||||
/* 插入排序 */
|
||||
func insertionSort(nums []int) {
|
||||
// 外循环:待排序元素数量为 n-1, n-2, ..., 1
|
||||
for i := 1; i < len(nums); i++ {
|
||||
|
@ -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 {
|
||||
|
@ -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 {
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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 {
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -11,7 +11,7 @@ import (
|
||||
)
|
||||
|
||||
/* 层序遍历 */
|
||||
func levelOrder(root *TreeNode) []int {
|
||||
func hierOrder(root *TreeNode) []int {
|
||||
// 初始化队列,加入根结点
|
||||
queue := list.New()
|
||||
queue.PushBack(root)
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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"
|
||||
|
@ -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"
|
||||
|
@ -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"
|
||||
|
@ -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"
|
||||
|
@ -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"
|
||||
|
@ -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"
|
||||
|
@ -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"
|
||||
|
@ -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"
|
||||
|
@ -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"
|
||||
|
@ -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"
|
||||
|
@ -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"
|
||||
|
@ -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"
|
||||
|
@ -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"
|
||||
|
@ -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"
|
||||
|
@ -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"
|
||||
|
@ -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"
|
||||
|
@ -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"
|
||||
|
@ -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"
|
||||
|
@ -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"
|
||||
|
@ -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(),
|
||||
|
@ -24,4 +24,4 @@ cd site
|
||||
git add .
|
||||
git commit -m "deploy"
|
||||
git push -u origin gh-pages
|
||||
cd..
|
||||
cd ..
|
||||
|
183
docs/utils/extract_code_go.py
Normal file
183
docs/utils/extract_code_go.py
Normal file
@ -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
|
@ -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):
|
||||
|
Loading…
x
Reference in New Issue
Block a user