diff --git a/.gitignore b/.gitignore index aef8d7436..71851d074 100644 --- a/.gitignore +++ b/.gitignore @@ -7,9 +7,6 @@ hello-algo.iml # mkdocs files -site/ .cache/ scripts/ docs/overrides/ - -src/ diff --git a/codes/python/chapter_hashing/array_hash_map.py b/codes/python/chapter_hashing/array_hash_map.py index ce8889924..e42c52bbc 100644 --- a/codes/python/chapter_hashing/array_hash_map.py +++ b/codes/python/chapter_hashing/array_hash_map.py @@ -6,7 +6,7 @@ Author: msk397 (machangxinq@gmail.com) """ 键值对 int->String """ class Entry: - def __init__(self, key: int, val: str): + def __init__(self, key, val): self.key = key self.val = val diff --git a/codes/python/chapter_tree/binary_search_tree.py b/codes/python/chapter_tree/binary_search_tree.py index c3058c93f..3a8dcf269 100644 --- a/codes/python/chapter_tree/binary_search_tree.py +++ b/codes/python/chapter_tree/binary_search_tree.py @@ -54,11 +54,9 @@ class BinarySearchTree: # 若树为空,直接提前返回 if root is None: return None - - cur = root - pre = None - + # 循环查找,越过叶结点后跳出 + cur, pre = root, None while cur is not None: # 找到重复结点,直接返回 if cur.val == num: @@ -86,10 +84,8 @@ class BinarySearchTree: if root is None: return None - cur = root - pre = None - # 循环查找,越过叶结点后跳出 + cur, pre = root, None while cur is not None: # 找到待删除结点,跳出循环 if cur.val == num: @@ -99,7 +95,6 @@ class BinarySearchTree: cur = cur.right else: # 待删除结点在 cur 的左子树中 cur = cur.left - # 若无待删除结点,则直接返回 if cur is None: return None diff --git a/deploy.sh b/deploy.sh deleted file mode 100644 index fb4e574fd..000000000 --- a/deploy.sh +++ /dev/null @@ -1,8 +0,0 @@ -rm -rf ./site -mkdocs build --clean -cd site -git init -git add -A -git commit -m "deploy" -git push -f git@github.com:krahets/hello-algo.git main:gh-pages -cd - diff --git a/docs/chapter_array_and_linkedlist/array.md b/docs/chapter_array_and_linkedlist/array.md old mode 100644 new mode 100755 index fa4418ee8..f60c64628 --- a/docs/chapter_array_and_linkedlist/array.md +++ b/docs/chapter_array_and_linkedlist/array.md @@ -143,13 +143,7 @@ elementAddr = firtstElementAddr + elementLength * elementIndex === "Python" ```python title="array.py" - """ 随机访问元素 """ - def random_access(nums): - # 在区间 [0, len(nums)-1] 中随机抽取一个数字 - random_index = random.randint(0, len(nums) - 1) - # 获取并返回随机元素 - random_num = nums[random_index] - return random_num + [class]{}-[func]{random_access} ``` === "Go" @@ -279,17 +273,7 @@ elementAddr = firtstElementAddr + elementLength * elementIndex === "Python" ```python title="array.py" - """ 扩展数组长度 """ - # 请注意,Python 的 list 是动态数组,可以直接扩展 - # 为了方便学习,本函数将 list 看作是长度不可变的数组 - def extend(nums, enlarge): - # 初始化一个扩展长度后的数组 - res = [0] * (len(nums) + enlarge) - # 将原数组中的所有元素复制到新数组 - for i in range(len(nums)): - res[i] = nums[i] - # 返回扩展后的新数组 - return res + [class]{}-[func]{extend} ``` === "Go" @@ -452,19 +436,9 @@ elementAddr = firtstElementAddr + elementLength * elementIndex === "Python" ```python title="array.py" - """ 在数组的索引 index 处插入元素 num """ - def insert(nums, num, index): - # 把索引 index 以及之后的所有元素向后移动一位 - for i in range(len(nums) - 1, index, -1): - nums[i] = nums[i - 1] - # 将 num 赋给 index 处元素 - nums[index] = num + [class]{}-[func]{insert} - """ 删除索引 index 处元素 """ - def remove(nums, index): - # 把索引 index 之后的所有元素向前移动一位 - for i in range(index, len(nums) - 1): - nums[i] = nums[i + 1] + [class]{}-[func]{remove} ``` === "Go" @@ -648,15 +622,7 @@ elementAddr = firtstElementAddr + elementLength * elementIndex === "Python" ```python title="array.py" - """ 遍历数组 """ - def traverse(nums): - count = 0 - # 通过索引遍历数组 - for i in range(len(nums)): - count += 1 - # 直接遍历数组 - for num in nums: - count += 1 + [class]{}-[func]{traverse} ``` === "Go" @@ -803,12 +769,7 @@ elementAddr = firtstElementAddr + elementLength * elementIndex === "Python" ```python title="array.py" - """ 在数组中查找指定元素 """ - def find(nums, target): - for i in range(len(nums)): - if nums[i] == target: - return i - return -1 + [class]{}-[func]{find} ``` === "Go" diff --git a/docs/chapter_array_and_linkedlist/linked_list.md b/docs/chapter_array_and_linkedlist/linked_list.md old mode 100644 new mode 100755 index 0e17954a5..71d91d73e --- a/docs/chapter_array_and_linkedlist/linked_list.md +++ b/docs/chapter_array_and_linkedlist/linked_list.md @@ -369,20 +369,9 @@ comments: true === "Python" ```python title="linked_list.py" - """ 在链表的结点 n0 之后插入结点 P """ - def insert(n0, P): - n1 = n0.next - n0.next = P - P.next = n1 + [class]{}-[func]{insert} - """ 删除链表的结点 n0 之后的首个结点 """ - def remove(n0): - if not n0.next: - return - # n0 -> P -> n1 - P = n0.next - n1 = P.next - n0.next = n1 + [class]{}-[func]{remove} ``` === "Go" @@ -557,13 +546,7 @@ comments: true === "Python" ```python title="linked_list.py" - """ 访问链表中索引为 index 的结点 """ - def access(head, index): - for _ in range(index): - if not head: - return None - head = head.next - return head + [class]{}-[func]{access} ``` === "Go" @@ -704,15 +687,7 @@ comments: true === "Python" ```python title="linked_list.py" - """ 在链表中查找值为 target 的首个结点 """ - def find(head, target): - index = 0 - while head: - if head.val == target: - return index - head = head.next - index += 1 - return -1 + [class]{}-[func]{find} ``` === "Go" diff --git a/docs/chapter_array_and_linkedlist/list.md b/docs/chapter_array_and_linkedlist/list.md old mode 100644 new mode 100755 index b6b413aca..f1c470499 --- a/docs/chapter_array_and_linkedlist/list.md +++ b/docs/chapter_array_and_linkedlist/list.md @@ -912,68 +912,7 @@ comments: true === "Python" ```python title="my_list.py" - """ 列表类简易实现 """ - class MyList: - """ 构造函数 """ - def __init__(self): - self.__capacity = 10 # 列表容量 - self.__nums = [0] * self.__capacity # 数组(存储列表元素) - self.__size = 0 # 列表长度(即当前元素数量) - self.__extend_ratio = 2 # 每次列表扩容的倍数 - - """ 获取列表长度(即当前元素数量) """ - def size(self): - return self.__size - - """ 获取列表容量 """ - def capacity(self): - return self.__capacity - - """ 访问元素 """ - def get(self, index): - # 索引如果越界则抛出异常,下同 - assert index >= 0 and index < self.__size, "索引越界" - return self.__nums[index] - - """ 更新元素 """ - def set(self, num, index): - assert index >= 0 and index < self.__size, "索引越界" - self.__nums[index] = num - - """ 中间插入(尾部添加)元素 """ - def add(self, num, index=-1): - assert index >= 0 and index < self.__size, "索引越界" - # 若不指定索引 index ,则向数组尾部添加元素 - if index == -1: - index = self.__size - # 元素数量超出容量时,触发扩容机制 - if self.__size == self.capacity(): - self.extend_capacity() - # 索引 i 以及之后的元素都向后移动一位 - for j in range(self.__size - 1, index - 1, -1): - self.__nums[j + 1] = self.__nums[j] - self.__nums[index] = num - # 更新元素数量 - self.__size += 1 - - """ 删除元素 """ - def remove(self, index): - assert index >= 0 and index < self.__size, "索引越界" - num = self.nums[index] - # 索引 i 之后的元素都向前移动一位 - for j in range(index, self.__size - 1): - self.__nums[j] = self.__nums[j + 1] - # 更新元素数量 - self.__size -= 1 - # 返回被删除元素 - return num - - """ 列表扩容 """ - def extend_capacity(self): - # 新建一个长度为 self.__size 的数组,并将原数组拷贝到新数组 - self.__nums = self.__nums + [0] * self.capacity() * (self.__extend_ratio - 1) - # 更新列表容量 - self.__capacity = len(self.__nums) + [class]{MyList}-[func]{} ``` === "Go" diff --git a/docs/chapter_computational_complexity/space_complexity.md b/docs/chapter_computational_complexity/space_complexity.md old mode 100644 new mode 100755 index 61a217f6e..8033d2a1e --- a/docs/chapter_computational_complexity/space_complexity.md +++ b/docs/chapter_computational_complexity/space_complexity.md @@ -624,18 +624,7 @@ $$ === "Python" ```python title="space_complexity.py" - """ 常数阶 """ - def constant(n): - # 常量、变量、对象占用 O(1) 空间 - a = 0 - nums = [0] * 10000 - node = ListNode(0) - # 循环中的变量占用 O(1) 空间 - for _ in range(n): - c = 0 - # 循环中的函数占用 O(1) 空间 - for _ in range(n): - function() + [class]{}-[func]{constant} ``` === "Go" @@ -829,14 +818,7 @@ $$ === "Python" ```python title="space_complexity.py" - """ 线性阶 """ - def linear(n): - # 长度为 n 的列表占用 O(n) 空间 - nums = [0] * n - # 长度为 n 的哈希表占用 O(n) 空间 - mapp = {} - for i in range(n): - mapp[i] = str(i) + [class]{}-[func]{linear} ``` === "Go" @@ -996,11 +978,7 @@ $$ === "Python" ```python title="space_complexity.py" - """ 线性阶(递归实现) """ - def linear_recur(n): - print("递归 n =", n) - if n == 1: return - linear_recur(n - 1) + [class]{}-[func]{linear_recur} ``` === "Go" @@ -1127,10 +1105,7 @@ $$ === "Python" ```python title="space_complexity.py" - """ 平方阶 """ - def quadratic(n): - # 二维列表占用 O(n^2) 空间 - num_matrix = [[0] * n for _ in range(n)] + [class]{}-[func]{quadratic} ``` === "Go" @@ -1272,12 +1247,7 @@ $$ === "Python" ```python title="space_complexity.py" - """ 平方阶(递归实现) """ - def quadratic_recur(n): - if n <= 0: return 0 - # 数组 nums 长度为 n, n-1, ..., 2, 1 - nums = [0] * n - return quadratic_recur(n - 1) + [class]{}-[func]{quadratic_recur} ``` === "Go" @@ -1400,13 +1370,7 @@ $$ === "Python" ```python title="space_complexity.py" - """ 指数阶(建立满二叉树) """ - def build_tree(n): - if n == 0: return None - root = TreeNode(0) - root.left = build_tree(n - 1) - root.right = build_tree(n - 1) - return root + [class]{}-[func]{build_tree} ``` === "Go" diff --git a/docs/chapter_computational_complexity/space_time_tradeoff.md b/docs/chapter_computational_complexity/space_time_tradeoff.md old mode 100644 new mode 100755 index 84dc1afc7..8b8ee2be6 --- a/docs/chapter_computational_complexity/space_time_tradeoff.md +++ b/docs/chapter_computational_complexity/space_time_tradeoff.md @@ -70,14 +70,7 @@ comments: true === "Python" ```python title="leetcode_two_sum.py" - class SolutionBruteForce: - def twoSum(self, nums: List[int], target: int) -> List[int]: - # 两层循环,时间复杂度 O(n^2) - for i in range(len(nums) - 1): - for j in range(i + 1, len(nums)): - if nums[i] + nums[j] == target: - return i, j - return [] + [class]{SolutionBruteForce}-[func]{} ``` === "Go" @@ -247,16 +240,7 @@ comments: true === "Python" ```python title="leetcode_two_sum.py" - class SolutionHashMap: - def twoSum(self, nums: List[int], target: int) -> List[int]: - # 辅助哈希表,空间复杂度 O(n) - dic = {} - # 单层循环,时间复杂度 O(n) - for i in range(len(nums)): - if target - nums[i] in dic: - return dic[target - nums[i]], i - dic[nums[i]] = i - return [] + [class]{SolutionHashMap}-[func]{} ``` === "Go" diff --git a/docs/chapter_computational_complexity/time_complexity.md b/docs/chapter_computational_complexity/time_complexity.md old mode 100644 new mode 100755 index dd8df29b2..4a64327d1 --- a/docs/chapter_computational_complexity/time_complexity.md +++ b/docs/chapter_computational_complexity/time_complexity.md @@ -821,13 +821,7 @@ $$ === "Python" ```python title="time_complexity.py" - """ 常数阶 """ - def constant(n): - count = 0 - size = 100000 - for _ in range(size): - count += 1 - return count + [class]{}-[func]{constant} ``` === "Go" @@ -958,12 +952,7 @@ $$ === "Python" ```python title="time_complexity.py" - """ 线性阶 """ - def linear(n): - count = 0 - for _ in range(n): - count += 1 - return count + [class]{}-[func]{linear} ``` === "Go" @@ -1091,13 +1080,7 @@ $$ === "Python" ```python title="time_complexity.py" - """ 线性阶(遍历数组)""" - def array_traversal(nums): - count = 0 - # 循环次数与数组长度成正比 - for num in nums: - count += 1 - return count + [class]{}-[func]{array_traversal} ``` === "Go" @@ -1239,14 +1222,7 @@ $$ === "Python" ```python title="time_complexity.py" - """ 平方阶 """ - def quadratic(n): - count = 0 - # 循环次数与数组长度成平方关系 - for i in range(n): - for j in range(n): - count += 1 - return count + [class]{}-[func]{quadratic} ``` === "Go" @@ -1425,20 +1401,7 @@ $$ === "Python" ```python title="time_complexity.py" - """ 平方阶(冒泡排序)""" - def bubble_sort(nums): - count = 0 # 计数器 - # 外循环:待排序元素数量为 n-1, n-2, ..., 1 - for i in range(len(nums) - 1, 0, -1): - # 内循环:冒泡操作 - for j in range(i): - 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]{bubble_sort} ``` === "Go" @@ -1658,16 +1621,7 @@ $$ === "Python" ```python title="time_complexity.py" - """ 指数阶(循环实现)""" - def exponential(n): - count, base = 0, 1 - # cell 每轮一分为二,形成数列 1, 2, 4, 8, ..., 2^(n-1) - for _ in range(n): - for _ in range(base): - count += 1 - base *= 2 - # count = 1 + 2 + 4 + 8 + .. + 2^(n-1) = 2^n - 1 - return count + [class]{}-[func]{exponential} ``` === "Go" @@ -1836,10 +1790,7 @@ $$ === "Python" ```python title="time_complexity.py" - """ 指数阶(递归实现)""" - def exp_recur(n): - if n == 1: return 1 - return exp_recur(n - 1) + exp_recur(n - 1) + 1 + [class]{}-[func]{exp_recur} ``` === "Go" @@ -1957,13 +1908,7 @@ $$ === "Python" ```python title="time_complexity.py" - """ 对数阶(循环实现)""" - def logarithmic(n): - count = 0 - while n > 1: - n = n / 2 - count += 1 - return count + [class]{}-[func]{logarithmic} ``` === "Go" @@ -2099,10 +2044,7 @@ $$ === "Python" ```python title="time_complexity.py" - """ 对数阶(递归实现)""" - def log_recur(n): - if n <= 1: return 0 - return log_recur(n / 2) + 1 + [class]{}-[func]{log_recur} ``` === "Go" @@ -2220,14 +2162,7 @@ $$ === "Python" ```python title="time_complexity.py" - """ 线性对数阶 """ - def linear_log_recur(n): - if n <= 1: return 1 - count = linear_log_recur(n // 2) + \ - linear_log_recur(n // 2) - for _ in range(n): - count += 1 - return count + [class]{}-[func]{linear_log_recur} ``` === "Go" @@ -2387,14 +2322,7 @@ $$ === "Python" ```python title="time_complexity.py" - """ 阶乘阶(递归实现)""" - def factorial_recur(n): - if n == 0: return 1 - count = 0 - # 从 1 个分裂出 n 个 - for _ in range(n): - count += factorial_recur(n - 1) - return count + [class]{}-[func]{factorial_recur} ``` === "Go" @@ -2587,22 +2515,9 @@ $$ === "Python" ```python title="worst_best_time_complexity.py" - """ 生成一个数组,元素为: 1, 2, ..., n ,顺序被打乱 """ - def random_numbers(n): - # 生成数组 nums =: 1, 2, 3, ..., n - nums = [i for i in range(1, n + 1)] - # 随机打乱数组元素 - random.shuffle(nums) - return nums + [class]{}-[func]{random_numbers} - """ 查找数组 nums 中数字 1 所在索引 """ - def find_one(nums): - for i in range(len(nums)): - # 当元素 1 在数组头部时,达到最佳时间复杂度 O(1) - # 当元素 1 在数组尾部时,达到最差时间复杂度 O(n) - if nums[i] == 1: - return i - return -1 + [class]{}-[func]{find_one} ``` === "Go" diff --git a/docs/chapter_hashing/hash_map.md b/docs/chapter_hashing/hash_map.md old mode 100644 new mode 100755 index d1cd1a1c1..8708fb38a --- a/docs/chapter_hashing/hash_map.md +++ b/docs/chapter_hashing/hash_map.md @@ -523,42 +523,9 @@ $$ === "Python" ```python title="array_hash_map.py" - """ 键值对 int->String """ - class Entry: - def __init__(self, key, val): - self.key = key - self.val = val + [class]{Entry}-[func]{} - """ 基于数组简易实现的哈希表 """ - class ArrayHashMap: - def __init__(self): - # 初始化一个长度为 100 的桶(数组) - self.bucket = [None] * 100 - - """ 哈希函数 """ - def hash_func(self, key): - index = key % 100 - return index - - """ 查询操作 """ - def get(self, key): - index = self.hash_func(key) - pair = self.bucket[index] - if pair is None: - return None - return pair.val - - """ 添加操作 """ - def put(self, key, val): - pair = Entry(key, val) - index = self.hash_func(key) - self.bucket[index] = pair - - """ 删除操作 """ - def remove(self, key): - index = self.hash_func(key) - # 置为 None ,代表删除 - self.bucket[index] = None + [class]{ArrayHashMap}-[func]{} ``` === "Go" diff --git a/docs/chapter_searching/binary_search.md b/docs/chapter_searching/binary_search.md old mode 100644 new mode 100755 index 9ac254cec..531d48a28 --- a/docs/chapter_searching/binary_search.md +++ b/docs/chapter_searching/binary_search.md @@ -98,19 +98,7 @@ $$ === "Python" ```python title="binary_search.py" - """ 二分查找(双闭区间) """ - def binary_search(nums, target): - # 初始化双闭区间 [0, n-1] ,即 i, j 分别指向数组首元素、尾元素 - i, j = 0, len(nums) - 1 - while i <= j: - m = (i + j) // 2 # 计算中点索引 m - if nums[m] < target: # 此情况说明 target 在区间 [m+1, j] 中 - i = m + 1 - elif nums[m] > target: # 此情况说明 target 在区间 [i, m-1] 中 - j = m - 1 - else: - return m # 找到目标元素,返回其索引 - return -1 # 未找到目标元素,返回 -1 + [class]{}-[func]{binary_search} ``` === "Go" @@ -291,20 +279,7 @@ $$ === "Python" ```python title="binary_search.py" - """ 二分查找(左闭右开) """ - def binary_search1(nums, target): - # 初始化左闭右开 [0, n) ,即 i, j 分别指向数组首元素、尾元素+1 - i, j = 0, len(nums) - # 循环,当搜索区间为空时跳出(当 i = j 时为空) - while i < j: - m = (i + j) // 2 # 计算中点索引 m - if nums[m] < target: # 此情况说明 target 在区间 [m+1, j) 中 - i = m + 1 - elif nums[m] > target: # 此情况说明 target 在区间 [i, m) 中 - j = m - else: # 找到目标元素,返回其索引 - return m - return -1 # 未找到目标元素,返回 -1 + [class]{}-[func]{binary_search1} ``` === "Go" diff --git a/docs/chapter_searching/hashing_search.md b/docs/chapter_searching/hashing_search.md old mode 100644 new mode 100755 index 157e67a2e..043106ef0 --- a/docs/chapter_searching/hashing_search.md +++ b/docs/chapter_searching/hashing_search.md @@ -43,11 +43,7 @@ comments: true === "Python" ```python title="hashing_search.py" - """ 哈希查找(数组) """ - def hashing_search_array(mapp, target): - # 哈希表的 key: 目标元素,value: 索引 - # 若哈希表中无此 key ,返回 -1 - return mapp.get(target, -1) + [class]{}-[func]{hashing_search_array} ``` === "Go" @@ -153,11 +149,7 @@ comments: true === "Python" ```python title="hashing_search.py" - """ 哈希查找(链表) """ - def hashing_search_linkedlist(mapp, target): - # 哈希表的 key: 目标元素,value: 结点对象 - # 若哈希表中无此 key ,返回 -1 - return mapp.get(target, -1) + [class]{}-[func]{hashing_search_linkedlist} ``` === "Go" diff --git a/docs/chapter_searching/linear_search.md b/docs/chapter_searching/linear_search.md old mode 100644 new mode 100755 index 5a8bb05fa..1a6e62722 --- a/docs/chapter_searching/linear_search.md +++ b/docs/chapter_searching/linear_search.md @@ -47,13 +47,7 @@ comments: true === "Python" ```python title="linear_search.py" - """ 线性查找(数组) """ - def linear_search_array(nums, target): - # 遍历数组 - for i in range(len(nums)): - if nums[i] == target: # 找到目标元素,返回其索引 - return i - return -1 # 未找到目标元素,返回 -1 + [class]{}-[func]{linear_search_array} ``` === "Go" @@ -195,14 +189,7 @@ comments: true === "Python" ```python title="linear_search.py" - """ 线性查找(链表) """ - def linear_search_linkedlist(head, target): - # 遍历链表 - while head: - if head.val == target: # 找到目标结点,返回之 - return head - head = head.next - return None # 未找到目标结点,返回 None + [class]{}-[func]{linear_search_linkedlist} ``` === "Go" diff --git a/docs/chapter_sorting/bubble_sort.md b/docs/chapter_sorting/bubble_sort.md old mode 100644 new mode 100755 index c9063d754..0337ac432 --- a/docs/chapter_sorting/bubble_sort.md +++ b/docs/chapter_sorting/bubble_sort.md @@ -15,31 +15,24 @@ comments: true 完成此次冒泡操作后,**数组最大元素已在正确位置,接下来只需排序剩余 $n - 1$ 个元素**。 === "Step 1" - ![bubble_operation_step1](bubble_sort.assets/bubble_operation_step1.png) === "Step 2" - ![bubble_operation_step2](bubble_sort.assets/bubble_operation_step2.png) === "Step 3" - ![bubble_operation_step3](bubble_sort.assets/bubble_operation_step3.png) === "Step 4" - ![bubble_operation_step4](bubble_sort.assets/bubble_operation_step4.png) === "Step 5" - ![bubble_operation_step5](bubble_sort.assets/bubble_operation_step5.png) === "Step 6" - ![bubble_operation_step6](bubble_sort.assets/bubble_operation_step6.png) === "Step 7" - ![bubble_operation_step7](bubble_sort.assets/bubble_operation_step7.png)

Fig. 冒泡操作

@@ -96,16 +89,7 @@ comments: true === "Python" ```python title="bubble_sort.py" - """ 冒泡排序 """ - def bubble_sort(nums): - n = len(nums) - # 外循环:待排序元素数量为 n-1, n-2, ..., 1 - for i in range(n - 1, 0, -1): - # 内循环:冒泡操作 - for j in range(i): - if nums[j] > nums[j + 1]: - # 交换 nums[j] 与 nums[j + 1] - nums[j], nums[j + 1] = nums[j + 1], nums[j] + [class]{}-[func]{bubble_sort} ``` === "Go" @@ -304,20 +288,7 @@ comments: true === "Python" ```python title="bubble_sort.py" - """ 冒泡排序(标志优化) """ - def bubble_sort_with_flag(nums): - n = len(nums) - # 外循环:待排序元素数量为 n-1, n-2, ..., 1 - for i in range(n - 1, 0, -1): - flag = False # 初始化标志位 - # 内循环:冒泡操作 - for j in range(i): - if nums[j] > nums[j + 1]: - # 交换 nums[j] 与 nums[j + 1] - nums[j], nums[j + 1] = nums[j + 1], nums[j] - flag = True # 记录交换元素 - if not flag: - break # 此轮冒泡未交换任何元素,直接跳出 + [class]{}-[func]{bubble_sort_with_flag} ``` === "Go" diff --git a/docs/chapter_sorting/insertion_sort.md b/docs/chapter_sorting/insertion_sort.md old mode 100644 new mode 100755 index 0c3cee929..130d2c7cf --- a/docs/chapter_sorting/insertion_sort.md +++ b/docs/chapter_sorting/insertion_sort.md @@ -63,17 +63,7 @@ comments: true === "Python" ```python title="insertion_sort.py" - """ 插入排序 """ - def insertion_sort(nums): - # 外循环:base = nums[1], nums[2], ..., nums[n-1] - for i in range(1, len(nums)): - base = nums[i] - j = i - 1 - # 内循环:将 base 插入到左边的正确位置 - while j >= 0 and nums[j] > base: - nums[j + 1] = nums[j] # 1. 将 nums[j] 向右移动一位 - j -= 1 - nums[j + 1] = base # 2. 将 base 赋值到正确位置 + [class]{}-[func]{insertion_sort} ``` === "Go" diff --git a/docs/chapter_sorting/merge_sort.md b/docs/chapter_sorting/merge_sort.md old mode 100644 new mode 100755 index 969bd65ca..7e11a6b22 --- a/docs/chapter_sorting/merge_sort.md +++ b/docs/chapter_sorting/merge_sort.md @@ -150,46 +150,9 @@ comments: true === "Python" ```python title="merge_sort.py" - """ - 合并左子数组和右子数组 - 左子数组区间 [left, mid] - 右子数组区间 [mid + 1, right] - """ - def merge(nums, left, mid, right): - # 初始化辅助数组 借助 copy模块 - tmp = nums[left:right + 1] - # 左子数组的起始索引和结束索引 - left_start, left_end = left - left, mid - left - # 右子数组的起始索引和结束索引 - right_start, right_end = mid + 1 - left, right - left - # i, j 分别指向左子数组、右子数组的首元素 - i, j = left_start, right_start - # 通过覆盖原数组 nums 来合并左子数组和右子数组 - for k in range(left, right + 1): - # 若“左子数组已全部合并完”,则选取右子数组元素,并且 j++ - if i > left_end: - nums[k] = tmp[j] - j += 1 - # 否则,若“右子数组已全部合并完”或“左子数组元素 <= 右子数组元素”,则选取左子数组元素,并且 i++ - elif j > right_end or tmp[i] <= tmp[j]: - nums[k] = tmp[i] - i += 1 - # 否则,若“左右子数组都未全部合并完”且“左子数组元素 > 右子数组元素”,则选取右子数组元素,并且 j++ - else: - nums[k] = tmp[j] - j += 1 + [class]{}-[func]{merge} - """ 归并排序 """ - def merge_sort(nums, left, right): - # 终止条件 - if left >= right: - return # 当子数组长度为 1 时终止递归 - # 划分阶段 - mid = (left + right) // 2 # 计算中点 - merge_sort(nums, left, mid) # 递归左子数组 - merge_sort(nums, mid + 1, right) # 递归右子数组 - # 合并阶段 - merge(nums, left, mid, right) + [class]{}-[func]{merge_sort} ``` === "Go" diff --git a/docs/chapter_sorting/quick_sort.md b/docs/chapter_sorting/quick_sort.md old mode 100644 new mode 100755 index 63a876271..e8a97384e --- a/docs/chapter_sorting/quick_sort.md +++ b/docs/chapter_sorting/quick_sort.md @@ -98,20 +98,7 @@ comments: true === "Python" ```python title="quick_sort.py" - """ 哨兵划分 """ - def partition(self, nums, left, right): - # 以 nums[left] 作为基准数 - i, j = left, right - while i < j: - while i < j and nums[j] >= nums[left]: - j -= 1 # 从右向左找首个小于基准数的元素 - while i < j and nums[i] <= nums[left]: - i += 1 # 从左向右找首个大于基准数的元素 - # 元素交换 - nums[i], nums[j] = nums[j], nums[i] - # 将基准数交换至两子数组的分界线 - nums[i], nums[left] = nums[left], nums[i] - return i # 返回基准数的索引 + [class]{QuickSort}-[func]{partition} ``` === "Go" @@ -316,16 +303,7 @@ comments: true === "Python" ```python title="quick_sort.py" - """ 快速排序 """ - def quick_sort(self, nums, left, right): - # 子数组长度为 1 时终止递归 - if left >= right: - return - # 哨兵划分 - pivot = self.partition(nums, left, right) - # 递归左子数组、右子数组 - self.quick_sort(nums, left, pivot - 1) - self.quick_sort(nums, pivot + 1, right) + [class]{QuickSort}-[func]{quick_sort} ``` === "Go" @@ -509,24 +487,9 @@ comments: true === "Python" ```python title="quick_sort.py" - """ 选取三个元素的中位数 """ - def median_three(self, nums, left, mid, right): - # 使用了异或操作来简化代码 - # 异或规则为 0 ^ 0 = 1 ^ 1 = 0, 0 ^ 1 = 1 ^ 0 = 1 - if (nums[left] < nums[mid]) ^ (nums[left] < nums[right]): - return left - elif (nums[mid] < nums[left]) ^ (nums[mid] > nums[right]): - return mid - return right + [class]{QuickSortMedian}-[func]{median_three} - """ 哨兵划分(三数取中值) """ - def partition(self, nums, left, right): - # 以 nums[left] 作为基准数 - med = self.median_three(nums, left, (left + right) // 2, right) - # 将中位数交换至数组最左端 - nums[left], nums[med] = nums[med], nums[left] - # 以 nums[left] 作为基准数 - # 下同省略... + [class]{QuickSortMedian}-[func]{partition} ``` === "Go" @@ -721,19 +684,7 @@ comments: true === "Python" ```python title="quick_sort.py" - """ 快速排序(尾递归优化) """ - def quick_sort(self, nums, left, right): - # 子数组长度为 1 时终止 - while left < right: - # 哨兵划分操作 - pivot = self.partition(nums, left, right) - # 对两个子数组中较短的那个执行快排 - if pivot - left < right - pivot: - self.quick_sort(nums, left, pivot - 1) # 递归排序左子数组 - left = pivot + 1 # 剩余待排序区间为 [pivot + 1, right] - else: - self.quick_sort(nums, pivot + 1, right) # 递归排序右子数组 - right = pivot - 1 # 剩余待排序区间为 [left, pivot - 1] + [class]{QuickSortTailCall}-[func]{quick_sort} ``` === "Go" diff --git a/docs/chapter_stack_and_queue/queue.md b/docs/chapter_stack_and_queue/queue.md old mode 100644 new mode 100755 index 6eb6121e2..ae4825e83 --- a/docs/chapter_stack_and_queue/queue.md +++ b/docs/chapter_stack_and_queue/queue.md @@ -398,49 +398,7 @@ comments: true === "Python" ```python title="linkedlist_queue.py" - """ 基于链表实现的队列 """ - class LinkedListQueue: - def __init__(self): - self.__front = None # 头结点 front - self.__rear = None # 尾结点 rear - self.__size = 0 - - """ 获取队列的长度 """ - def size(self): - return self.__size - - """ 判断队列是否为空 """ - def is_empty(self): - return not self.__front - - """ 入队 """ - def push(self, num): - # 尾结点后添加 num - node = ListNode(num) - # 如果队列为空,则令头、尾结点都指向该结点 - if self.__front is None: - self.__front = node - self.__rear = node - # 如果队列不为空,则将该结点添加到尾结点后 - else: - self.__rear.next = node - self.__rear = node - self.__size += 1 - - """ 出队 """ - def poll(self): - num = self.peek() - # 删除头结点 - self.__front = self.__front.next - self.__size -= 1 - return num - - """ 访问队首元素 """ - def peek(self): - if self.size() == 0: - print("队列为空") - return False - return self.__front.val + [class]{LinkedListQueue}-[func]{} ``` === "Go" @@ -881,47 +839,7 @@ comments: true === "Python" ```python title="array_queue.py" - """ 基于环形数组实现的队列 """ - class ArrayQueue: - def __init__(self, size): - self.__nums = [0] * size # 用于存储队列元素的数组 - self.__front = 0 # 队首指针,指向队首元素 - self.__size = 0 # 队列长度 - - """ 获取队列的容量 """ - def capacity(self): - return len(self.__nums) - - """ 获取队列的长度 """ - def size(self): - return self.__size - - """ 判断队列是否为空 """ - def is_empty(self): - return self.__size == 0 - - """ 入队 """ - def push(self, num): - assert self.__size < self.capacity(), "队列已满" - # 计算尾指针,指向队尾索引 + 1 - # 通过取余操作,实现 rear 越过数组尾部后回到头部 - rear = (self.__front + self.__size) % self.capacity() - # 尾结点后添加 num - self.__nums[rear] = num - self.__size += 1 - - """ 出队 """ - def poll(self): - num = self.peek() - # 队首指针向后移动一位,若越过尾部则返回到数组头部 - self.__front = (self.__front + 1) % self.capacity() - self.__size -= 1 - return num - - """ 访问队首元素 """ - def peek(self): - assert not self.is_empty(), "队列为空" - return self.__nums[self.__front] + [class]{ArrayQueue}-[func]{} ``` === "Go" diff --git a/docs/chapter_stack_and_queue/stack.md b/docs/chapter_stack_and_queue/stack.md old mode 100644 new mode 100755 index c97af130e..38408fcfc --- a/docs/chapter_stack_and_queue/stack.md +++ b/docs/chapter_stack_and_queue/stack.md @@ -378,39 +378,7 @@ comments: true === "Python" ```python title="linkedlist_stack.py" - """ 基于链表实现的栈 """ - class LinkedListStack: - def __init__(self): - self.__peek = None - self.__size = 0 - - """ 获取栈的长度 """ - def size(self): - return self.__size - - """ 判断栈是否为空 """ - def is_empty(self): - return not self.__peek - - """ 入栈 """ - def push(self, val): - node = ListNode(val) - node.next = self.__peek - self.__peek = node - self.__size += 1 - - """ 出栈 """ - def pop(self): - num = self.peek() - self.__peek = self.__peek.next - self.__size -= 1 - return num - - """ 访问栈顶元素 """ - def peek(self): - # 判空处理 - if not self.__peek: return None - return self.__peek.val + [class]{LinkedListStack}-[func]{} ``` === "Go" @@ -785,32 +753,7 @@ comments: true === "Python" ```python title="array_stack.py" - """ 基于数组实现的栈 """ - class ArrayStack: - def __init__(self): - self.__stack = [] - - """ 获取栈的长度 """ - def size(self): - return len(self.__stack) - - """ 判断栈是否为空 """ - def is_empty(self): - return self.__stack == [] - - """ 入栈 """ - def push(self, item): - self.__stack.append(item) - - """ 出栈 """ - def pop(self): - assert not self.is_empty(), "栈为空" - return self.__stack.pop() - - """ 访问栈顶元素 """ - def peek(self): - assert not self.is_empty(), "栈为空" - return self.__stack[-1] + [class]{ArrayStack}-[func]{} ``` === "Go" diff --git a/docs/chapter_tree/avl_tree.md b/docs/chapter_tree/avl_tree.md old mode 100644 new mode 100755 index b1b2adb52..39cc374a6 --- a/docs/chapter_tree/avl_tree.md +++ b/docs/chapter_tree/avl_tree.md @@ -179,17 +179,9 @@ G. M. Adelson-Velsky 和 E. M. Landis 在其 1962 年发表的论文 "An algorit === "Python" ```python title="avl_tree.py" - """ 获取结点高度 """ - def height(self, node: Optional[TreeNode]) -> int: - # 空结点高度为 -1 ,叶结点高度为 0 - if node is not None: - return node.height - return -1 + [class]{AVLTree}-[func]{height} - """ 更新结点高度 """ - def __update_height(self, node: Optional[TreeNode]): - # 结点高度等于最高子树高度 + 1 - node.height = max([self.height(node.left), self.height(node.right)]) + 1 + [class]{AVLTree}-[func]{__update_height} ``` === "Go" @@ -316,13 +308,7 @@ G. M. Adelson-Velsky 和 E. M. Landis 在其 1962 年发表的论文 "An algorit === "Python" ```python title="avl_tree.py" - """ 获取平衡因子 """ - def balance_factor(self, node: Optional[TreeNode]) -> int: - # 空结点平衡因子为 0 - if node is None: - return 0 - # 结点平衡因子 = 左子树高度 - 右子树高度 - return self.height(node.left) - self.height(node.right) + [class]{AVLTree}-[func]{balance_factor} ``` === "Go" @@ -467,18 +453,7 @@ AVL 树的独特之处在于「旋转 Rotation」的操作,其可 **在不影 === "Python" ```python title="avl_tree.py" - """ 右旋操作 """ - def __right_rotate(self, node: Optional[TreeNode]) -> TreeNode: - child = node.left - grand_child = child.right - # 以 child 为原点,将 node 向右旋转 - child.right = node - node.left = grand_child - # 更新结点高度 - self.__update_height(node) - self.__update_height(child) - # 返回旋转后子树的根节点 - return child + [class]{AVLTree}-[func]{__right_rotate} ``` === "Go" @@ -623,18 +598,7 @@ AVL 树的独特之处在于「旋转 Rotation」的操作,其可 **在不影 === "Python" ```python title="avl_tree.py" - """ 左旋操作 """ - def __left_rotate(self, node: Optional[TreeNode]) -> TreeNode: - child = node.right - grand_child = child.left - # 以 child 为原点,将 node 向左旋转 - child.left = node - node.right = grand_child - # 更新结点高度 - self.__update_height(node) - self.__update_height(child) - # 返回旋转后子树的根节点 - return child + [class]{AVLTree}-[func]{__left_rotate} ``` === "Go" @@ -835,30 +799,7 @@ AVL 树的独特之处在于「旋转 Rotation」的操作,其可 **在不影 === "Python" ```python title="avl_tree.py" - """ 执行旋转操作,使该子树重新恢复平衡 """ - def __rotate(self, node: Optional[TreeNode]) -> TreeNode: - # 获取结点 node 的平衡因子 - balance_factor = self.balance_factor(node) - # 左偏树 - if balance_factor > 1: - if self.balance_factor(node.left) >= 0: - # 右旋 - return self.__right_rotate(node) - else: - # 先左旋后右旋 - node.left = self.__left_rotate(node.left) - return self.__right_rotate(node) - # 右偏树 - elif balance_factor < -1: - if self.balance_factor(node.right) <= 0: - # 左旋 - return self.__left_rotate(node) - else: - # 先右旋后左旋 - node.right = self.__right_rotate(node.right) - return self.__left_rotate(node) - # 平衡树,无需旋转,直接返回 - return node + [class]{AVLTree}-[func]{__rotate} ``` === "Go" @@ -1088,27 +1029,9 @@ AVL 树的独特之处在于「旋转 Rotation」的操作,其可 **在不影 === "Python" ```python title="avl_tree.py" - """ 插入结点 """ - def insert(self, val) -> TreeNode: - self.root = self.__insert_helper(self.root, val) - return self.root + [class]{AVLTree}-[func]{insert} - """ 递归插入结点(辅助函数)""" - def __insert_helper(self, node: Optional[TreeNode], val: int) -> TreeNode: - if node is None: - return TreeNode(val) - # 1. 查找插入位置,并插入结点 - if val < node.val: - node.left = self.__insert_helper(node.left, val) - elif val > node.val: - node.right = self.__insert_helper(node.right, val) - else: - # 重复结点不插入,直接返回 - return node - # 更新结点高度 - self.__update_height(node) - # 2. 执行旋转操作,使该子树重新恢复平衡 - return self.__rotate(node) + [class]{AVLTree}-[func]{__insert_helper} ``` === "Go" @@ -1340,37 +1263,9 @@ AVL 树的独特之处在于「旋转 Rotation」的操作,其可 **在不影 === "Python" ```python title="avl_tree.py" - """ 删除结点 """ - def remove(self, val: int): - root = self.__remove_helper(self.root, val) - return root + [class]{AVLTree}-[func]{remove} - """ 递归删除结点(辅助函数) """ - def __remove_helper(self, node: Optional[TreeNode], val: int) -> Optional[TreeNode]: - if node is None: - return None - # 1. 查找结点,并删除之 - if val < node.val: - node.left = self.__remove_helper(node.left, val) - elif val > node.val: - node.right = self.__remove_helper(node.right, val) - else: - if node.left is None or node.right is None: - child = node.left or node.right - # 子结点数量 = 0 ,直接删除 node 并返回 - if child is None: - return None - # 子结点数量 = 1 ,直接删除 node - else: - node = child - else: # 子结点数量 = 2 ,则将中序遍历的下个结点删除,并用该结点替换当前结点 - temp = self.__get_inorder_next(node.right) - node.right = self.__remove_helper(node.right, temp.val) - node.val = temp.val - # 更新结点高度 - self.__update_height(node) - # 2. 执行旋转操作,使该子树重新恢复平衡 - return self.__rotate(node) + [class]{AVLTree}-[func]{__remove_helper} ``` === "Go" diff --git a/docs/chapter_tree/binary_search_tree.md b/docs/chapter_tree/binary_search_tree.md old mode 100644 new mode 100755 index b9f41bd7f..15e1052fb --- a/docs/chapter_tree/binary_search_tree.md +++ b/docs/chapter_tree/binary_search_tree.md @@ -78,21 +78,7 @@ comments: true === "Python" ```python title="binary_search_tree.py" - """ 查找结点 """ - def search(self, num: int) -> Optional[TreeNode]: - cur = self.root - # 循环查找,越过叶结点后跳出 - while cur is not None: - # 目标结点在 cur 的右子树中 - if cur.val < num: - cur = cur.right - # 目标结点在 cur 的左子树中 - elif cur.val > num: - cur = cur.left - # 找到目标结点,跳出循环 - else: - break - return cur + [class]{BinarySearchTree}-[func]{search} ``` === "Go" @@ -286,36 +272,7 @@ comments: true === "Python" ```python title="binary_search_tree.py" - """ 插入结点 """ - def insert(self, num: int) -> Optional[TreeNode]: - root = self.root - # 若树为空,直接提前返回 - if root is None: - return None - - cur = root - pre = None - - # 循环查找,越过叶结点后跳出 - while cur is not None: - # 找到重复结点,直接返回 - if cur.val == num: - return None - pre = cur - # 插入位置在 cur 的右子树中 - if cur.val < num: - cur = cur.right - # 插入位置在 cur 的左子树中 - else: - cur = cur.left - - # 插入结点 val - node = TreeNode(num) - if pre.val < num: - pre.right = node - else: - pre.left = node - return node + [class]{BinarySearchTree}-[func]{insert} ``` === "Go" @@ -640,59 +597,9 @@ comments: true === "Python" ```python title="binary_search_tree.py" - """ 删除结点 """ - def remove(self, num: int) -> Optional[TreeNode]: - root = self.root - # 若树为空,直接提前返回 - if root is None: - return None - - cur = root - pre = None - - # 循环查找,越过叶结点后跳出 - while cur is not None: - # 找到待删除结点,跳出循环 - if cur.val == num: - break - pre = cur - if cur.val < num: # 待删除结点在 cur 的右子树中 - cur = cur.right - else: # 待删除结点在 cur 的左子树中 - cur = cur.left - - # 若无待删除结点,则直接返回 - if cur is None: - return None - - # 子结点数量 = 0 or 1 - if cur.left is None or cur.right is None: - # 当子结点数量 = 0 / 1 时, child = null / 该子结点 - child = cur.left or cur.right - # 删除结点 cur - if pre.left == cur: - pre.left = child - else: - pre.right = child - # 子结点数量 = 2 - else: - # 获取中序遍历中 cur 的下一个结点 - nex = self.get_inorder_next(cur.right) - tmp = nex.val - # 递归删除结点 nex - self.remove(nex.val) - # 将 nex 的值复制给 cur - cur.val = tmp - return cur + [class]{BinarySearchTree}-[func]{remove} - """ 获取中序遍历中的下一个结点(仅适用于 root 有左子结点的情况) """ - def get_inorder_next(self, root: Optional[TreeNode]) -> Optional[TreeNode]: - if root is None: - return root - # 循环访问左子结点,直到叶结点时为最小结点,跳出 - while root.left is not None: - root = root.left - return root + [class]{BinarySearchTree}-[func]{get_inorder_next} ``` === "Go" diff --git a/docs/chapter_tree/binary_tree_traversal.md b/docs/chapter_tree/binary_tree_traversal.md old mode 100644 new mode 100755 index 197cb0bb5..7714b3904 --- a/docs/chapter_tree/binary_tree_traversal.md +++ b/docs/chapter_tree/binary_tree_traversal.md @@ -65,21 +65,7 @@ comments: true === "Python" ```python title="binary_tree_bfs.py" - """ 层序遍历 """ - def hier_order(root: Optional[TreeNode]): - # 初始化队列,加入根结点 - queue = collections.deque() - queue.append(root) - # 初始化一个列表,用于保存遍历序列 - res = [] - while queue: - node = queue.popleft() # 队列出队 - res.append(node.val) # 保存节点值 - if node.left is not None: - queue.append(node.left) # 左子结点入队 - if node.right is not None: - queue.append(node.right) # 右子结点入队 - return res + [class]{}-[func]{hier_order} ``` === "Go" @@ -299,32 +285,11 @@ comments: true === "Python" ```python title="binary_tree_dfs.py" - """ 前序遍历 """ - def pre_order(root: Optional[TreeNode]): - if root is None: - return - # 访问优先级:根结点 -> 左子树 -> 右子树 - res.append(root.val) - pre_order(root=root.left) - pre_order(root=root.right) + [class]{}-[func]{pre_order} - """ 中序遍历 """ - def in_order(root: Optional[TreeNode]): - if root is None: - return - # 访问优先级:左子树 -> 根结点 -> 右子树 - in_order(root=root.left) - res.append(root.val) - in_order(root=root.right) + [class]{}-[func]{in_order} - """ 后序遍历 """ - def post_order(root: Optional[TreeNode]): - if root is None: - return - # 访问优先级:左子树 -> 右子树 -> 根结点 - post_order(root=root.left) - post_order(root=root.right) - res.append(root.val) + [class]{}-[func]{post_order} ``` === "Go" diff --git a/docs/utils/.gitignore b/docs/utils/.gitignore new file mode 100644 index 000000000..ed8ebf583 --- /dev/null +++ b/docs/utils/.gitignore @@ -0,0 +1 @@ +__pycache__ \ No newline at end of file diff --git a/docs/utils/build_markdown.py b/docs/utils/build_markdown.py new file mode 100755 index 000000000..6b119b29e --- /dev/null +++ b/docs/utils/build_markdown.py @@ -0,0 +1,87 @@ +""" +File: build_markdown_docs.py +Created Time: 2023-02-06 +Author: Krahets (krahets@163.com) +""" + +import sys, os.path as osp +sys.path.append(osp.dirname(osp.dirname(osp.dirname(osp.abspath(__file__))))) + +import re +import glob +import shutil +from docs.utils.extract_code_python import ExtractCodeBlocksPython + +def build_markdown(md_path): + with open(md_path, "r") as f: + lines = f.readlines() + + code_blocks_dict = {} + file_pattern = re.compile(r'\s*```(\w+)\s+title="(.+)"') + src_pattern = re.compile(r'\s*\[class\]\{(.*?)\}-\[func\]\{(.*?)\}') + for i in range(len(lines)): + # Find the line target to the source codes + src_match = src_pattern.match(lines[i]) + if src_match is None: + continue + for j in range(i - 1, -1 ,-1): + file_match = file_pattern.match(lines[j]) + if file_match is not None: + break + + # Get code blocks + lang = file_match[1] + file_name = file_match[2] + if file_name not in code_blocks_dict: + code_blocks_dict[file_name] = ExtractCodeBlocksPython( + file_path=osp.dirname(md_path).replace("docs/", f"codes/{lang}/") + f"/{file_name}") + + header_line = i + class_label = src_match[1] + func_label = src_match[2] + code_blocks = code_blocks_dict[file_name] + src_info = { + "line_number": i, + "class_label": src_match[1], + "func_label": src_match[2], + "code_blocks": code_blocks_dict[file_name] + } + + # Add the class to the doc + if not func_label and class_label: + if class_label in code_blocks.classes: + lines.pop(header_line) + class_block = code_blocks.classes[class_label]["block"] + for code_line in class_block[::-1]: + ind = " " * 4 if code_line != "\n" else "" + lines.insert(header_line, ind + code_line) + # Add the function to the doc + elif func_label and not class_label: + if func_label in code_blocks.functions: + lines.pop(header_line) + func_block = code_blocks.functions[func_label] + for code_line in func_block["block"][::-1]: + ind = " " * 4 if code_line != "\n" else "" + lines.insert(header_line, ind + code_line) + # Add the class method to the doc + elif func_label and class_label: + if class_label in code_blocks.classes: + class_dict = code_blocks.classes[class_label] + if func_label in class_dict["functions"]: + lines.pop(header_line) + func_block = class_dict["functions"][func_label] + for code_line in func_block["block"][::-1]: + lines.insert(header_line, code_line) + + with open(md_path.replace("docs/", "build/"), "w") as f: + f.writelines(lines) + print(f"Built {md_path}") + + +if __name__ == "__main__": + # Copy files to the build dir + shutil.copytree("docs", "build", dirs_exist_ok=True) + shutil.rmtree("build/utils") + # Build docs + for md_path in glob.glob("docs/chapter_*/*.md"): + build_markdown(md_path) diff --git a/docs/utils/deploy.sh b/docs/utils/deploy.sh new file mode 100644 index 000000000..fb269ea00 --- /dev/null +++ b/docs/utils/deploy.sh @@ -0,0 +1,8 @@ +# This script is borrowed from https://gist.github.com/cobyism/4730490 + +git add build && git commit -m "build" +git subtree push --prefix build origin built-docs + +mkdocs build --clean +git add site && git commit -m "deploy" +git subtree push --prefix site origin gh-pages diff --git a/docs/utils/extract_code_python.py b/docs/utils/extract_code_python.py new file mode 100755 index 000000000..fb660bca7 --- /dev/null +++ b/docs/utils/extract_code_python.py @@ -0,0 +1,117 @@ +""" +File: extract_code_python.py +Created Time: 2023-02-06 +Author: Krahets (krahets@163.com) +""" + +import re +import os +import os.path as osp +import glob + +class ExtractCodeBlocksPython: + def __init__(self, file_path) -> None: + self.file_path = file_path + with open(file_path) as f: + self.lines = f.readlines() + self.content = "".join(self.lines) + + # Regular expression pattern to match function names and class names + self.func_pattern = re.compile(r'(\s*)def\s+(\w+)\s*\(') + self.class_pattern = re.compile(r'class\s+(\w+)') + + # Detect and extract all the classes and fucntions + self.classes = self.extract_class_blocks() + self.functions = self.extract_function_blocks() + + def search_block(self, header_line, indentation): + """ + Search class/function block given the header_line and indentation + """ + start_line, end_line = 0, len(self.lines) + # Search the code + for i in range(header_line + 1, len(self.lines)): + if re.search("^\s*\n|^\s{ind}\s+.+\n".replace("ind", str(indentation)), + self.lines[i]) is None: + end_line = i + break + # Search the header comment + for i in range(header_line - 1, -1, -1): + if re.search('^\s{ind}""".+'.replace("ind", str(indentation)), + self.lines[i]) is not None: + start_line = i + break + func_block = self.lines[start_line:end_line] + # Remove empty lines at bottom + for i in range(len(func_block) - 1, -1, -1): + if re.search("^\s*\n", func_block[i]) is None: + break + end_line -= 1 + + return start_line, end_line, self.lines[start_line:end_line] + + + def extract_function_blocks(self, indentation=0, start_line=-1, end_line=-1): + """ + Extract all the functions with given indentation + """ + functions = {} + + if start_line == -1: + start_line = 0 + if end_line == -1: + end_line = len(self.lines) - 1 + + for line_num in range(start_line, end_line + 1): + # Search the function header + func_match = self.func_pattern.match(self.lines[line_num]) + if func_match is None: continue + # The function should match the input indentation + if len(func_match.group(1)) != indentation: continue + header_line = line_num + + # Search the block from the header line + start_line, end_line, func_block = self.search_block(header_line, indentation) + # Construct the functions dict + func_label = func_match.group(2) + functions[func_label] = { + "indentation": indentation, + "line_number": { + "start": start_line, + "end": end_line, + "header": header_line, + }, + "block": func_block, + } + + return functions + + def extract_class_blocks(self): + """ + Extract all the classes with given indentation + """ + classes = {} + + for line_num, line in enumerate(self.lines): + # Search the class header + class_match = self.class_pattern.match(line) + if class_match is None: continue + header_line = line_num + + # Search the block from the header line + start_line, end_line, class_block = self.search_block(header_line, 0) + # Construct the classes dict + class_label = class_match.group(1) + classes[class_label] = { + "indentation": 0, + "line_number": { + "start": start_line, + "end": end_line, + "header": header_line, + }, + "block": class_block, + "functions": self.extract_function_blocks( + indentation=4, start_line=start_line, end_line=end_line) + } + + return classes diff --git a/mkdocs.yml b/mkdocs.yml index ae4987632..ccdc539a2 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -3,11 +3,11 @@ site_name: Hello 算法 site_url: https://www.hello-algo.com/ site_author: Krahets site_description: 一本动画图解、能运行、可提问的数据结构与算法入门书 -docs_dir: docs +docs_dir: build # Repository repo_name: krahets/hello-algo repo_url: https://github.com/krahets/hello-algo -edit_uri: https://github.com/krahets/hello-algo/tree/master/docs/ +edit_uri: https://github.com/krahets/hello-algo/tree/main/docs/ # Copyright copyright: Copyright © 2022 Krahets @@ -15,7 +15,7 @@ copyright: Copyright © 2022 Krahets # Configuration theme: name: material - custom_dir: docs/overrides + custom_dir: build/overrides language: zh features: # - announce.dismiss