From eb93939f689d7323a4ee30c49d7ef48f298acc0c Mon Sep 17 00:00:00 2001 From: danielsss Date: Tue, 20 Dec 2022 12:02:21 +1100 Subject: [PATCH 01/43] added: typescript hash func --- .../chapter_hashing/array_hash_map.ts | 137 ++++++++++++++++++ codes/typescript/chapter_hashing/hash_map.ts | 45 ++++++ codes/typescript/tsconfig.json | 16 ++ docs/chapter_hashing/hash_map.md | 110 +++++++++++++- hello-algo.iml | 11 ++ 5 files changed, 317 insertions(+), 2 deletions(-) create mode 100644 codes/typescript/chapter_hashing/array_hash_map.ts create mode 100644 codes/typescript/chapter_hashing/hash_map.ts create mode 100644 codes/typescript/tsconfig.json create mode 100644 hello-algo.iml diff --git a/codes/typescript/chapter_hashing/array_hash_map.ts b/codes/typescript/chapter_hashing/array_hash_map.ts new file mode 100644 index 00000000..d56fb8fd --- /dev/null +++ b/codes/typescript/chapter_hashing/array_hash_map.ts @@ -0,0 +1,137 @@ +/* 键值对 int->String */ +class Entry { + public key: number; + public val: string; + constructor(key: number, val: string) { + this.key = key; + this.val = val; + } +} + +/* 数组的初始化和基本操作 */ +class ArrayList { + + private readonly elements: Entry[]; + constructor(length: number) { + this.elements = new Array(length); + this.initialize(); + } + + /* 初始化 */ + private initialize() { + this.elements.fill(null as any, 0, this.elements.length - 1); + } + + /* 新增和删除 */ + public set(key: number, val: string | null) { + this.isOutOfRange(key); + if (val !== null) { + this.elements[key] = new Entry(key, val); + } + this.elements[key] = null as any; + } + + /* 获取 */ + public get(key: number): string { + return this.elements[key].val; + } + + public entrySet() { + let arr = []; + for (let i = 0; i < this.elements.length; i++) { + if (this.elements[i] !== null) { + arr.push(this.elements[i]); + } + } + return arr; + } + + public valueSet() { + let arr = []; + for (let i = 0; i < this.elements.length; i++) { + if (this.elements[i] !== null) { + arr.push(this.elements[i].val); + } + } + return arr; + } + + public keySet() { + let arr = []; + for (let i = 0; i < this.elements.length; i++) { + if (this.elements[i] !== null) { + arr.push(this.elements[i].key); + } + } + return arr; + } + + private isOutOfRange(key: number) { + if (key > this.elements.length - 1) { + throw new Error('Out of array range'); + } + } +} + +/* 基于数组简易实现的哈希表 */ +class ArrayHashMap { + // 初始化一个长度为 100 的桶(数组) + private bucket: ArrayList; + + constructor() { + this.bucket = new ArrayList(100); + } + + /* 哈希函数 */ + private hashFunc(key: number): number { + return key % 100; + } + + /* 查询操作 */ + public get(key: number): string | null { + let index = this.hashFunc(key); + let val = this.bucket.get(index); + if (val === null) { + return null; + } + return val; + } + + /* 添加操作 */ + public put(key: number, val: string) { + let index = this.hashFunc(key); + this.bucket.set(index, val); + } + + /* 删除操作 */ + public remove(key: number) { + let index = this.hashFunc(key); + // 置为 null ,代表删除 + this.bucket.set(index, null); + } + + /* 获取所有键值对 */ + public entrySet(): Entry[] { + return this.bucket.entrySet(); + } + + /* 获取所有键 */ + public keySet(): number[] { + return this.bucket.keySet(); + } + + /* 获取所有值 */ + public valueSet(): string[] { + return this.bucket.valueSet(); + } + +/* 打印哈希表 */ + public print() { + let entrySet = this.entrySet(); + for (const entry of entrySet) { + console.info(`${entry.key} -> ${entry.val}`); + } + } +} + +export default ArrayHashMap; diff --git a/codes/typescript/chapter_hashing/hash_map.ts b/codes/typescript/chapter_hashing/hash_map.ts new file mode 100644 index 00000000..8849d98f --- /dev/null +++ b/codes/typescript/chapter_hashing/hash_map.ts @@ -0,0 +1,45 @@ +import ArrayHashMap from './array_hash_map'; + +class HashMap { + + constructor() { + /* 初始化哈希表 */ + const map = new ArrayHashMap(); + /* 添加操作 */ + // 在哈希表中添加键值对 (key, value) + map.put(12836, '小哈'); + map.put(15937, '小啰'); + map.put(16750, '小算'); + map.put(13276, '小法'); + map.put(10583, '小鸭'); + console.info('\n添加完成后,哈希表为\nKey -> Value'); + map.print(); + + /* 查询操作 */ + // 向哈希表输入键 key ,得到值 value + let name = map.get(15937); + console.info('\n输入学号 15937 ,查询到姓名 ' + name); + + /* 删除操作 */ + // 在哈希表中删除键值对 (key, value) + map.remove(10583); + console.info('\n删除 10583 后,哈希表为\nKey -> Value'); + map.print(); + + /* 遍历哈希表 */ + console.info('\n遍历键值对 Key->Value'); + for (const entry of map.entrySet()) { + console.info(entry.key + ' -> ' + entry.val); + } + console.info('\n单独遍历键 Key'); + for (const key of map.keySet()) { + console.info(key); + } + console.info('\n单独遍历值 Value'); + for (const val of map.valueSet()) { + console.info(val); + } + } +} + +export default HashMap; \ No newline at end of file diff --git a/codes/typescript/tsconfig.json b/codes/typescript/tsconfig.json new file mode 100644 index 00000000..c53bf4f7 --- /dev/null +++ b/codes/typescript/tsconfig.json @@ -0,0 +1,16 @@ +{ + "compilerOptions": { + "target": "es6", + "moduleResolution": "node", + "resolveJsonModule": true, + "module": "esnext", + "strict": true, + "importHelpers": true, + "noEmit": false, + "sourceMap": true, + "baseUrl": ".", + "esModuleInterop": true, + "downlevelIteration": true, + }, + "include": ["./**/*"], +} diff --git a/docs/chapter_hashing/hash_map.md b/docs/chapter_hashing/hash_map.md index 3a53f5db..091e1242 100644 --- a/docs/chapter_hashing/hash_map.md +++ b/docs/chapter_hashing/hash_map.md @@ -138,7 +138,28 @@ comments: true === "TypeScript" ```typescript title="hash_map.ts" + /* 初始化哈希表 */ + const map = new ArrayHashMap(); + /* 添加操作 */ + // 在哈希表中添加键值对 (key, value) + map.put(12836, '小哈'); + map.put(15937, '小啰'); + map.put(16750, '小算'); + map.put(13276, '小法'); + map.put(10583, '小鸭'); + console.info('\n添加完成后,哈希表为\nKey -> Value'); + map.print(); + /* 查询操作 */ + // 向哈希表输入键 key ,得到值 value + let name = map.get(15937); + console.info('\n输入学号 15937 ,查询到姓名 ' + name); + + /* 删除操作 */ + // 在哈希表中删除键值对 (key, value) + map.remove(10583); + console.info('\n删除 10583 后,哈希表为\nKey -> Value'); + map.print(); ``` === "C" @@ -233,7 +254,19 @@ comments: true === "TypeScript" ```typescript title="hash_map.ts" - + /* 遍历哈希表 */ + console.info('\n遍历键值对 Key->Value'); + for (const entry of map.entrySet()) { + console.info(entry.key + ' -> ' + entry.val); + } + console.info('\n单独遍历键 Key'); + for (const key of map.keySet()) { + console.info(key); + } + console.info('\n单独遍历值 Value'); + for (const val of map.valueSet()) { + console.info(val); + } ``` === "C" @@ -477,7 +510,80 @@ $$ === "TypeScript" ```typescript title="array_hash_map.ts" - + /* 键值对 int->String */ + class Entry { + public key: number; + public val: string; + constructor(key: number, val: string) { + this.key = key; + this.val = val; + } + } + + /* 数组的初始化和基本操作 */ + class ArrayList { + + private readonly elements: Entry[]; + constructor(length: number) { + this.elements = new Array(length); + this.initialize(); + } + + /* 初始化 */ + private initialize() { + this.elements.fill(null as any, 0, this.elements.length - 1); + } + + /* 新增和删除 */ + public set(key: number, val: string | null) { + this.isOutOfRange(key); + if (val !== null) { + this.elements[key] = new Entry(key, val); + } + this.elements[key] = null as any; + } + + /* 获取 */ + public get(key: number): string { + return this.elements[key].val; + } + + public entrySet() { + let arr = []; + for (let i = 0; i < this.elements.length; i++) { + if (this.elements[i] !== null) { + arr.push(this.elements[i]); + } + } + return arr; + } + + public valueSet() { + let arr = []; + for (let i = 0; i < this.elements.length; i++) { + if (this.elements[i] !== null) { + arr.push(this.elements[i].val); + } + } + return arr; + } + + public keySet() { + let arr = []; + for (let i = 0; i < this.elements.length; i++) { + if (this.elements[i] !== null) { + arr.push(this.elements[i].key); + } + } + return arr; + } + + private isOutOfRange(key: number) { + if (key > this.elements.length - 1) { + throw new Error('Out of array range'); + } + } + } ``` === "C" diff --git a/hello-algo.iml b/hello-algo.iml new file mode 100644 index 00000000..0a762e4a --- /dev/null +++ b/hello-algo.iml @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file From 1ef6cd09872576d9ea2bd4471fc306ecf08251a1 Mon Sep 17 00:00:00 2001 From: danielsss Date: Tue, 20 Dec 2022 12:12:46 +1100 Subject: [PATCH 02/43] updated: .gitignore --- .gitignore | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.gitignore b/.gitignore index 70b2f49f..3ff30549 100644 --- a/.gitignore +++ b/.gitignore @@ -13,3 +13,6 @@ docs/overrides/ # python files __pycache__ + +# iml +hello-algo.iml From 6eec01d594c6be44f1d0d7d57402bdf2fd1b94ad Mon Sep 17 00:00:00 2001 From: danielsss Date: Tue, 20 Dec 2022 12:27:44 +1100 Subject: [PATCH 03/43] removed: out of array range check --- codes/typescript/chapter_hashing/array_hash_map.ts | 7 ------- docs/chapter_hashing/hash_map.md | 7 ------- 2 files changed, 14 deletions(-) diff --git a/codes/typescript/chapter_hashing/array_hash_map.ts b/codes/typescript/chapter_hashing/array_hash_map.ts index d56fb8fd..d5b5a9f8 100644 --- a/codes/typescript/chapter_hashing/array_hash_map.ts +++ b/codes/typescript/chapter_hashing/array_hash_map.ts @@ -24,7 +24,6 @@ class ArrayList { /* 新增和删除 */ public set(key: number, val: string | null) { - this.isOutOfRange(key); if (val !== null) { this.elements[key] = new Entry(key, val); } @@ -65,12 +64,6 @@ class ArrayList { } return arr; } - - private isOutOfRange(key: number) { - if (key > this.elements.length - 1) { - throw new Error('Out of array range'); - } - } } /* 基于数组简易实现的哈希表 */ diff --git a/docs/chapter_hashing/hash_map.md b/docs/chapter_hashing/hash_map.md index 091e1242..2fed2fac 100644 --- a/docs/chapter_hashing/hash_map.md +++ b/docs/chapter_hashing/hash_map.md @@ -536,7 +536,6 @@ $$ /* 新增和删除 */ public set(key: number, val: string | null) { - this.isOutOfRange(key); if (val !== null) { this.elements[key] = new Entry(key, val); } @@ -577,12 +576,6 @@ $$ } return arr; } - - private isOutOfRange(key: number) { - if (key > this.elements.length - 1) { - throw new Error('Out of array range'); - } - } } ``` From 9eac1275f65f4f7f70e2d23bcc325ae9eed4f1fb Mon Sep 17 00:00:00 2001 From: a16su <33782391+a16su@users.noreply.github.com> Date: Tue, 20 Dec 2022 15:52:00 +0800 Subject: [PATCH 04/43] add binary_tree and avl_tree python code --- codes/python/chapter_tree/avl_tree.py | 281 ++++++++++++++++++ .../python/chapter_tree/binary_search_tree.py | 167 ++++++++++- codes/python/chapter_tree/binary_tree.py | 32 +- codes/python/chapter_tree/binary_tree_bfs.py | 39 ++- codes/python/chapter_tree/binary_tree_dfs.py | 74 ++++- codes/python/include/binary_tree.py | 2 +- docs/chapter_tree/avl_tree.md | 210 ++++++++++++- docs/chapter_tree/binary_search_tree.md | 104 +++++++ docs/chapter_tree/binary_tree.md | 80 ++++- 9 files changed, 967 insertions(+), 22 deletions(-) create mode 100644 codes/python/chapter_tree/avl_tree.py diff --git a/codes/python/chapter_tree/avl_tree.py b/codes/python/chapter_tree/avl_tree.py new file mode 100644 index 00000000..4e6e3572 --- /dev/null +++ b/codes/python/chapter_tree/avl_tree.py @@ -0,0 +1,281 @@ +import sys, os.path as osp +import typing + +sys.path.append(osp.dirname(osp.dirname(osp.abspath(__file__)))) +from include import * + + +class AVLTreeNode: + def __init__( + self, + val=None, + height: int = 0, + left: typing.Optional["AVLTreeNode"] = None, + right: typing.Optional["AVLTreeNode"] = None, + ): + self.val = val + self.height = height + self.left = left + self.right = right + + def __str__(self): + val = self.val + left_val = self.left.val if self.left else None + right_val = self.right.val if self.right else None + return "".format( + val, left_val, right_val + ) + + +class AVLTree: + def __init__(self, root: typing.Optional[AVLTreeNode] = None): + self.root = root + + @staticmethod + def height(node: typing.Optional[AVLTreeNode]) -> int: + """ + 获取结点高度 + Args: + node:起始结点 + + Returns: 高度 or -1 + + """ + # 空结点高度为 -1 ,叶结点高度为 0 + if node is not None: + return node.height + return -1 + + def __update_height(self, node: AVLTreeNode): + """ + 更新结点高度 + Args: + node: 要更新高度的结点 + + Returns: None + + """ + # 结点高度等于最高子树高度 + 1 + node.height = max([self.height(node.left), self.height(node.right)]) + 1 + + def balance_factor(self, node: AVLTreeNode) -> int: + """ + 获取结点平衡因子 + Args: + node: 要获取平衡因子的结点 + + Returns: 平衡因子 + + """ + # 空结点平衡因子为 0 + if node is None: + return 0 + # 结点平衡因子 = 左子树高度 - 右子树高度 + return self.height(node.left) - self.height(node.right) + + def __right_rotate(self, node: AVLTreeNode) -> AVLTreeNode: + 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 + + def __left_rotate(self, node: AVLTreeNode) -> AVLTreeNode: + 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 + + def rotate(self, node: AVLTreeNode): + """ + 执行旋转操作,使该子树重新恢复平衡 + Args: + node: 要旋转的根结点 + + Returns: 旋转后的根结点 + + """ + # 获取结点 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 + + def insert(self, val) -> AVLTreeNode: + """ + 插入结点 + Args: + val: 结点的值 + + Returns: + node: 插入结点后的根结点 + """ + self.root = self.insert_helper(self.root, val) + return self.root + + def insert_helper( + self, node: typing.Optional[AVLTreeNode], val: int + ) -> AVLTreeNode: + """ + 递归插入结点(辅助函数) + Args: + node: 要插入的根结点 + val: 要插入的结点的值 + + Returns: 插入结点后的根结点 + + """ + if node is None: + return AVLTreeNode(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) + + def remove(self, val: int): + """ + 删除结点 + Args: + val: 要删除的结点的值 + + Returns: + + """ + root = self.remove_helper(self.root, val) + return root + + def remove_helper( + self, node: typing.Optional[AVLTreeNode], val: int + ) -> typing.Optional[AVLTreeNode]: + """ + 递归删除结点(辅助函数) + Args: + node: 删除的起始结点 + val: 要删除的结点的值 + + Returns: 删除目标结点后的起始结点 + + """ + 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.min_node(node.right) + node.right = self.remove_helper(node.right, temp.val) + node.val = temp.val + # 更新结点高度 + self.__update_height(node) + # 2. 执行旋转操作,使该子树重新恢复平衡 + return self.rotate(node) + + def min_node( + self, node: typing.Optional[AVLTreeNode] + ) -> typing.Optional[AVLTreeNode]: + # 获取最小结点 + if node is None: + return None + # 循环访问左子结点,直到叶结点时为最小结点,跳出 + while node.left is not None: + node = node.left + return node + + def search(self, val: int): + cur = self.root + while cur is not None: + if cur.val < val: + cur = cur.right + elif cur.val > val: + cur = cur.left + else: + break + return cur + + +if __name__ == "__main__": + + def test_insert(tree: AVLTree, val: int): + tree.insert(val) + print("\n插入结点 {} 后,AVL 树为".format(val)) + print_tree(tree.root) + + def test_remove(tree: AVLTree, val: int): + tree.remove(val) + print("\n删除结点 {} 后,AVL 树为".format(val)) + print_tree(tree.root) + + # 初始化空 AVL 树 + avl_tree = AVLTree() + + # 插入结点 + # 请关注插入结点后,AVL 树是如何保持平衡的 + test_insert(avl_tree, 1) + test_insert(avl_tree, 2) + test_insert(avl_tree, 3) + test_insert(avl_tree, 4) + test_insert(avl_tree, 5) + test_insert(avl_tree, 8) + test_insert(avl_tree, 7) + test_insert(avl_tree, 9) + test_insert(avl_tree, 10) + test_insert(avl_tree, 6) + + # 插入重复结点 + test_insert(avl_tree, 7) + + # 删除结点 + # 请关注删除结点后,AVL 树是如何保持平衡的 + test_remove(avl_tree, 8) # 删除度为 0 的结点 + test_remove(avl_tree, 5) # 删除度为 1 的结点 + test_remove(avl_tree, 4) # 删除度为 2 的结点 + + result_node = avl_tree.search(7) + print("\n查找到的结点对象为 {},结点值 = {}".format(result_node, result_node.val)) diff --git a/codes/python/chapter_tree/binary_search_tree.py b/codes/python/chapter_tree/binary_search_tree.py index f9dd9ec9..211e7c0d 100644 --- a/codes/python/chapter_tree/binary_search_tree.py +++ b/codes/python/chapter_tree/binary_search_tree.py @@ -1,10 +1,173 @@ -''' +""" File: binary_search_tree.py Created Time: 2022-11-25 Author: Krahets (krahets@163.com) -''' +""" import sys, os.path as osp + sys.path.append(osp.dirname(osp.dirname(osp.abspath(__file__)))) from include import * + +class BinarySearchTree: + """ + 二叉搜索树 + """ + + def __init__(self, nums) -> None: + nums.sort() + self.__root = self.buildTree(nums, 0, len(nums) - 1) + + def buildTree(self, nums, start_index, end_index): + if start_index > end_index: + return None + mid = (start_index + end_index) // 2 + root = TreeNode(nums[mid]) + root.left = self.buildTree( + nums=nums, start_index=start_index, end_index=mid - 1 + ) + root.right = self.buildTree(nums=nums, start_index=mid + 1, end_index=end_index) + return root + + def get_root(self): + return self.__root + + def search(self, num): + """ + 查找结点 + """ + cur = self.get_root() + # 循环查找,越过叶结点后跳出 + while cur is not None: + # 目标结点在 root 的右子树中 + if cur.val < num: + cur = cur.right + # 目标结点在 root 的左子树中 + elif cur.val > num: + cur = cur.left + # 找到目标结点,跳出循环 + else: + break + return cur + + def insert(self, num): + """ + 插入结点 + """ + root = self.get_root() + # 若树为空,直接提前返回 + if root is None: + return None + + cur = root + pre = None + + # 循环查找,越过叶结点后跳出 + while cur is not None: + # 找到重复结点,直接返回 + if cur.val == num: + return None + pre = cur + + if cur.val < num: # 插入位置在 root 的右子树中 + cur = cur.right + else: # 插入位置在 root 的左子树中 + cur = cur.left + + # 插入结点 val + node = TreeNode(num) + if pre.val < num: + pre.right = node + else: + pre.left = node + return node + + def remove(self, num): + """ + 删除结点 + """ + root = self.get_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: # 待删除结点在 root 的右子树中 + cur = cur.right + else: # 待删除结点在 root 的左子树中 + 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.min(cur.right) + tmp = nex.val + # 递归删除结点 nex + self.remove(nex.val) + # 将 nex 的值复制给 cur + cur.val = tmp + return cur + + def min(self, root): + """ + 获取最小结点 + """ + if root is None: + return root + + # 循环访问左子结点,直到叶结点时为最小结点,跳出 + while root.left is not None: + root = root.left + return root + + +if __name__ == "__main__": + # 初始化二叉搜索树 + nums = list(range(1, 16)) + bst = BinarySearchTree(nums=nums) + print("\n初始化的二叉树为\n") + print_tree(bst.get_root()) + + # 查找结点 + node = bst.search(5) + print("\n查找到的结点对象为: {},结点值 = {}".format(node, node.val)) + + # 插入结点 + ndoe = bst.insert(16) + print("\n插入结点 16 后,二叉树为\n") + print_tree(bst.get_root()) + + # 删除结点 + bst.remove(1) + print("\n删除结点 1 后,二叉树为\n") + print_tree(bst.get_root()) + + bst.remove(2) + print("\n删除结点 2 后,二叉树为\n") + print_tree(bst.get_root()) + + bst.remove(4) + print("\n删除结点 4 后,二叉树为\n") + print_tree(bst.get_root()) diff --git a/codes/python/chapter_tree/binary_tree.py b/codes/python/chapter_tree/binary_tree.py index 78afa868..2a892fae 100644 --- a/codes/python/chapter_tree/binary_tree.py +++ b/codes/python/chapter_tree/binary_tree.py @@ -1,10 +1,38 @@ -''' +""" File: binary_tree.py Created Time: 2022-11-25 Author: Krahets (krahets@163.com) -''' +""" import sys, os.path as osp + sys.path.append(osp.dirname(osp.dirname(osp.abspath(__file__)))) from include import * + +""" Driver Code """ +if __name__ == "__main__": + # 初始化二叉树 + # 初始化节点 + n1 = TreeNode(val=1) + n2 = TreeNode(val=2) + n3 = TreeNode(val=3) + n4 = TreeNode(val=4) + n5 = TreeNode(val=5) + n1.left = n2 + n1.right = n3 + n2.left = n4 + n2.right = n5 + print_tree(n1) + + # 插入与删除结点 + P = TreeNode(0) + + # 在 n1 -> n2 中间插入节点 P + n1.left = P + P.left = n2 + print_tree(n1) + + # 删除结点 + n1.left = n2 + print_tree(n1) diff --git a/codes/python/chapter_tree/binary_tree_bfs.py b/codes/python/chapter_tree/binary_tree_bfs.py index 43f19220..57d15f91 100644 --- a/codes/python/chapter_tree/binary_tree_bfs.py +++ b/codes/python/chapter_tree/binary_tree_bfs.py @@ -1,10 +1,45 @@ -''' +""" File: binary_tree_bfs.py Created Time: 2022-11-25 Author: Krahets (krahets@163.com) -''' +""" import sys, os.path as osp sys.path.append(osp.dirname(osp.dirname(osp.abspath(__file__)))) from include import * + +def hierOrder(root): + # 初始化队列,加入根结点 + queue = collections.deque() + queue.append(root) + # 初始化一个列表,用于保存遍历序列 + result = [] + while queue: + # 队列出队 + node = queue.popleft() + # 保存节点值 + result.append(node.val) + if node.left is not None: + # 左子结点入队 + queue.append(node.left) + if node.right is not None: + # 右子结点入队 + queue.append(node.right) + return result + + +""" Driver Code """ +if __name__ == "__main__": + # 初始化二叉树 + # 这里借助了一个从数组直接生成二叉树的函数 + root = list_to_tree( + arr=[1, 2, 3, 4, 5, 6, 7, None, None, None, None, None, None, None, None] + ) + print("\n初始化二叉树\n") + print_tree(root) + + # 层序遍历 + result = hierOrder(root) + print("\n层序遍历的结点打印序列 = ", result) + assert result == [1, 2, 3, 4, 5, 6, 7] \ No newline at end of file diff --git a/codes/python/chapter_tree/binary_tree_dfs.py b/codes/python/chapter_tree/binary_tree_dfs.py index f8415ef5..6c5b92a3 100644 --- a/codes/python/chapter_tree/binary_tree_dfs.py +++ b/codes/python/chapter_tree/binary_tree_dfs.py @@ -1,10 +1,80 @@ -''' +""" File: binary_tree_dfs.py Created Time: 2022-11-25 Author: Krahets (krahets@163.com) -''' +""" import sys, os.path as osp sys.path.append(osp.dirname(osp.dirname(osp.abspath(__file__)))) from include import * + +result = [] + + +def preOrder(root): + """ + 前序遍历二叉树 + """ + if root is None: + return + + # 访问优先级:根结点 -> 左子树 -> 右子树 + result.append(root.val) + preOrder(root=root.left) + preOrder(root=root.right) + + +def inOrder(root): + """ + 中序遍历二叉树 + """ + if root is None: + return + + # 访问优先级:左子树 -> 根结点 -> 右子树 + inOrder(root=root.left) + result.append(root.val) + inOrder(root=root.right) + + +def postOrder(root): + """ + 后序遍历二叉树 + """ + if root is None: + return + + # 访问优先级:左子树 -> 右子树 -> 根结点 + postOrder(root=root.left) + postOrder(root=root.right) + result.append(root.val) + + +""" Driver Code """ +if __name__ == "__main__": + # 初始化二叉树 + # 这里借助了一个从数组直接生成二叉树的函数 + root = list_to_tree( + arr=[1, 2, 3, 4, 5, 6, 7, None, None, None, None, None, None, None, None] + ) + print("\n初始化二叉树\n") + print_tree(root) + + # 前序遍历 + result = [] + preOrder(root) + print("\n前序遍历的结点打印序列 = ", result) + assert result == [1, 2, 4, 5, 3, 6, 7] + + # 中序遍历 + result = [] + inOrder(root) + print("\n中序遍历的结点打印序列 = ", result) + assert result == [4, 2, 5, 1, 6, 3, 7] + + # 后序遍历 + result = [] + postOrder(root) + print("\n后序遍历的结点打印序列 = ", result) + assert result == [4, 5, 2, 6, 7, 3, 1] \ No newline at end of file diff --git a/codes/python/include/binary_tree.py b/codes/python/include/binary_tree.py index 24acb47d..bfe5b5f2 100644 --- a/codes/python/include/binary_tree.py +++ b/codes/python/include/binary_tree.py @@ -9,7 +9,7 @@ import collections class TreeNode: """Definition for a binary tree node """ - def __init__(self, val=0, left=None, right=None): + def __init__(self, val=None, left=None, right=None): self.val = val self.left = left self.right = right diff --git a/docs/chapter_tree/avl_tree.md b/docs/chapter_tree/avl_tree.md index bfa2391d..ef88975b 100644 --- a/docs/chapter_tree/avl_tree.md +++ b/docs/chapter_tree/avl_tree.md @@ -48,7 +48,24 @@ G. M. Adelson-Velsky 和 E. M. Landis 在其 1962 年发表的论文 "An algorit === "Python" ```python title="avl_tree.py" - + class AVLTreeNode: + def __init__( + self, + val=None, + height: int = 0, + left: typing.Optional["AVLTreeNode"] = None, + right: typing.Optional["AVLTreeNode"] = None + ): + self.val = val + self.height = height + self.left = left + self.right = right + + def __str__(self): + val = self.val + left_val = self.left.val if self.left else None + right_val = self.right.val if self.right else None + return "".format(val, left_val, right_val) ``` === "Go" @@ -108,7 +125,31 @@ G. M. Adelson-Velsky 和 E. M. Landis 在其 1962 年发表的论文 "An algorit === "Python" ```python title="avl_tree.py" - + def height(node: typing.Optional[AVLTreeNode]) -> int: + """ + 获取结点高度 + Args: + node:起始结点 + + Returns: 高度 or -1 + + """ + # 空结点高度为 -1 ,叶结点高度为 0 + if node is not None: + return node.height + return -1 + + def update_height(node: AVLTreeNode): + """ + 更新结点高度 + Args: + node: 要更新高度的结点 + + Returns: None + + """ + # 结点高度等于最高子树高度 + 1 + node.height = max([height(node.left), height(node.right)]) + 1 ``` === "Go" @@ -166,7 +207,20 @@ G. M. Adelson-Velsky 和 E. M. Landis 在其 1962 年发表的论文 "An algorit === "Python" ```python title="avl_tree.py" - + def balance_factor(node: AVLTreeNode) -> int: + """ + 获取结点平衡因子 + Args: + node: 要获取平衡因子的结点 + + Returns: 平衡因子 + + """ + # 空结点平衡因子为 0 + if node is None: + return 0 + # 结点平衡因子 = 左子树高度 - 右子树高度 + return height(node.left) - height(node.right) ``` === "Go" @@ -255,7 +309,17 @@ AVL 树的独特之处在于「旋转 Rotation」的操作,其可 **在不影 === "Python" ```python title="avl_tree.py" - + def rightRotate(node: AVLTreeNode): + child = node.left + grand_child = child.right + # 以 child 为原点,将 node 向右旋转 + child.right = node + node.left = grand_child + # 更新结点高度 + update_height(node) + update_height(child) + # 返回旋转后子树的根节点 + return child ``` === "Go" @@ -323,7 +387,17 @@ AVL 树的独特之处在于「旋转 Rotation」的操作,其可 **在不影 === "Python" ```python title="avl_tree.py" - + def leftRotate(node: AVLTreeNode): + child = node.right + grand_child = child.left + # 以 child 为原点,将 node 向左旋转 + child.left = node + node.right = grand_child + # 更新结点高度 + update_height(node) + update_height(child) + # 返回旋转后子树的根节点 + return child ``` === "Go" @@ -432,7 +506,37 @@ AVL 树的独特之处在于「旋转 Rotation」的操作,其可 **在不影 === "Python" ```python title="avl_tree.py" - + def rotate(node: AVLTreeNode): + """ + 执行旋转操作,使该子树重新恢复平衡 + Args: + node: 要旋转的根结点 + + Returns: 旋转后的根结点 + + """ + # 获取结点 node 的平衡因子 + factor = balance_factor(node) + # 左偏树 + if factor > 1: + if balance_factor(node.left) >= 0: + # 右旋 + return right_rotate(node) + else: + # 先左旋后右旋 + node.left = left_rotate(node.left) + return right_rotate(node) + # 右偏树 + elif factor < -1: + if balance_factor(node.right) <= 0: + # 左旋 + return left_rotate(node) + else: + # 先右旋后左旋 + node.right = right_rotate(node.right) + return left_rotate(node) + # 平衡树,无需旋转,直接返回 + return node ``` === "Go" @@ -507,7 +611,42 @@ AVL 树的独特之处在于「旋转 Rotation」的操作,其可 **在不影 === "Python" ```python title="avl_tree.py" - + def insert(val) -> AVLTreeNode: + """ + 插入结点 + Args: + val: 结点的值 + + Returns: + node: 插入结点后的根结点 + """ + root = insert_helper(root, val) + return root + + def insert_helper(node: typing.Optional[AVLTreeNode], val: int) -> AVLTreeNode: + """ + 递归插入结点(辅助函数) + Args: + node: 要插入的根结点 + val: 要插入的结点的值 + + Returns: 插入结点后的根结点 + + """ + if node is None: + return AVLTreeNode(val) + # 1. 查找插入位置,并插入结点 + if val < node.val: + node.left = insert_helper(node.left, val) + elif val > node.val: + node.right = insert_helper(node.right, val) + else: + # 重复结点不插入,直接返回 + return node + # 更新结点高度 + update_height(node) + # 2. 执行旋转操作,使该子树重新恢复平衡 + return rotate(node) ``` === "Go" @@ -604,7 +743,62 @@ AVL 树的独特之处在于「旋转 Rotation」的操作,其可 **在不影 === "Python" ```python title="avl_tree.py" - + def remove(val: int): + """ + 删除结点 + Args: + val: 要删除的结点的值 + + Returns: + + """ + root = remove_helper(root, val) + return root + + def remove_helper(node: typing.Optional[AVLTreeNode], val: int) -> typing.Optional[AVLTreeNode]: + """ + 递归删除结点(辅助函数) + Args: + node: 删除的起始结点 + val: 要删除的结点的值 + + Returns: 删除目标结点后的起始结点 + + """ + if node is None: + return None + # 1. 查找结点,并删除之 + if val < node.val: + node.left = remove_helper(node.left, val) + elif val > node.val: + node.right = 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 = min_node(node.right) + node.right = remove_helper(node.right, temp.val) + node.val = temp.val + # 更新结点高度 + update_height(node) + # 2. 执行旋转操作,使该子树重新恢复平衡 + return rotate(node) + + + def min_node(node: typing.Optional[AVLTreeNode]) -> typing.Optional[AVLTreeNode]: + # 获取最小结点 + if node is None: + return None + # 循环访问左子结点,直到叶结点时为最小结点,跳出 + while node.left is not None: + node = node.left + return node ``` === "Go" diff --git a/docs/chapter_tree/binary_search_tree.md b/docs/chapter_tree/binary_search_tree.md index 9ff36432..a9328ddc 100644 --- a/docs/chapter_tree/binary_search_tree.md +++ b/docs/chapter_tree/binary_search_tree.md @@ -82,6 +82,23 @@ comments: true === "Python" ```python title="binary_search_tree.py" + def search(self, num): + """ + 查找结点 + """ + cur = self.get_root() + # 循环查找,越过叶结点后跳出 + while cur is not None: + # 目标结点在 root 的右子树中 + if cur.val < num: + cur = cur.right + # 目标结点在 root 的左子树中 + elif cur.val > num: + cur = cur.left + # 找到目标结点,跳出循环 + else: + break + return cur ``` @@ -228,7 +245,37 @@ comments: true === "Python" ```python title="binary_search_tree.py" + def insert(self, num): + """ + 插入结点 + """ + root = self.get_root() + # 若树为空,直接提前返回 + if root is None: + return None + cur = root + pre = None + + # 循环查找,越过叶结点后跳出 + while cur is not None: + # 找到重复结点,直接返回 + if cur.val == num: + return None + pre = cur + + if cur.val < num: # 插入位置在 root 的右子树中 + cur = cur.right + else: # 插入位置在 root 的左子树中 + cur = cur.left + + # 插入结点 val + node = TreeNode(num) + if pre.val < num: + pre.right = node + else: + pre.left = node + return node ``` === "Go" @@ -483,7 +530,64 @@ comments: true === "Python" ```python title="binary_search_tree.py" + def remove(self, num): + """ + 删除结点 + """ + root = self.get_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: # 待删除结点在 root 的右子树中 + cur = cur.right + else: # 待删除结点在 root 的左子树中 + 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.min(cur.right) + tmp = nex.val + # 递归删除结点 nex + self.remove(nex.val) + # 将 nex 的值复制给 cur + cur.val = tmp + return cur + + def min(self, root): + """ + 获取最小结点 + """ + if root is None: + return root + + # 循环访问左子结点,直到叶结点时为最小结点,跳出 + while root.left is not None: + root = root.left + return root ``` === "Go" diff --git a/docs/chapter_tree/binary_tree.md b/docs/chapter_tree/binary_tree.md index 243a0753..ab67e6f8 100644 --- a/docs/chapter_tree/binary_tree.md +++ b/docs/chapter_tree/binary_tree.md @@ -33,9 +33,9 @@ comments: true === "Python" ```python title="" - """ 链表结点类 """ class TreeNode: - def __init__(self, val=0, left=None, right=None): + """ 链表结点类 """ + def __init__(self, val=None, left=None, right=None): self.val = val # 结点值 self.left = left # 左子结点指针 self.right = right # 右子结点指针 @@ -190,7 +190,18 @@ comments: true === "Python" ```python title="binary_tree.py" - + # 初始化二叉树 + # 初始化节点 + n1 = TreeNode(val=1) + n2 = TreeNode(val=2) + n3 = TreeNode(val=3) + n4 = TreeNode(val=4) + n5 = TreeNode(val=5) + # 构建引用指向(即指针) + n1.left = n2 + n1.right = n3 + n2.left = n4 + n2.right = n5 ``` === "Go" @@ -288,7 +299,13 @@ comments: true === "Python" ```python title="binary_tree.py" - + # 插入与删除结点 + p = TreeNode(0) + # 在 n1 -> n2 中间插入结点 P + n1.left = p + p.left = n2 + # 删除节点 P + n1.left = n2 ``` === "Go" @@ -406,7 +423,24 @@ comments: true === "Python" ```python title="binary_tree_bfs.py" - + def hierOrder(root): + # 初始化队列,加入根结点 + queue = collections.deque() + queue.append(root) + # 初始化一个列表,用于保存遍历序列 + result = [] + while queue: + # 队列出队 + node = queue.popleft() + # 保存节点值 + result.append(node.val) + if node.left is not None: + # 左子结点入队 + queue.append(node.left) + if node.right is not None: + # 右子结点入队 + queue.append(node.right) + return result ``` === "Go" @@ -578,7 +612,43 @@ comments: true === "Python" ```python title="binary_tree_dfs.py" + def preOrder(root): + """ + 前序遍历二叉树 + """ + if root is None: + return + + # 访问优先级:根结点 -> 左子树 -> 右子树 + result.append(root.val) + preOrder(root=root.left) + preOrder(root=root.right) + + def inOrder(root): + """ + 中序遍历二叉树 + """ + if root is None: + return + + # 访问优先级:左子树 -> 根结点 -> 右子树 + inOrder(root=root.left) + result.append(root.val) + inOrder(root=root.right) + + + def postOrder(root): + """ + 后序遍历二叉树 + """ + if root is None: + return + + # 访问优先级:左子树 -> 右子树 -> 根结点 + postOrder(root=root.left) + postOrder(root=root.right) + result.append(root.val) ``` === "Go" From bd21fd8be9e8e2a07f41658992ec012729d34495 Mon Sep 17 00:00:00 2001 From: danielsss Date: Tue, 20 Dec 2022 19:29:06 +1100 Subject: [PATCH 05/43] fixed: several bugs --- .../chapter_hashing/array_hash_map.ts | 23 +++--- codes/typescript/tsconfig.json | 3 +- docs/chapter_hashing/hash_map.md | 71 ++++++++++++++++--- 3 files changed, 77 insertions(+), 20 deletions(-) diff --git a/codes/typescript/chapter_hashing/array_hash_map.ts b/codes/typescript/chapter_hashing/array_hash_map.ts index d5b5a9f8..e4d1c83f 100644 --- a/codes/typescript/chapter_hashing/array_hash_map.ts +++ b/codes/typescript/chapter_hashing/array_hash_map.ts @@ -1,4 +1,4 @@ -/* 键值对 int->String */ +/* 键值对 Number -> String */ class Entry { public key: number; public val: string; @@ -26,19 +26,23 @@ class ArrayList { public set(key: number, val: string | null) { if (val !== null) { this.elements[key] = new Entry(key, val); + } else { + this.elements[key] = null as any; } - this.elements[key] = null as any; } /* 获取 */ - public get(key: number): string { - return this.elements[key].val; + public get(key: number): string | null { + if (this.elements[key] instanceof Entry) { + return this.elements[key].val; + } + return null; } public entrySet() { let arr = []; for (let i = 0; i < this.elements.length; i++) { - if (this.elements[i] !== null) { + if (this.elements[i]) { arr.push(this.elements[i]); } } @@ -48,7 +52,7 @@ class ArrayList { public valueSet() { let arr = []; for (let i = 0; i < this.elements.length; i++) { - if (this.elements[i] !== null) { + if (this.elements[i]) { arr.push(this.elements[i].val); } } @@ -58,7 +62,7 @@ class ArrayList { public keySet() { let arr = []; for (let i = 0; i < this.elements.length; i++) { - if (this.elements[i] !== null) { + if (this.elements[i]) { arr.push(this.elements[i].key); } } @@ -84,9 +88,7 @@ class ArrayHashMap { public get(key: number): string | null { let index = this.hashFunc(key); let val = this.bucket.get(index); - if (val === null) { - return null; - } + if (val === null) return null; return val; } @@ -122,6 +124,7 @@ class ArrayHashMap { public print() { let entrySet = this.entrySet(); for (const entry of entrySet) { + if (!entry) continue; console.info(`${entry.key} -> ${entry.val}`); } } diff --git a/codes/typescript/tsconfig.json b/codes/typescript/tsconfig.json index c53bf4f7..446280b1 100644 --- a/codes/typescript/tsconfig.json +++ b/codes/typescript/tsconfig.json @@ -3,9 +3,8 @@ "target": "es6", "moduleResolution": "node", "resolveJsonModule": true, - "module": "esnext", + "module": "commonjs", "strict": true, - "importHelpers": true, "noEmit": false, "sourceMap": true, "baseUrl": ".", diff --git a/docs/chapter_hashing/hash_map.md b/docs/chapter_hashing/hash_map.md index 2fed2fac..981204b7 100644 --- a/docs/chapter_hashing/hash_map.md +++ b/docs/chapter_hashing/hash_map.md @@ -510,7 +510,7 @@ $$ === "TypeScript" ```typescript title="array_hash_map.ts" - /* 键值对 int->String */ + /* 键值对 Number -> String */ class Entry { public key: number; public val: string; @@ -538,19 +538,23 @@ $$ public set(key: number, val: string | null) { if (val !== null) { this.elements[key] = new Entry(key, val); + } else { + this.elements[key] = null as any; } - this.elements[key] = null as any; } /* 获取 */ - public get(key: number): string { - return this.elements[key].val; + public get(key: number): string | null { + if (this.elements[key] instanceof Entry) { + return this.elements[key].val; + } + return null; } public entrySet() { - let arr = []; + let arr = []; for (let i = 0; i < this.elements.length; i++) { - if (this.elements[i] !== null) { + if (this.elements[i]) { arr.push(this.elements[i]); } } @@ -560,7 +564,7 @@ $$ public valueSet() { let arr = []; for (let i = 0; i < this.elements.length; i++) { - if (this.elements[i] !== null) { + if (this.elements[i]) { arr.push(this.elements[i].val); } } @@ -570,13 +574,64 @@ $$ public keySet() { let arr = []; for (let i = 0; i < this.elements.length; i++) { - if (this.elements[i] !== null) { + if (this.elements[i]) { arr.push(this.elements[i].key); } } return arr; } } + + /* 基于数组简易实现的哈希表 */ + class ArrayHashMap { + // 初始化一个长度为 100 的桶(数组) + private bucket: ArrayList; + + constructor() { + this.bucket = new ArrayList(100); + } + + /* 哈希函数 */ + private hashFunc(key: number): number { + return key % 100; + } + + /* 查询操作 */ + public get(key: number): string | null { + let index = this.hashFunc(key); + let val = this.bucket.get(index); + if (val === null) return null; + return val; + } + + /* 添加操作 */ + public put(key: number, val: string) { + let index = this.hashFunc(key); + this.bucket.set(index, val); + } + + /* 删除操作 */ + public remove(key: number) { + let index = this.hashFunc(key); + // 置为 null ,代表删除 + this.bucket.set(index, null); + } + + /* 获取所有键值对 */ + public entrySet(): Entry[] { + return this.bucket.entrySet(); + } + + /* 获取所有键 */ + public keySet(): number[] { + return this.bucket.keySet(); + } + + /* 获取所有值 */ + public valueSet(): string[] { + return this.bucket.valueSet(); + } + } ``` === "C" From 045df5847230a829a243fb31b5c5e2ef2a6f2f22 Mon Sep 17 00:00:00 2001 From: danielsss Date: Tue, 20 Dec 2022 19:37:24 +1100 Subject: [PATCH 06/43] added: header comments --- codes/typescript/chapter_hashing/array_hash_map.ts | 6 ++++++ codes/typescript/chapter_hashing/hash_map.ts | 6 ++++++ 2 files changed, 12 insertions(+) diff --git a/codes/typescript/chapter_hashing/array_hash_map.ts b/codes/typescript/chapter_hashing/array_hash_map.ts index e4d1c83f..41a153d6 100644 --- a/codes/typescript/chapter_hashing/array_hash_map.ts +++ b/codes/typescript/chapter_hashing/array_hash_map.ts @@ -1,3 +1,9 @@ +/* + * File: array_hash_map.ts + * Created Time: 2022-12-29 + * Author: Daniel (better.sunjian@gmail.com) + */ + /* 键值对 Number -> String */ class Entry { public key: number; diff --git a/codes/typescript/chapter_hashing/hash_map.ts b/codes/typescript/chapter_hashing/hash_map.ts index 8849d98f..a979d9fc 100644 --- a/codes/typescript/chapter_hashing/hash_map.ts +++ b/codes/typescript/chapter_hashing/hash_map.ts @@ -1,3 +1,9 @@ +/* + * File: hash_map.ts + * Created Time: 2022-12-29 + * Author: Daniel (better.sunjian@gmail.com) + */ + import ArrayHashMap from './array_hash_map'; class HashMap { From 18b8557a6aefc834da8ef4a61ef385e5e3967747 Mon Sep 17 00:00:00 2001 From: danielsss Date: Tue, 20 Dec 2022 19:37:39 +1100 Subject: [PATCH 07/43] added: header comments --- codes/typescript/chapter_hashing/array_hash_map.ts | 2 +- codes/typescript/chapter_hashing/hash_map.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/codes/typescript/chapter_hashing/array_hash_map.ts b/codes/typescript/chapter_hashing/array_hash_map.ts index 41a153d6..7ce7eeb3 100644 --- a/codes/typescript/chapter_hashing/array_hash_map.ts +++ b/codes/typescript/chapter_hashing/array_hash_map.ts @@ -1,6 +1,6 @@ /* * File: array_hash_map.ts - * Created Time: 2022-12-29 + * Created Time: 2022-12-20 * Author: Daniel (better.sunjian@gmail.com) */ diff --git a/codes/typescript/chapter_hashing/hash_map.ts b/codes/typescript/chapter_hashing/hash_map.ts index a979d9fc..5e37d5b0 100644 --- a/codes/typescript/chapter_hashing/hash_map.ts +++ b/codes/typescript/chapter_hashing/hash_map.ts @@ -1,6 +1,6 @@ /* * File: hash_map.ts - * Created Time: 2022-12-29 + * Created Time: 2022-12-20 * Author: Daniel (better.sunjian@gmail.com) */ From 7d0a30b1d7a1955035eb23fc7b013cfdf0514083 Mon Sep 17 00:00:00 2001 From: danielsss Date: Tue, 20 Dec 2022 19:47:23 +1100 Subject: [PATCH 08/43] removed: iml file --- hello-algo.iml | 11 ----------- 1 file changed, 11 deletions(-) delete mode 100644 hello-algo.iml diff --git a/hello-algo.iml b/hello-algo.iml deleted file mode 100644 index 0a762e4a..00000000 --- a/hello-algo.iml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - \ No newline at end of file From 1e72f66f093d5ec85427bd98cb9c4addf5705b69 Mon Sep 17 00:00:00 2001 From: danielsss Date: Thu, 22 Dec 2022 00:04:30 +1100 Subject: [PATCH 09/43] Updated code formats and removed useless codes --- .../chapter_hashing/array_hash_map.ts | 236 +++++++++--------- codes/typescript/chapter_hashing/hash_map.ts | 51 ---- codes/typescript/tsconfig.json | 15 -- docs/chapter_hashing/hash_map.md | 107 +++----- 4 files changed, 149 insertions(+), 260 deletions(-) delete mode 100644 codes/typescript/chapter_hashing/hash_map.ts delete mode 100644 codes/typescript/tsconfig.json diff --git a/codes/typescript/chapter_hashing/array_hash_map.ts b/codes/typescript/chapter_hashing/array_hash_map.ts index 7ce7eeb3..c1539e03 100644 --- a/codes/typescript/chapter_hashing/array_hash_map.ts +++ b/codes/typescript/chapter_hashing/array_hash_map.ts @@ -6,134 +6,130 @@ /* 键值对 Number -> String */ class Entry { - public key: number; - public val: string; - constructor(key: number, val: string) { - this.key = key; - this.val = val; - } -} + public key: number; + public val: string; -/* 数组的初始化和基本操作 */ -class ArrayList { - - private readonly elements: Entry[]; - constructor(length: number) { - this.elements = new Array(length); - this.initialize(); - } - - /* 初始化 */ - private initialize() { - this.elements.fill(null as any, 0, this.elements.length - 1); - } - - /* 新增和删除 */ - public set(key: number, val: string | null) { - if (val !== null) { - this.elements[key] = new Entry(key, val); - } else { - this.elements[key] = null as any; + constructor(key: number, val: string) { + this.key = key; + this.val = val; } - } - - /* 获取 */ - public get(key: number): string | null { - if (this.elements[key] instanceof Entry) { - return this.elements[key].val; - } - return null; - } - - public entrySet() { - let arr = []; - for (let i = 0; i < this.elements.length; i++) { - if (this.elements[i]) { - arr.push(this.elements[i]); - } - } - return arr; - } - - public valueSet() { - let arr = []; - for (let i = 0; i < this.elements.length; i++) { - if (this.elements[i]) { - arr.push(this.elements[i].val); - } - } - return arr; - } - - public keySet() { - let arr = []; - for (let i = 0; i < this.elements.length; i++) { - if (this.elements[i]) { - arr.push(this.elements[i].key); - } - } - return arr; - } } /* 基于数组简易实现的哈希表 */ class ArrayHashMap { - // 初始化一个长度为 100 的桶(数组) - private bucket: ArrayList; - constructor() { - this.bucket = new ArrayList(100); - } + private readonly bucket: Entry[]; - /* 哈希函数 */ - private hashFunc(key: number): number { - return key % 100; - } - - /* 查询操作 */ - public get(key: number): string | null { - let index = this.hashFunc(key); - let val = this.bucket.get(index); - if (val === null) return null; - return val; - } - - /* 添加操作 */ - public put(key: number, val: string) { - let index = this.hashFunc(key); - this.bucket.set(index, val); - } - - /* 删除操作 */ - public remove(key: number) { - let index = this.hashFunc(key); - // 置为 null ,代表删除 - this.bucket.set(index, null); - } - - /* 获取所有键值对 */ - public entrySet(): Entry[] { - return this.bucket.entrySet(); - } - - /* 获取所有键 */ - public keySet(): number[] { - return this.bucket.keySet(); - } - - /* 获取所有值 */ - public valueSet(): string[] { - return this.bucket.valueSet(); - } - -/* 打印哈希表 */ - public print() { - let entrySet = this.entrySet(); - for (const entry of entrySet) { - if (!entry) continue; - console.info(`${entry.key} -> ${entry.val}`); + constructor() { + // 初始化一个长度为 100 的桶(数组) + this.bucket = (new Array(100)).fill(null as any); + } + + /* 哈希函数 */ + private hashFunc(key: number): number { + return key % 100; + } + + /* 查询操作 */ + public get(key: number): string | null { + let index = this.hashFunc(key); + let entry = this.bucket[index]; + if (entry === null) return null; + return entry.val; + } + + /* 添加操作 */ + public put(key: number, val: string) { + let index = this.hashFunc(key); + this.bucket[index] = new Entry(index, val); + } + + /* 删除操作 */ + public remove(key: number) { + let index = this.hashFunc(key); + // 置为 null ,代表删除 + this.bucket[index] = null as any; + } + + /* 获取所有键值对 */ + public entrySet(): Entry[] { + let arr = []; + for (let i = 0; i < this.bucket.length; i++) { + if (this.bucket[i]) { + arr.push(this.bucket[i]); + } + } + return arr; + } + + /* 获取所有键 */ + public keySet(): number[] { + let arr = []; + for (let i = 0; i < this.bucket.length; i++) { + if (this.bucket[i]) { + arr.push(this.bucket[i].key); + } + } + return arr; + } + + /* 获取所有值 */ + public valueSet(): string[] { + let arr = []; + for (let i = 0; i < this.bucket.length; i++) { + if (this.bucket[i]) { + arr.push(this.bucket[i].val); + } + } + return arr; + } + + /* 打印哈希表 */ + public print() { + let entrySet = this.entrySet(); + for (const entry of entrySet) { + if (!entry) continue; + console.info(`${entry.key} -> ${entry.val}`); + } } - } } -export default ArrayHashMap; + +/* 初始化哈希表 */ +const map = new ArrayHashMap(); +/* 添加操作 */ +// 在哈希表中添加键值对 (key, value) +map.put(12836, '小哈'); +map.put(15937, '小啰'); +map.put(16750, '小算'); +map.put(13276, '小法'); +map.put(10583, '小鸭'); +console.info('\n添加完成后,哈希表为\nKey -> Value'); +map.print(); + +/* 查询操作 */ +// 向哈希表输入键 key ,得到值 value +let name = map.get(15937); +console.info('\n输入学号 15937 ,查询到姓名 ' + name); + +/* 删除操作 */ +// 在哈希表中删除键值对 (key, value) +map.remove(10583); +console.info('\n删除 10583 后,哈希表为\nKey -> Value'); +map.print(); + +/* 遍历哈希表 */ +console.info('\n遍历键值对 Key->Value'); +for (const entry of map.entrySet()) { + console.info(entry.key + ' -> ' + entry.val); +} +console.info('\n单独遍历键 Key'); +for (const key of map.keySet()) { + console.info(key); +} +console.info('\n单独遍历值 Value'); +for (const val of map.valueSet()) { + console.info(val); +} + +export {}; diff --git a/codes/typescript/chapter_hashing/hash_map.ts b/codes/typescript/chapter_hashing/hash_map.ts deleted file mode 100644 index 5e37d5b0..00000000 --- a/codes/typescript/chapter_hashing/hash_map.ts +++ /dev/null @@ -1,51 +0,0 @@ -/* - * File: hash_map.ts - * Created Time: 2022-12-20 - * Author: Daniel (better.sunjian@gmail.com) - */ - -import ArrayHashMap from './array_hash_map'; - -class HashMap { - - constructor() { - /* 初始化哈希表 */ - const map = new ArrayHashMap(); - /* 添加操作 */ - // 在哈希表中添加键值对 (key, value) - map.put(12836, '小哈'); - map.put(15937, '小啰'); - map.put(16750, '小算'); - map.put(13276, '小法'); - map.put(10583, '小鸭'); - console.info('\n添加完成后,哈希表为\nKey -> Value'); - map.print(); - - /* 查询操作 */ - // 向哈希表输入键 key ,得到值 value - let name = map.get(15937); - console.info('\n输入学号 15937 ,查询到姓名 ' + name); - - /* 删除操作 */ - // 在哈希表中删除键值对 (key, value) - map.remove(10583); - console.info('\n删除 10583 后,哈希表为\nKey -> Value'); - map.print(); - - /* 遍历哈希表 */ - console.info('\n遍历键值对 Key->Value'); - for (const entry of map.entrySet()) { - console.info(entry.key + ' -> ' + entry.val); - } - console.info('\n单独遍历键 Key'); - for (const key of map.keySet()) { - console.info(key); - } - console.info('\n单独遍历值 Value'); - for (const val of map.valueSet()) { - console.info(val); - } - } -} - -export default HashMap; \ No newline at end of file diff --git a/codes/typescript/tsconfig.json b/codes/typescript/tsconfig.json deleted file mode 100644 index 446280b1..00000000 --- a/codes/typescript/tsconfig.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "compilerOptions": { - "target": "es6", - "moduleResolution": "node", - "resolveJsonModule": true, - "module": "commonjs", - "strict": true, - "noEmit": false, - "sourceMap": true, - "baseUrl": ".", - "esModuleInterop": true, - "downlevelIteration": true, - }, - "include": ["./**/*"], -} diff --git a/docs/chapter_hashing/hash_map.md b/docs/chapter_hashing/hash_map.md index 981204b7..896675ec 100644 --- a/docs/chapter_hashing/hash_map.md +++ b/docs/chapter_hashing/hash_map.md @@ -512,83 +512,24 @@ $$ ```typescript title="array_hash_map.ts" /* 键值对 Number -> String */ class Entry { + public key: number; public val: string; + constructor(key: number, val: string) { this.key = key; this.val = val; } } - - /* 数组的初始化和基本操作 */ - class ArrayList { - - private readonly elements: Entry[]; - constructor(length: number) { - this.elements = new Array(length); - this.initialize(); - } - - /* 初始化 */ - private initialize() { - this.elements.fill(null as any, 0, this.elements.length - 1); - } - - /* 新增和删除 */ - public set(key: number, val: string | null) { - if (val !== null) { - this.elements[key] = new Entry(key, val); - } else { - this.elements[key] = null as any; - } - } - - /* 获取 */ - public get(key: number): string | null { - if (this.elements[key] instanceof Entry) { - return this.elements[key].val; - } - return null; - } - - public entrySet() { - let arr = []; - for (let i = 0; i < this.elements.length; i++) { - if (this.elements[i]) { - arr.push(this.elements[i]); - } - } - return arr; - } - - public valueSet() { - let arr = []; - for (let i = 0; i < this.elements.length; i++) { - if (this.elements[i]) { - arr.push(this.elements[i].val); - } - } - return arr; - } - - public keySet() { - let arr = []; - for (let i = 0; i < this.elements.length; i++) { - if (this.elements[i]) { - arr.push(this.elements[i].key); - } - } - return arr; - } - } /* 基于数组简易实现的哈希表 */ class ArrayHashMap { - // 初始化一个长度为 100 的桶(数组) - private bucket: ArrayList; - + + private readonly bucket: Entry[]; + constructor() { - this.bucket = new ArrayList(100); + // 初始化一个长度为 100 的桶(数组) + this.bucket = (new Array(100)).fill(null as any); } /* 哈希函数 */ @@ -599,37 +540,55 @@ $$ /* 查询操作 */ public get(key: number): string | null { let index = this.hashFunc(key); - let val = this.bucket.get(index); - if (val === null) return null; - return val; + let entry = this.bucket[index]; + if (entry === null) return null; + return entry.val; } /* 添加操作 */ public put(key: number, val: string) { let index = this.hashFunc(key); - this.bucket.set(index, val); + this.bucket[index] = new Entry(index, val); } /* 删除操作 */ public remove(key: number) { let index = this.hashFunc(key); // 置为 null ,代表删除 - this.bucket.set(index, null); + this.bucket[index] = null as any; } /* 获取所有键值对 */ public entrySet(): Entry[] { - return this.bucket.entrySet(); + let arr = []; + for (let i = 0; i < this.bucket.length; i++) { + if (this.bucket[i]) { + arr.push(this.bucket[i]); + } + } + return arr; } /* 获取所有键 */ public keySet(): number[] { - return this.bucket.keySet(); + let arr = []; + for (let i = 0; i < this.bucket.length; i++) { + if (this.bucket[i]) { + arr.push(this.bucket[i].key); + } + } + return arr; } /* 获取所有值 */ public valueSet(): string[] { - return this.bucket.valueSet(); + let arr = []; + for (let i = 0; i < this.bucket.length; i++) { + if (this.bucket[i]) { + arr.push(this.bucket[i].val); + } + } + return arr; } } ``` From 18636faf99178d190ec6a0d4af7353387d230986 Mon Sep 17 00:00:00 2001 From: danielsss Date: Thu, 22 Dec 2022 10:44:44 +1100 Subject: [PATCH 10/43] Update built-in Hash Map --- .../chapter_hashing/array_hash_map.ts | 38 +++++++------- codes/typescript/chapter_hashing/hash_map.ts | 49 +++++++++++++++++++ docs/chapter_hashing/hash_map.md | 46 ++++++++--------- 3 files changed, 91 insertions(+), 42 deletions(-) create mode 100644 codes/typescript/chapter_hashing/hash_map.ts diff --git a/codes/typescript/chapter_hashing/array_hash_map.ts b/codes/typescript/chapter_hashing/array_hash_map.ts index c1539e03..dde15185 100644 --- a/codes/typescript/chapter_hashing/array_hash_map.ts +++ b/codes/typescript/chapter_hashing/array_hash_map.ts @@ -18,11 +18,11 @@ class Entry { /* 基于数组简易实现的哈希表 */ class ArrayHashMap { - private readonly bucket: Entry[]; + private readonly bucket: Entry | null[]; constructor() { // 初始化一个长度为 100 的桶(数组) - this.bucket = (new Array(100)).fill(null as any); + this.bucket = (new Array(100)).fill(null); } /* 哈希函数 */ @@ -39,20 +39,20 @@ class ArrayHashMap { } /* 添加操作 */ - public put(key: number, val: string) { + public set(key: number, val: string) { let index = this.hashFunc(key); this.bucket[index] = new Entry(index, val); } /* 删除操作 */ - public remove(key: number) { + public delete(key: number) { let index = this.hashFunc(key); // 置为 null ,代表删除 - this.bucket[index] = null as any; + this.bucket[index] = null; } /* 获取所有键值对 */ - public entrySet(): Entry[] { + public entries(): Entry[] { let arr = []; for (let i = 0; i < this.bucket.length; i++) { if (this.bucket[i]) { @@ -63,7 +63,7 @@ class ArrayHashMap { } /* 获取所有键 */ - public keySet(): number[] { + public keys(): number[] { let arr = []; for (let i = 0; i < this.bucket.length; i++) { if (this.bucket[i]) { @@ -74,7 +74,7 @@ class ArrayHashMap { } /* 获取所有值 */ - public valueSet(): string[] { + public values(): string[] { let arr = []; for (let i = 0; i < this.bucket.length; i++) { if (this.bucket[i]) { @@ -86,7 +86,7 @@ class ArrayHashMap { /* 打印哈希表 */ public print() { - let entrySet = this.entrySet(); + let entrySet = this.entries(); for (const entry of entrySet) { if (!entry) continue; console.info(`${entry.key} -> ${entry.val}`); @@ -94,16 +94,16 @@ class ArrayHashMap { } } - +/* Driver Code */ /* 初始化哈希表 */ const map = new ArrayHashMap(); /* 添加操作 */ // 在哈希表中添加键值对 (key, value) -map.put(12836, '小哈'); -map.put(15937, '小啰'); -map.put(16750, '小算'); -map.put(13276, '小法'); -map.put(10583, '小鸭'); +map.set(12836, '小哈'); +map.set(15937, '小啰'); +map.set(16750, '小算'); +map.set(13276, '小法'); +map.set(10583, '小鸭'); console.info('\n添加完成后,哈希表为\nKey -> Value'); map.print(); @@ -114,21 +114,21 @@ console.info('\n输入学号 15937 ,查询到姓名 ' + name); /* 删除操作 */ // 在哈希表中删除键值对 (key, value) -map.remove(10583); +map.delete(10583); console.info('\n删除 10583 后,哈希表为\nKey -> Value'); map.print(); /* 遍历哈希表 */ console.info('\n遍历键值对 Key->Value'); -for (const entry of map.entrySet()) { +for (const entry of map.entries()) { console.info(entry.key + ' -> ' + entry.val); } console.info('\n单独遍历键 Key'); -for (const key of map.keySet()) { +for (const key of map.keys()) { console.info(key); } console.info('\n单独遍历值 Value'); -for (const val of map.valueSet()) { +for (const val of map.values()) { console.info(val); } diff --git a/codes/typescript/chapter_hashing/hash_map.ts b/codes/typescript/chapter_hashing/hash_map.ts new file mode 100644 index 00000000..3cc968cb --- /dev/null +++ b/codes/typescript/chapter_hashing/hash_map.ts @@ -0,0 +1,49 @@ +/* + * File: hash_map.ts + * Created Time: 2022-12-20 + * Author: Daniel (better.sunjian@gmail.com) + */ + +class hash_map { + constructor() { + /* 初始化哈希表 */ + const map = new Map(); + + /* 添加操作 */ + // 在哈希表中添加键值对 (key, value) + map.set(12836, '小哈'); + map.set(15937, '小啰'); + map.set(16750, '小算'); + map.set(13276, '小法'); + map.set(10583, '小鸭'); + console.info('\n添加完成后,哈希表为\nKey -> Value'); + console.info(map); + + /* 查询操作 */ + // 向哈希表输入键 key ,得到值 value + let name = map.get(15937); + console.info('\n输入学号 15937 ,查询到姓名 ' + name); + + /* 删除操作 */ + // 在哈希表中删除键值对 (key, value) + map.delete(10583); + console.info('\n删除 10583 后,哈希表为\nKey -> Value'); + console.info(map); + + /* 遍历哈希表 */ + console.info('\n遍历键值对 Key->Value'); + for (const [k, v] of map.entries()) { + console.info(k + ' -> ' + v); + } + console.info('\n单独遍历键 Key'); + for (const k of map.keys()) { + console.info(k); + } + console.info('\n单独遍历值 Value'); + for (const v of map.values()) { + console.info(v); + } + } +} + +export {}; diff --git a/docs/chapter_hashing/hash_map.md b/docs/chapter_hashing/hash_map.md index b3dc7521..6d289086 100644 --- a/docs/chapter_hashing/hash_map.md +++ b/docs/chapter_hashing/hash_map.md @@ -139,16 +139,16 @@ comments: true ```typescript title="hash_map.ts" /* 初始化哈希表 */ - const map = new ArrayHashMap(); + const map = new Map(); /* 添加操作 */ // 在哈希表中添加键值对 (key, value) - map.put(12836, '小哈'); - map.put(15937, '小啰'); - map.put(16750, '小算'); - map.put(13276, '小法'); - map.put(10583, '小鸭'); + map.set(12836, '小哈'); + map.set(15937, '小啰'); + map.set(16750, '小算'); + map.set(13276, '小法'); + map.set(10583, '小鸭'); console.info('\n添加完成后,哈希表为\nKey -> Value'); - map.print(); + console.info(map); /* 查询操作 */ // 向哈希表输入键 key ,得到值 value @@ -157,9 +157,9 @@ comments: true /* 删除操作 */ // 在哈希表中删除键值对 (key, value) - map.remove(10583); + map.delete(10583); console.info('\n删除 10583 后,哈希表为\nKey -> Value'); - map.print(); + console.info(map); ``` === "C" @@ -256,16 +256,16 @@ comments: true ```typescript title="hash_map.ts" /* 遍历哈希表 */ console.info('\n遍历键值对 Key->Value'); - for (const entry of map.entrySet()) { - console.info(entry.key + ' -> ' + entry.val); + for (const [k, v] of map.entries()) { + console.info(k + ' -> ' + v); } console.info('\n单独遍历键 Key'); - for (const key of map.keySet()) { - console.info(key); + for (const k of map.keys()) { + console.info(k); } console.info('\n单独遍历值 Value'); - for (const val of map.valueSet()) { - console.info(val); + for (const v of map.values()) { + console.info(v); } ``` @@ -525,11 +525,11 @@ $$ /* 基于数组简易实现的哈希表 */ class ArrayHashMap { - private readonly bucket: Entry[]; + private readonly bucket: Entry | null[]; constructor() { // 初始化一个长度为 100 的桶(数组) - this.bucket = (new Array(100)).fill(null as any); + this.bucket = (new Array(100)).fill(null); } /* 哈希函数 */ @@ -546,20 +546,20 @@ $$ } /* 添加操作 */ - public put(key: number, val: string) { + public set(key: number, val: string) { let index = this.hashFunc(key); this.bucket[index] = new Entry(index, val); } /* 删除操作 */ - public remove(key: number) { + public delete(key: number) { let index = this.hashFunc(key); // 置为 null ,代表删除 - this.bucket[index] = null as any; + this.bucket[index] = null; } /* 获取所有键值对 */ - public entrySet(): Entry[] { + public entries(): Entry[] { let arr = []; for (let i = 0; i < this.bucket.length; i++) { if (this.bucket[i]) { @@ -570,7 +570,7 @@ $$ } /* 获取所有键 */ - public keySet(): number[] { + public keys(): number[] { let arr = []; for (let i = 0; i < this.bucket.length; i++) { if (this.bucket[i]) { @@ -581,7 +581,7 @@ $$ } /* 获取所有值 */ - public valueSet(): string[] { + public values(): string[] { let arr = []; for (let i = 0; i < this.bucket.length; i++) { if (this.bucket[i]) { From 572471948583c600ab989b4297cb3c142448860b Mon Sep 17 00:00:00 2001 From: danielsss Date: Mon, 26 Dec 2022 11:14:59 +1100 Subject: [PATCH 11/43] Removed hash_map class --- codes/typescript/chapter_hashing/hash_map.ts | 71 +++++++++----------- 1 file changed, 33 insertions(+), 38 deletions(-) diff --git a/codes/typescript/chapter_hashing/hash_map.ts b/codes/typescript/chapter_hashing/hash_map.ts index 3cc968cb..7e54cf5c 100644 --- a/codes/typescript/chapter_hashing/hash_map.ts +++ b/codes/typescript/chapter_hashing/hash_map.ts @@ -4,46 +4,41 @@ * Author: Daniel (better.sunjian@gmail.com) */ -class hash_map { - constructor() { - /* 初始化哈希表 */ - const map = new Map(); +/* Driver Code */ +/* 初始化哈希表 */ +const map = new Map(); - /* 添加操作 */ - // 在哈希表中添加键值对 (key, value) - map.set(12836, '小哈'); - map.set(15937, '小啰'); - map.set(16750, '小算'); - map.set(13276, '小法'); - map.set(10583, '小鸭'); - console.info('\n添加完成后,哈希表为\nKey -> Value'); - console.info(map); +/* 添加操作 */ +// 在哈希表中添加键值对 (key, value) +map.set(12836, '小哈'); +map.set(15937, '小啰'); +map.set(16750, '小算'); +map.set(13276, '小法'); +map.set(10583, '小鸭'); +console.info('\n添加完成后,哈希表为\nKey -> Value'); +console.info(map); - /* 查询操作 */ - // 向哈希表输入键 key ,得到值 value - let name = map.get(15937); - console.info('\n输入学号 15937 ,查询到姓名 ' + name); +/* 查询操作 */ +// 向哈希表输入键 key ,得到值 value +let name = map.get(15937); +console.info('\n输入学号 15937 ,查询到姓名 ' + name); - /* 删除操作 */ - // 在哈希表中删除键值对 (key, value) - map.delete(10583); - console.info('\n删除 10583 后,哈希表为\nKey -> Value'); - console.info(map); +/* 删除操作 */ +// 在哈希表中删除键值对 (key, value) +map.delete(10583); +console.info('\n删除 10583 后,哈希表为\nKey -> Value'); +console.info(map); - /* 遍历哈希表 */ - console.info('\n遍历键值对 Key->Value'); - for (const [k, v] of map.entries()) { - console.info(k + ' -> ' + v); - } - console.info('\n单独遍历键 Key'); - for (const k of map.keys()) { - console.info(k); - } - console.info('\n单独遍历值 Value'); - for (const v of map.values()) { - console.info(v); - } - } +/* 遍历哈希表 */ +console.info('\n遍历键值对 Key->Value'); +for (const [k, v] of map.entries()) { + console.info(k + ' -> ' + v); +} +console.info('\n单独遍历键 Key'); +for (const k of map.keys()) { + console.info(k); +} +console.info('\n单独遍历值 Value'); +for (const v of map.values()) { + console.info(v); } - -export {}; From f8748e6006b4342d28278bfbea737214adead91e Mon Sep 17 00:00:00 2001 From: Yudong Jin Date: Mon, 26 Dec 2022 13:14:32 +0800 Subject: [PATCH 12/43] Update space complexity. --- codes/go/chapter_computational_complexity/space_complexity.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/codes/go/chapter_computational_complexity/space_complexity.go b/codes/go/chapter_computational_complexity/space_complexity.go index 77780ae0..eb3ebec9 100644 --- a/codes/go/chapter_computational_complexity/space_complexity.go +++ b/codes/go/chapter_computational_complexity/space_complexity.go @@ -42,7 +42,7 @@ func printTree(root *TreeNode) { printTree(root.right) } -/* 函数(或称方法)*/ +/* 函数 */ func function() int { // do something... return 0 From c2662592bbcff8e173bb73a4a713616d0974d6ff Mon Sep 17 00:00:00 2001 From: Yudong Jin Date: Mon, 26 Dec 2022 13:15:09 +0800 Subject: [PATCH 13/43] Update space complexity --- .../space_complexity.md | 10 +++++----- docs/chapter_tree/summary.md | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/chapter_computational_complexity/space_complexity.md b/docs/chapter_computational_complexity/space_complexity.md index 50f2698f..df5d98f3 100644 --- a/docs/chapter_computational_complexity/space_complexity.md +++ b/docs/chapter_computational_complexity/space_complexity.md @@ -38,7 +38,7 @@ comments: true Node(int x) { val = x; } } - /* 函数(或称方法) */ + /* 函数 */ int function() { // do something... return 0; @@ -63,7 +63,7 @@ comments: true Node(int x) : val(x), next(nullptr) {} }; - /* 函数(或称方法) */ + /* 函数 */ int func() { // do something... return 0; @@ -87,7 +87,7 @@ comments: true self.val = x # 结点值 self.next = None # 指向下一结点的指针(引用) - """ 函数(或称方法) """ + """ 函数 """ def function(): # do something... return 0 @@ -113,7 +113,7 @@ comments: true return &Node{val: val} } - /* 函数(或称方法)*/ + /* 函数 */ func function() int { // do something... return 0 @@ -157,7 +157,7 @@ comments: true Node(int x) { val = x; } } - /* 函数(或称方法) */ + /* 函数 */ int function() { // do something... diff --git a/docs/chapter_tree/summary.md b/docs/chapter_tree/summary.md index 7edfbad7..a46a253f 100644 --- a/docs/chapter_tree/summary.md +++ b/docs/chapter_tree/summary.md @@ -15,4 +15,4 @@ comments: true - 前序、中序、后序遍历是深度优先搜索,体现着“走到头、再回头继续”的回溯遍历方式,通常使用递归实现。 - 二叉搜索树是一种高效的元素查找数据结构,查找、插入、删除操作的时间复杂度皆为 $O(\log n)$ 。二叉搜索树退化为链表后,各项时间复杂度劣化至 $O(n)$ ,因此如何避免退化是非常重要的课题。 - AVL 树又称平衡二叉搜索树,其通过旋转操作,使得在不断插入与删除结点后,仍然可以保持二叉树的平衡(不退化)。 -- AVL 树的旋转操作分为右旋、左旋、先右旋后左旋、先左旋后右旋。在插入或删除结点后,AVL 树会从底置顶地执行旋转操作,使树恢复平衡。 \ No newline at end of file +- AVL 树的旋转操作分为右旋、左旋、先右旋后左旋、先左旋后右旋。在插入或删除结点后,AVL 树会从底置顶地执行旋转操作,使树恢复平衡。 From 305915270abb99ea9ab1054361221e20d4d3f9ce Mon Sep 17 00:00:00 2001 From: danielsss Date: Mon, 26 Dec 2022 17:01:22 +1100 Subject: [PATCH 14/43] Use tricky method to resolve type check --- .../chapter_hashing/array_hash_map.ts | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/codes/typescript/chapter_hashing/array_hash_map.ts b/codes/typescript/chapter_hashing/array_hash_map.ts index dde15185..ab35d94c 100644 --- a/codes/typescript/chapter_hashing/array_hash_map.ts +++ b/codes/typescript/chapter_hashing/array_hash_map.ts @@ -18,7 +18,7 @@ class Entry { /* 基于数组简易实现的哈希表 */ class ArrayHashMap { - private readonly bucket: Entry | null[]; + private readonly bucket: (Entry | null)[]; constructor() { // 初始化一个长度为 100 的桶(数组) @@ -52,8 +52,8 @@ class ArrayHashMap { } /* 获取所有键值对 */ - public entries(): Entry[] { - let arr = []; + public entries(): (Entry | null)[] { + let arr: (Entry | null)[] = []; for (let i = 0; i < this.bucket.length; i++) { if (this.bucket[i]) { arr.push(this.bucket[i]); @@ -63,22 +63,22 @@ class ArrayHashMap { } /* 获取所有键 */ - public keys(): number[] { - let arr = []; + public keys(): (number | undefined)[] { + let arr: (number | undefined)[] = []; for (let i = 0; i < this.bucket.length; i++) { if (this.bucket[i]) { - arr.push(this.bucket[i].key); + arr.push(this.bucket[i]?.key); } } return arr; } /* 获取所有值 */ - public values(): string[] { - let arr = []; + public values(): (string | undefined)[] { + let arr: (string | undefined)[] = []; for (let i = 0; i < this.bucket.length; i++) { if (this.bucket[i]) { - arr.push(this.bucket[i].val); + arr.push(this.bucket[i]?.val); } } return arr; @@ -121,6 +121,7 @@ map.print(); /* 遍历哈希表 */ console.info('\n遍历键值对 Key->Value'); for (const entry of map.entries()) { + if (!entry) continue; console.info(entry.key + ' -> ' + entry.val); } console.info('\n单独遍历键 Key'); From 528b716766df179e493777667f0ab496490fde79 Mon Sep 17 00:00:00 2001 From: danielsss Date: Mon, 26 Dec 2022 17:15:20 +1100 Subject: [PATCH 15/43] Update hash_map docs --- docs/chapter_hashing/hash_map.md | 31 +++++++++++++++---------------- 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/docs/chapter_hashing/hash_map.md b/docs/chapter_hashing/hash_map.md index 6d289086..3c603c58 100644 --- a/docs/chapter_hashing/hash_map.md +++ b/docs/chapter_hashing/hash_map.md @@ -512,21 +512,20 @@ $$ ```typescript title="array_hash_map.ts" /* 键值对 Number -> String */ class Entry { - - public key: number; - public val: string; - + public key: number; + public val: string; + constructor(key: number, val: string) { this.key = key; this.val = val; } } - + /* 基于数组简易实现的哈希表 */ class ArrayHashMap { - - private readonly bucket: Entry | null[]; - + + private readonly bucket: (Entry | null)[]; + constructor() { // 初始化一个长度为 100 的桶(数组) this.bucket = (new Array(100)).fill(null); @@ -559,8 +558,8 @@ $$ } /* 获取所有键值对 */ - public entries(): Entry[] { - let arr = []; + public entries(): (Entry | null)[] { + let arr: (Entry | null)[] = []; for (let i = 0; i < this.bucket.length; i++) { if (this.bucket[i]) { arr.push(this.bucket[i]); @@ -570,22 +569,22 @@ $$ } /* 获取所有键 */ - public keys(): number[] { - let arr = []; + public keys(): (number | undefined)[] { + let arr: (number | undefined)[] = []; for (let i = 0; i < this.bucket.length; i++) { if (this.bucket[i]) { - arr.push(this.bucket[i].key); + arr.push(this.bucket[i]?.key); } } return arr; } /* 获取所有值 */ - public values(): string[] { - let arr = []; + public values(): (string | undefined)[] { + let arr: (string | undefined)[] = []; for (let i = 0; i < this.bucket.length; i++) { if (this.bucket[i]) { - arr.push(this.bucket[i].val); + arr.push(this.bucket[i]?.val); } } return arr; From 630bbac28580dd165cee51af75eb60aabc6aaf6f Mon Sep 17 00:00:00 2001 From: justin Date: Mon, 26 Dec 2022 23:02:39 +0800 Subject: [PATCH 16/43] Add the JavaScript code (Chapter of Hashing) --- .../chapter_hashing/array_hash_map.js | 129 ++++++++++++++++++ codes/javascript/chapter_hashing/hash_map.js | 44 ++++++ 2 files changed, 173 insertions(+) create mode 100644 codes/javascript/chapter_hashing/array_hash_map.js create mode 100644 codes/javascript/chapter_hashing/hash_map.js diff --git a/codes/javascript/chapter_hashing/array_hash_map.js b/codes/javascript/chapter_hashing/array_hash_map.js new file mode 100644 index 00000000..056a8007 --- /dev/null +++ b/codes/javascript/chapter_hashing/array_hash_map.js @@ -0,0 +1,129 @@ +/* + * File: array_hash_map.js + * Created Time: 2022-12-26 + * Author: Justin (xiefahit@gmail.com) + */ + +/* 键值对 Number -> String */ +class Entry { + constructor(key, val) { + this.key = key; + this.val = val; + } +} + +/* 基于数组简易实现的哈希表 */ +class ArrayHashMap { + #bucket + constructor() { + // 初始化一个长度为 100 的桶(数组) + this.#bucket = new Array(100).fill(null); + } + + /* 哈希函数 */ + #hashFunc(key) { + return key % 100; + } + + /* 查询操作 */ + get(key) { + let index = this.#hashFunc(key); + let entry = this.#bucket[index]; + if (entry === null) return null; + return entry.val; + } + + /* 添加操作 */ + set(key, val) { + let index = this.#hashFunc(key); + this.#bucket[index] = new Entry(key, val); + } + + /* 删除操作 */ + delete(key) { + let index = this.#hashFunc(key); + // 置为 null ,代表删除 + this.#bucket[index] = null; + } + + /* 获取所有键值对 */ + entries() { + let arr = []; + for (let i = 0; i < this.#bucket.length; i++) { + if (this.#bucket[i]) { + arr.push(this.#bucket[i]); + } + } + return arr; + } + + /* 获取所有键 */ + keys() { + let arr = []; + for (let i = 0; i < this.#bucket.length; i++) { + if (this.#bucket[i]) { + arr.push(this.#bucket[i]?.key); + } + } + return arr; + } + + /* 获取所有值 */ + values() { + let arr = []; + for (let i = 0; i < this.#bucket.length; i++) { + if (this.#bucket[i]) { + arr.push(this.#bucket[i]?.val); + } + } + return arr; + } + + /* 打印哈希表 */ + print() { + let entrySet = this.entries(); + for (const entry of entrySet) { + if (!entry) continue; + console.info(`${entry.key} -> ${entry.val}`); + } + } +} + +/* Driver Code */ +/* 初始化哈希表 */ +const map = new ArrayHashMap(); +/* 添加操作 */ +// 在哈希表中添加键值对 (key, value) +map.set(12836, '小哈'); +map.set(15937, '小啰'); +map.set(16750, '小算'); +map.set(13276, '小法'); +map.set(10583, '小鸭'); +console.info('\n添加完成后,哈希表为\nKey -> Value'); +map.print(); + +/* 查询操作 */ +// 向哈希表输入键 key ,得到值 value +let name = map.get(15937); +console.info('\n输入学号 15937 ,查询到姓名 ' + name); + +/* 删除操作 */ +// 在哈希表中删除键值对 (key, value) +map.delete(10583); +console.info('\n删除 10583 后,哈希表为\nKey -> Value'); +map.print(); + +/* 遍历哈希表 */ +console.info('\n遍历键值对 Key->Value'); +for (const entry of map.entries()) { + if (!entry) continue; + console.info(entry.key + ' -> ' + entry.val); +} +console.info('\n单独遍历键 Key'); +for (const key of map.keys()) { + console.info(key); +} +console.info('\n单独遍历值 Value'); +for (const val of map.values()) { + console.info(val); +} diff --git a/codes/javascript/chapter_hashing/hash_map.js b/codes/javascript/chapter_hashing/hash_map.js new file mode 100644 index 00000000..197fb7dd --- /dev/null +++ b/codes/javascript/chapter_hashing/hash_map.js @@ -0,0 +1,44 @@ +/* + * File: hash_map.js + * Created Time: 2022-12-26 + * Author: Justin (xiefahit@gmail.com) + */ + +/* Driver Code */ +/* 初始化哈希表 */ +const map = new Map(); + +/* 添加操作 */ +// 在哈希表中添加键值对 (key, value) +map.set(12836, '小哈'); +map.set(15937, '小啰'); +map.set(16750, '小算'); +map.set(13276, '小法'); +map.set(10583, '小鸭'); +console.info('\n添加完成后,哈希表为\nKey -> Value'); +console.info(map); + +/* 查询操作 */ +// 向哈希表输入键 key ,得到值 value +let name = map.get(15937); +console.info('\n输入学号 15937 ,查询到姓名 ' + name); + +/* 删除操作 */ +// 在哈希表中删除键值对 (key, value) +map.delete(10583); +console.info('\n删除 10583 后,哈希表为\nKey -> Value'); +console.info(map); + +/* 遍历哈希表 */ +console.info('\n遍历键值对 Key->Value'); +for (const [k, v] of map.entries()) { + console.info(k + ' -> ' + v); +} +console.info('\n单独遍历键 Key'); +for (const k of map.keys()) { + console.info(k); +} +console.info('\n单独遍历值 Value'); +for (const v of map.values()) { + console.info(v); +} From 650872cb05bf0a8093fa11a1f78158d227e83b06 Mon Sep 17 00:00:00 2001 From: justin Date: Mon, 26 Dec 2022 23:03:12 +0800 Subject: [PATCH 17/43] Add the JavaScript code to docs (Chapter of Hashing) --- docs/chapter_hashing/hash_map.md | 72 +++++++++++++++++++++++++++++++- 1 file changed, 71 insertions(+), 1 deletion(-) diff --git a/docs/chapter_hashing/hash_map.md b/docs/chapter_hashing/hash_map.md index b51a1da9..c441c718 100644 --- a/docs/chapter_hashing/hash_map.md +++ b/docs/chapter_hashing/hash_map.md @@ -132,7 +132,23 @@ comments: true === "JavaScript" ```js title="hash_map.js" + /* 初始化哈希表 */ + const map = new ArrayHashMap(); + /* 添加操作 */ + // 在哈希表中添加键值对 (key, value) + map.set(12836, '小哈'); + map.set(15937, '小啰'); + map.set(16750, '小算'); + map.set(13276, '小法'); + map.set(10583, '小鸭'); + /* 查询操作 */ + // 向哈希表输入键 key ,得到值 value + let name = map.get(15937); + + /* 删除操作 */ + // 在哈希表中删除键值对 (key, value) + map.delete(10583); ``` === "TypeScript" @@ -244,7 +260,20 @@ comments: true === "JavaScript" ```js title="hash_map.js" - + /* 遍历哈希表 */ + // 遍历键值对 key->value + for (const entry of map.entries()) { + if (!entry) continue; + console.info(entry.key + ' -> ' + entry.val); + } + // 单独遍历键 key + for (const key of map.keys()) { + console.info(key); + } + // 单独遍历值 value + for (const val of map.values()) { + console.info(val); + } ``` === "TypeScript" @@ -500,7 +529,48 @@ $$ === "JavaScript" ```js title="array_hash_map.js" + /* 键值对 Number -> String */ + class Entry { + constructor(key, val) { + this.key = key; + this.val = val; + } + } + /* 基于数组简易实现的哈希表 */ + class ArrayHashMap { + #bucket + constructor() { + // 初始化一个长度为 100 的桶(数组) + this.#bucket = new Array(100).fill(null); + } + + /* 哈希函数 */ + #hashFunc(key) { + return key % 100; + } + + /* 查询操作 */ + get(key) { + let index = this.#hashFunc(key); + let entry = this.#bucket[index]; + if (entry === null) return null; + return entry.val; + } + + /* 添加操作 */ + set(key, val) { + let index = this.#hashFunc(key); + this.#bucket[index] = new Entry(key, val); + } + + /* 删除操作 */ + delete(key) { + let index = this.#hashFunc(key); + // 置为 null ,代表删除 + this.#bucket[index] = null; + } + } ``` === "TypeScript" From f628fe27d9ce6fb2a2861dc21fcdb5dd9ce70b21 Mon Sep 17 00:00:00 2001 From: Yudong Jin Date: Mon, 26 Dec 2022 23:12:22 +0800 Subject: [PATCH 18/43] Update codes/typescript/chapter_hashing/array_hash_map.ts Co-authored-by: Justin Tse --- codes/typescript/chapter_hashing/array_hash_map.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/codes/typescript/chapter_hashing/array_hash_map.ts b/codes/typescript/chapter_hashing/array_hash_map.ts index ab35d94c..627205f7 100644 --- a/codes/typescript/chapter_hashing/array_hash_map.ts +++ b/codes/typescript/chapter_hashing/array_hash_map.ts @@ -41,7 +41,7 @@ class ArrayHashMap { /* 添加操作 */ public set(key: number, val: string) { let index = this.hashFunc(key); - this.bucket[index] = new Entry(index, val); + this.bucket[index] = new Entry(key, val); } /* 删除操作 */ From ae9b010894caeecef658dd47c0cd7e524f98fef8 Mon Sep 17 00:00:00 2001 From: nuomi1 Date: Mon, 26 Dec 2022 23:28:45 +0800 Subject: [PATCH 19/43] feat: add Swift installation --- docs/chapter_preface/installation.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/docs/chapter_preface/installation.md b/docs/chapter_preface/installation.md index b58457c7..c6c1b2ee 100644 --- a/docs/chapter_preface/installation.md +++ b/docs/chapter_preface/installation.md @@ -41,3 +41,8 @@ comments: true 1. 下载并安装 [.Net 6.0](https://dotnet.microsoft.com/en-us/download) ; 2. 在 VSCode 的插件市场中搜索 `c#` ,安装 c# 。 + +## Swift 环境 + +1. 下载并安装 [Swift](https://www.swift.org/download/); +2. 在 VSCode 的插件市场中搜索 `swift`,安装 [Swift for Visual Studio Code](https://marketplace.visualstudio.com/items?itemName=sswg.swift-lang)。 From 7e1ff8f74177be403888bbf6a10a3e0d2ab0ac4c Mon Sep 17 00:00:00 2001 From: nuomi1 Date: Mon, 26 Dec 2022 23:29:37 +0800 Subject: [PATCH 20/43] feat: add Swift codes for time complexity article --- .../time_complexity.swift | 170 +++++++++++ .../worst_best_time_complexity.swift | 37 +++ .../time_complexity.md | 276 ++++++++++++++++++ 3 files changed, 483 insertions(+) create mode 100644 codes/swift/chapter_computational_complexity/time_complexity.swift create mode 100644 codes/swift/chapter_computational_complexity/worst_best_time_complexity.swift diff --git a/codes/swift/chapter_computational_complexity/time_complexity.swift b/codes/swift/chapter_computational_complexity/time_complexity.swift new file mode 100644 index 00000000..38bac4fa --- /dev/null +++ b/codes/swift/chapter_computational_complexity/time_complexity.swift @@ -0,0 +1,170 @@ +/* + * File: time_complexity.swift + * Created Time: 2022-12-26 + * Author: nuomi1 (nuomi1@qq.com) + */ + +// 常数阶 +func constant(n: Int) -> Int { + var count = 0 + let size = 100_000 + for _ in 0 ..< size { + count += 1 + } + return count +} + +// 线性阶 +func linear(n: Int) -> Int { + var count = 0 + for _ in 0 ..< n { + count += 1 + } + return count +} + +// 线性阶(遍历数组) +func arrayTraversal(nums: [Int]) -> Int { + var count = 0 + // 循环次数与数组长度成正比 + for _ in nums { + count += 1 + } + return count +} + +// 平方阶 +func quadratic(n: Int) -> Int { + var count = 0 + // 循环次数与数组长度成平方关系 + for _ in 0 ..< n { + for _ in 0 ..< n { + count += 1 + } + } + return count +} + +// 平方阶(冒泡排序) +func bubbleSort(nums: inout [Int]) -> Int { + var count = 0 // 计数器 + // 外循环:待排序元素数量为 n-1, n-2, ..., 1 + for i in sequence(first: nums.count - 1, next: { $0 > 0 ? $0 - 1 : nil }) { + // 内循环:冒泡操作 + for j in 0 ..< i { + if nums[j] > nums[j + 1] { + // 交换 nums[j] 与 nums[j + 1] + let tmp = nums[j] + nums[j] = nums[j + 1] + nums[j + 1] = tmp + count += 3 // 元素交换包含 3 个单元操作 + } + } + } + return count +} + +// 指数阶(循环实现) +func exponential(n: Int) -> Int { + var count = 0 + var base = 1 + // cell 每轮一分为二,形成数列 1, 2, 4, 8, ..., 2^(n-1) + for _ in 0 ..< n { + for _ in 0 ..< base { + count += 1 + } + base *= 2 + } + // count = 1 + 2 + 4 + 8 + .. + 2^(n-1) = 2^n - 1 + return count +} + +// 指数阶(递归实现) +func expRecur(n: Int) -> Int { + if n == 1 { + return 1 + } + return expRecur(n: n - 1) + expRecur(n: n - 1) + 1 +} + +// 对数阶(循环实现) +func logarithmic(n: Int) -> Int { + var count = 0 + var n = n + while n > 1 { + n = n / 2 + count += 1 + } + return count +} + +// 对数阶(递归实现) +func logRecur(n: Int) -> Int { + if n <= 1 { + return 0 + } + return logRecur(n: n / 2) + 1 +} + +// 线性对数阶 +func linearLogRecur(n: Double) -> Int { + if n <= 1 { + return 1 + } + var count = linearLogRecur(n: n / 2) + linearLogRecur(n: n / 2) + for _ in 0 ..< Int(n) { + count += 1 + } + return count +} + +// 阶乘阶(递归实现) +func factorialRecur(n: Int) -> Int { + if n == 0 { + return 1 + } + var count = 0 + // 从 1 个分裂出 n 个 + for _ in 0 ..< n { + count += factorialRecur(n: n - 1) + } + return count +} + +func main() { + // 可以修改 n 运行,体会一下各种复杂度的操作数量变化趋势 + let n = 8 + print("输入数据大小 n =", n) + + var count = constant(n: n) + print("常数阶的计算操作数量 =", count) + + count = linear(n: n) + print("线性阶的计算操作数量 =", count) + count = arrayTraversal(nums: Array(repeating: 0, count: n)) + print("线性阶(遍历数组)的计算操作数量 =", count) + + count = quadratic(n: n) + print("平方阶的计算操作数量 =", count) + var nums = Array(sequence(first: n, next: { $0 > 0 ? $0 - 1 : nil })) // [n,n-1,...,2,1] + count = bubbleSort(nums: &nums) + print("平方阶(冒泡排序)的计算操作数量 =", count) + + count = exponential(n: n) + print("指数阶(循环实现)的计算操作数量 =", count) + count = expRecur(n: n) + print("指数阶(递归实现)的计算操作数量 =", count) + + count = logarithmic(n: n) + print("对数阶(循环实现)的计算操作数量 =", count) + count = logRecur(n: n) + print("对数阶(递归实现)的计算操作数量 =", count) + + count = linearLogRecur(n: Double(n)) + print("线性对数阶(递归实现)的计算操作数量 =", count) + + count = factorialRecur(n: n) + print("阶乘阶(递归实现)的计算操作数量 =", count) +} + +main() diff --git a/codes/swift/chapter_computational_complexity/worst_best_time_complexity.swift b/codes/swift/chapter_computational_complexity/worst_best_time_complexity.swift new file mode 100644 index 00000000..73db6954 --- /dev/null +++ b/codes/swift/chapter_computational_complexity/worst_best_time_complexity.swift @@ -0,0 +1,37 @@ +/* + * File: worst_best_time_complexity.swift + * Created Time: 2022-12-26 + * Author: nuomi1 (nuomi1@qq.com) + */ + +// 生成一个数组,元素为 { 1, 2, ..., n },顺序被打乱 +func randomNumbers(n: Int) -> [Int] { + // 生成数组 nums = { 1, 2, 3, ..., n } + var nums = Array(1 ... n) + // 随机打乱数组元素 + nums.shuffle() + return nums +} + +// 查找数组 nums 中数字 1 所在索引 +func findOne(nums: [Int]) -> Int { + for i in nums.indices { + if nums[i] == 1 { + return i + } + } + return -1 +} + +// Driver Code +func main() { + for _ in 0 ..< 10 { + let n = 100 + let nums = randomNumbers(n: n) + let index = findOne(nums: nums) + print("数组 [ 1, 2, ..., n ] 被打乱后 =", nums) + print("数字 1 的索引为", index) + } +} + +main() diff --git a/docs/chapter_computational_complexity/time_complexity.md b/docs/chapter_computational_complexity/time_complexity.md index 8841a613..aafb0d89 100644 --- a/docs/chapter_computational_complexity/time_complexity.md +++ b/docs/chapter_computational_complexity/time_complexity.md @@ -111,6 +111,21 @@ $$ } ``` +=== "Swift" + + ```swift title="" + // 在某运行平台下 + func algorithm(_ n: Int) { + var a = 2 // 1 ns + a = a + 1 // 1 ns + a = a * 2 // 10 ns + // 循环 n 次 + for _ in 0 ..< n { // 1 ns + print(0) // 5 ns + } + } + ``` + 但实际上, **统计算法的运行时间既不合理也不现实。** 首先,我们不希望预估时间和运行平台绑定,毕竟算法需要跑在各式各样的平台之上。其次,我们很难获知每一种操作的运行时间,这为预估过程带来了极大的难度。 ## 统计时间增长趋势 @@ -246,6 +261,29 @@ $$ } ``` +=== "Swift" + + ```swift title="" + // 算法 A 时间复杂度:常数阶 + func algorithmA(_ n: Int) { + print(0) + } + + // 算法 B 时间复杂度:线性阶 + func algorithmB(_ n: Int) { + for _ in 0 ..< n { + print(0) + } + } + + // 算法 C 时间复杂度:常数阶 + func algorithmC(_ n: Int) { + for _ in 0 ..< 1000000 { + print(0) + } + } + ``` + ![time_complexity_first_example](time_complexity.assets/time_complexity_first_example.png)

Fig. 算法 A, B, C 的时间增长趋势

@@ -352,6 +390,20 @@ $$ } ``` +=== "Swift" + + ```swift title="" + func algorithm(n: Int) { + var a = 1 // +1 + a = a + 1 // +1 + a = a * 2 // +1 + // 循环 n 次 + for _ in 0 ..< n { // +1 + print(0) // +1 + } + } + ``` + $T(n)$ 是个一次函数,说明时间增长趋势是线性的,因此易得时间复杂度是线性阶。 我们将线性阶的时间复杂度记为 $O(n)$ ,这个数学符号被称为「大 $O$ 记号 Big-$O$ Notation」,代表函数 $T(n)$ 的「渐近上界 asymptotic upper bound」。 @@ -516,6 +568,25 @@ $$ } ``` +=== "Swift" + + ```swift title="" + func algorithm(n: Int) { + var a = 1 // +0(技巧 1) + a = a + n // +0(技巧 1) + // +n(技巧 2) + for _ in 0 ..< (5 * n + 1) { + print(0) + } + // +n*n(技巧 3) + for _ in 0 ..< (2 * n) { + for _ in 0 ..< (n + 1) { + print(0) + } + } + } + ``` + ### 2. 判断渐近上界 **时间复杂度由多项式 $T(n)$ 中最高阶的项来决定**。这是因为在 $n$ 趋于无穷大时,最高阶的项将处于主导作用,其它项的影响都可以被忽略。 @@ -643,6 +714,20 @@ $$ } ``` +=== "Swift" + + ```swift title="time_complexity.swift" + // 常数阶 + func constant(n: Int) -> Int { + var count = 0 + let size = 100000 + for _ in 0 ..< size { + count += 1 + } + return count + } + ``` + ### 线性阶 $O(n)$ 线性阶的操作数量相对输入数据大小成线性级别增长。线性阶常出现于单层循环。 @@ -726,6 +811,19 @@ $$ } ``` +=== "Swift" + + ```swift title="time_complexity.swift" + // 线性阶 + func linear(n: Int) -> Int { + var count = 0 + for _ in 0 ..< n { + count += 1 + } + return count + } + ``` + 「遍历数组」和「遍历链表」等操作,时间复杂度都为 $O(n)$ ,其中 $n$ 为数组或链表的长度。 !!! tip @@ -820,6 +918,20 @@ $$ } ``` +=== "Swift" + + ```swift title="time_complexity.swift" + // 线性阶(遍历数组) + func arrayTraversal(nums: [Int]) -> Int { + var count = 0 + // 循环次数与数组长度成正比 + for _ in nums { + count += 1 + } + return count + } + ``` + ### 平方阶 $O(n^2)$ 平方阶的操作数量相对输入数据大小成平方级别增长。平方阶常出现于嵌套循环,外层循环和内层循环都为 $O(n)$ ,总体为 $O(n^2)$ 。 @@ -922,6 +1034,22 @@ $$ } ``` +=== "Swift" + + ```swift title="time_complexity.swift" + // 平方阶 + func quadratic(n: Int) -> Int { + var count = 0 + // 循环次数与数组长度成平方关系 + for _ in 0 ..< n { + for _ in 0 ..< n { + count += 1 + } + } + return count + } + ``` + ![time_complexity_constant_linear_quadratic](time_complexity.assets/time_complexity_constant_linear_quadratic.png)

Fig. 常数阶、线性阶、平方阶的时间复杂度

@@ -1066,6 +1194,29 @@ $$ ``` +=== "Swift" + + ```swift title="time_complexity.swift" + // 平方阶(冒泡排序) + func bubbleSort(nums: inout [Int]) -> Int { + var count = 0 // 计数器 + // 外循环:待排序元素数量为 n-1, n-2, ..., 1 + for i in sequence(first: nums.count - 1, next: { $0 > 0 ? $0 - 1 : nil }) { + // 内循环:冒泡操作 + for j in 0 ..< i { + if nums[j] > nums[j + 1] { + // 交换 nums[j] 与 nums[j + 1] + let tmp = nums[j] + nums[j] = nums[j + 1] + nums[j + 1] = tmp + count += 3 // 元素交换包含 3 个单元操作 + } + } + } + return count + } + ``` + ### 指数阶 $O(2^n)$ !!! note @@ -1182,6 +1333,25 @@ $$ } ``` +=== "Swift" + + ```swift title="time_complexity.swift" + // 指数阶(循环实现) + func exponential(n: Int) -> Int { + var count = 0 + var base = 1 + // cell 每轮一分为二,形成数列 1, 2, 4, 8, ..., 2^(n-1) + for _ in 0 ..< n { + for _ in 0 ..< base { + count += 1 + } + base *= 2 + } + // count = 1 + 2 + 4 + 8 + .. + 2^(n-1) = 2^n - 1 + return count + } + ``` + ![time_complexity_exponential](time_complexity.assets/time_complexity_exponential.png)

Fig. 指数阶的时间复杂度

@@ -1258,6 +1428,18 @@ $$ } ``` +=== "Swift" + + ```swift title="time_complexity.swift" + // 指数阶(递归实现) + func expRecur(n: Int) -> Int { + if n == 1 { + return 1 + } + return expRecur(n: n - 1) + expRecur(n: n - 1) + 1 + } + ``` + ### 对数阶 $O(\log n)$ 对数阶与指数阶正好相反,后者反映“每轮增加到两倍的情况”,而前者反映“每轮缩减到一半的情况”。对数阶仅次于常数阶,时间增长的很慢,是理想的时间复杂度。 @@ -1354,6 +1536,21 @@ $$ } ``` +=== "Swift" + + ```swift title="time_complexity.swift" + // 对数阶(循环实现) + func logarithmic(n: Int) -> Int { + var count = 0 + var n = n + while n > 1 { + n = n / 2 + count += 1 + } + return count + } + ``` + ![time_complexity_logarithmic](time_complexity.assets/time_complexity_logarithmic.png)

Fig. 对数阶的时间复杂度

@@ -1430,6 +1627,18 @@ $$ } ``` +=== "Swift" + + ```swift title="time_complexity.swift" + // 对数阶(递归实现) + func logRecur(n: Int) -> Int { + if n <= 1 { + return 0 + } + return logRecur(n: n / 2) + 1 + } + ``` + ### 线性对数阶 $O(n \log n)$ 线性对数阶常出现于嵌套循环中,两层循环的时间复杂度分别为 $O(\log n)$ 和 $O(n)$ 。 @@ -1531,6 +1740,22 @@ $$ } ``` +=== "Swift" + + ```swift title="time_complexity.swift" + // 线性对数阶 + func linearLogRecur(n: Double) -> Int { + if n <= 1 { + return 1 + } + var count = linearLogRecur(n: n / 2) + linearLogRecur(n: n / 2) + for _ in 0 ..< Int(n) { + count += 1 + } + return count + } + ``` + ![time_complexity_logarithmic_linear](time_complexity.assets/time_complexity_logarithmic_linear.png)

Fig. 线性对数阶的时间复杂度

@@ -1640,6 +1865,23 @@ $$ } ``` +=== "Swift" + + ```swift title="time_complexity.swift" + // 阶乘阶(递归实现) + func factorialRecur(n: Int) -> Int { + if n == 0 { + return 1 + } + var count = 0 + // 从 1 个分裂出 n 个 + for _ in 0 ..< n { + count += factorialRecur(n: n - 1) + } + return count + } + ``` + ![time_complexity_factorial](time_complexity.assets/time_complexity_factorial.png)

Fig. 阶乘阶的时间复杂度

@@ -1872,6 +2114,40 @@ $$ } ``` +=== "Swift" + + ```swift title="" + // 生成一个数组,元素为 { 1, 2, ..., n },顺序被打乱 + func randomNumbers(n: Int) -> [Int] { + // 生成数组 nums = { 1, 2, 3, ..., n } + var nums = Array(1 ... n) + // 随机打乱数组元素 + nums.shuffle() + return nums + } + + // 查找数组 nums 中数字 1 所在索引 + func findOne(nums: [Int]) -> Int { + for i in nums.indices { + if nums[i] == 1 { + return i + } + } + return -1 + } + + // Driver Code + func main() { + for _ in 0 ..< 10 { + let n = 100 + let nums = randomNumbers(n: n) + let index = findOne(nums: nums) + print("数组 [ 1, 2, ..., n ] 被打乱后 =", nums) + print("数字 1 的索引为", index) + } + } + ``` + !!! tip 我们在实际应用中很少使用「最佳时间复杂度」,因为往往只有很小概率下才能达到,会带来一定的误导性。反之,「最差时间复杂度」最为实用,因为它给出了一个“效率安全值”,让我们可以放心地使用算法。 From 60c715b041fdc4c000b2dcdaf88c7c1c23393ea2 Mon Sep 17 00:00:00 2001 From: justin Date: Mon, 26 Dec 2022 23:45:23 +0800 Subject: [PATCH 21/43] Update JavaScript style (Chapter of Hashing) --- codes/javascript/chapter_hashing/array_hash_map.js | 2 +- docs/chapter_hashing/hash_map.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/codes/javascript/chapter_hashing/array_hash_map.js b/codes/javascript/chapter_hashing/array_hash_map.js index 056a8007..f5c77aa2 100644 --- a/codes/javascript/chapter_hashing/array_hash_map.js +++ b/codes/javascript/chapter_hashing/array_hash_map.js @@ -14,7 +14,7 @@ class Entry { /* 基于数组简易实现的哈希表 */ class ArrayHashMap { - #bucket + #bucket; constructor() { // 初始化一个长度为 100 的桶(数组) this.#bucket = new Array(100).fill(null); diff --git a/docs/chapter_hashing/hash_map.md b/docs/chapter_hashing/hash_map.md index c441c718..61f4c229 100644 --- a/docs/chapter_hashing/hash_map.md +++ b/docs/chapter_hashing/hash_map.md @@ -539,7 +539,7 @@ $$ /* 基于数组简易实现的哈希表 */ class ArrayHashMap { - #bucket + #bucket; constructor() { // 初始化一个长度为 100 的桶(数组) this.#bucket = new Array(100).fill(null); From 845a68d6f1cc932a6057a8624ebb886ac614b8ee Mon Sep 17 00:00:00 2001 From: danielsss Date: Tue, 27 Dec 2022 09:30:20 +1100 Subject: [PATCH 22/43] Add the TypeScript code and docs for Chapter of Binary Search --- docs/chapter_searching/binary_search.md | 59 ++++++++++++++++++++----- 1 file changed, 47 insertions(+), 12 deletions(-) diff --git a/docs/chapter_searching/binary_search.md b/docs/chapter_searching/binary_search.md index a74c07aa..32ae411c 100644 --- a/docs/chapter_searching/binary_search.md +++ b/docs/chapter_searching/binary_search.md @@ -116,17 +116,17 @@ $$ === "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 { + /* 二分查找(双闭区间) */ + 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) 中 + if nums[m] < target { // 此情况说明 target 在区间 [m+1, j] 中 i = m + 1 - } else if nums[m] > target { // 此情况说明 target 在区间 [i, m) 中 - j = m + } else if nums[m] > target { // 此情况说明 target 在区间 [i, m-1] 中 + j = m - 1 } else { // 找到目标元素,返回其索引 return m } @@ -161,7 +161,23 @@ $$ === "TypeScript" ```typescript title="binary_search.ts" - + /* 二分查找(左闭右开) */ + const binarySearch1 = function (nums: number[], target: number): number { + // 初始化左闭右开 [0, n) ,即 i, j 分别指向数组首元素、尾元素+1 + let i = 0, j = nums.length; + // 循环,当搜索区间为空时跳出(当 i = j 时为空) + while (i < j) { + let m = Math.floor(i + (j - i) / 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; + } + } + return -1; // 未找到目标元素,返回 -1 + } ``` === "C" @@ -309,7 +325,23 @@ $$ === "TypeScript" ```typescript title="binary_search.ts" - + /* 二分查找(左闭右开) */ + const binarySearch1 = function (nums: number[], target: number): number { + // 初始化左闭右开 [0, n) ,即 i, j 分别指向数组首元素、尾元素+1 + let i = 0, j = nums.length; + // 循环,当搜索区间为空时跳出(当 i = j 时为空) + while (i < j) { + let m = Math.floor(i + (j - i) / 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; + } + } + return -1; // 未找到目标元素,返回 -1 + } ``` === "C" @@ -407,7 +439,10 @@ $$ === "TypeScript" ```typescript title="" - + // (i + j) 有可能超出 Number 的取值范围 + let m = Math.floor((i + j) / 2); + // 更换为此写法则不会越界 + let m = Math.floor(i + (j - i) / 2); ``` === "C" From 67d7cba977e0f97b3a648ea53fdd2011bc50a95b Mon Sep 17 00:00:00 2001 From: danielsss Date: Tue, 27 Dec 2022 09:30:34 +1100 Subject: [PATCH 23/43] Add the TypeScript code and docs for Chapter of Binary Search --- .editorconfig | 16 ++++++ .../chapter_searching/binary_search.ts | 54 +++++++++++++++++++ 2 files changed, 70 insertions(+) create mode 100644 .editorconfig create mode 100644 codes/typescript/chapter_searching/binary_search.ts diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 00000000..53ad327c --- /dev/null +++ b/.editorconfig @@ -0,0 +1,16 @@ +# EditorConfig is awesome: https://EditorConfig.org + +# Unix-style newlines with a newline ending every file +[*] +end_of_line = lf +insert_final_newline = true + +# Matches multiple files with brace expansion notation +# Set default charset +[*.{ts,js,py,java,go,c,cpp,cs}] +charset = utf-8 + +# 4 space indentation +[*.{ts,js,py,java,go,c,cpp,cs}] +indent_style = space +indent_size = 4 \ No newline at end of file diff --git a/codes/typescript/chapter_searching/binary_search.ts b/codes/typescript/chapter_searching/binary_search.ts new file mode 100644 index 00000000..0a96720d --- /dev/null +++ b/codes/typescript/chapter_searching/binary_search.ts @@ -0,0 +1,54 @@ +/* +* File: binary_search.ts +* Created Time: 2022-12-27 +* Author: Daniel (better.sunjian@gmail.com) +*/ + +/* 二分查找(双闭区间) */ +const binarySearch = function (nums: number[], target: number): number { + // 初始化双闭区间 [0, n-1] ,即 i, j 分别指向数组首元素、尾元素 + let i = 0, j = nums.length - 1; + // 循环,当搜索区间为空时跳出(当 i > j 时为空) + while (i <= j) { + let m = Math.floor(i + (j - i) / 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; + } + } + return -1; // 未找到目标元素,返回 -1 +} + +/* 二分查找(左闭右开) */ +const binarySearch1 = function (nums: number[], target: number): number { + // 初始化左闭右开 [0, n) ,即 i, j 分别指向数组首元素、尾元素+1 + let i = 0, j = nums.length; + // 循环,当搜索区间为空时跳出(当 i = j 时为空) + while (i < j) { + const m = Math.floor(i + (j - i) / 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; + } + } + return -1; // 未找到目标元素,返回 -1 +} + + +/* Driver Code */ +const target = 6; +const nums = [ 1, 3, 6, 8, 12, 15, 23, 67, 70, 92 ]; + +/* 二分查找(双闭区间) */ +let index = binarySearch(nums, target); +console.info('目标元素 6 的索引 = %d', index); + +/* 二分查找(左闭右开) */ +index = binarySearch1(nums, target); +console.info('目标元素 6 的索引 = %d', index); From 6264edcadb9af2692ac10c7b61ddf31478a29e43 Mon Sep 17 00:00:00 2001 From: danielsss Date: Tue, 27 Dec 2022 09:35:08 +1100 Subject: [PATCH 24/43] Removed .editorconfig --- .editorconfig | 16 ---------------- 1 file changed, 16 deletions(-) delete mode 100644 .editorconfig diff --git a/.editorconfig b/.editorconfig deleted file mode 100644 index 53ad327c..00000000 --- a/.editorconfig +++ /dev/null @@ -1,16 +0,0 @@ -# EditorConfig is awesome: https://EditorConfig.org - -# Unix-style newlines with a newline ending every file -[*] -end_of_line = lf -insert_final_newline = true - -# Matches multiple files with brace expansion notation -# Set default charset -[*.{ts,js,py,java,go,c,cpp,cs}] -charset = utf-8 - -# 4 space indentation -[*.{ts,js,py,java,go,c,cpp,cs}] -indent_style = space -indent_size = 4 \ No newline at end of file From e0d3572a47295831ae5445c4f950a41ca4b3c9bb Mon Sep 17 00:00:00 2001 From: danielsss Date: Tue, 27 Dec 2022 09:45:33 +1100 Subject: [PATCH 25/43] Fixed format of doc --- docs/chapter_searching/binary_search.md | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/docs/chapter_searching/binary_search.md b/docs/chapter_searching/binary_search.md index 32ae411c..a059d75d 100644 --- a/docs/chapter_searching/binary_search.md +++ b/docs/chapter_searching/binary_search.md @@ -161,18 +161,18 @@ $$ === "TypeScript" ```typescript title="binary_search.ts" - /* 二分查找(左闭右开) */ - const binarySearch1 = function (nums: number[], target: number): number { - // 初始化左闭右开 [0, n) ,即 i, j 分别指向数组首元素、尾元素+1 - let i = 0, j = nums.length; - // 循环,当搜索区间为空时跳出(当 i = j 时为空) - while (i < j) { - let m = Math.floor(i + (j - i) / 2); // 计算中点索引 m - if (nums[m] < target) { // 此情况说明 target 在区间 [m+1, j) 中 + /* 二分查找(双闭区间) */ + const binarySearch = function (nums: number[], target: number): number { + // 初始化双闭区间 [0, n-1] ,即 i, j 分别指向数组首元素、尾元素 + let i = 0, j = nums.length - 1; + // 循环,当搜索区间为空时跳出(当 i > j 时为空) + while (i <= j) { + let m = Math.floor(i + (j - i) / 2);// 计算中点索引 m + if (nums[m] < target) { // 此情况说明 target 在区间 [m+1, j] 中 i = m + 1; - } else if (nums[m] > target) { // 此情况说明 target 在区间 [i, m) 中 - j = m; - } else { // 找到目标元素,返回其索引 + } else if (nums[m] > target) { // 此情况说明 target 在区间 [i, m-1] 中 + j = m - 1; + } else { // 找到目标元素,返回其索引 return m; } } From 88ce287a6f602f38d21c733505e735aeeebaeaca Mon Sep 17 00:00:00 2001 From: danielsss Date: Tue, 27 Dec 2022 09:47:17 +1100 Subject: [PATCH 26/43] Fixed format of doc --- docs/chapter_searching/binary_search.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/chapter_searching/binary_search.md b/docs/chapter_searching/binary_search.md index a059d75d..a04b9515 100644 --- a/docs/chapter_searching/binary_search.md +++ b/docs/chapter_searching/binary_search.md @@ -331,12 +331,12 @@ $$ let i = 0, j = nums.length; // 循环,当搜索区间为空时跳出(当 i = j 时为空) while (i < j) { - let m = Math.floor(i + (j - i) / 2); // 计算中点索引 m - if (nums[m] < target) { // 此情况说明 target 在区间 [m+1, j) 中 + let m = Math.floor(i + (j - i) / 2);// 计算中点索引 m + if (nums[m] < target) { // 此情况说明 target 在区间 [m+1, j) 中 i = m + 1; - } else if (nums[m] > target) { // 此情况说明 target 在区间 [i, m) 中 + } else if (nums[m] > target) { // 此情况说明 target 在区间 [i, m) 中 j = m; - } else { // 找到目标元素,返回其索引 + } else { // 找到目标元素,返回其索引 return m; } } From 9a46bf1d80f4ea8335edb0b134d832ad4bebb0a0 Mon Sep 17 00:00:00 2001 From: DullSword <40877476+DullSword@users.noreply.github.com> Date: Tue, 27 Dec 2022 11:34:41 +0800 Subject: [PATCH 27/43] =?UTF-8?q?docs(chapter=5Ftree/binary=5Ftree/?= =?UTF-8?q?=E4=BA=8C=E5=8F=89=E6=A0=91=E8=A1=A8=E7=A4=BA=E6=96=B9=E5=BC=8F?= =?UTF-8?q?=20*):=20JS=20code?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 与下图及其他编程语言示例代码不一致 --- docs/chapter_tree/binary_tree.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/chapter_tree/binary_tree.md b/docs/chapter_tree/binary_tree.md index 9fc81812..891325b7 100644 --- a/docs/chapter_tree/binary_tree.md +++ b/docs/chapter_tree/binary_tree.md @@ -453,7 +453,7 @@ comments: true ```js title="" /* 二叉树的数组表示 */ // 直接使用 null 来表示空位 - let tree = [1, 2, 3, 4, 5, 6, 7, null, null, null, null, null, null, null, null] + let tree = [1, 2, 3, 4, null, 6, 7, 8, 9, null, null, 12, null, null, 15]; ``` === "TypeScript" From 142913bc9d18afc8264ed9722f7924d2a7d83ae3 Mon Sep 17 00:00:00 2001 From: DullSword <40877476+DullSword@users.noreply.github.com> Date: Tue, 27 Dec 2022 11:51:04 +0800 Subject: [PATCH 28/43] =?UTF-8?q?docs(chapter=5Ftree/binary=5Ftree/?= =?UTF-8?q?=E4=BA=8C=E5=8F=89=E6=A0=91=E8=A1=A8=E7=A4=BA=E6=96=B9=E5=BC=8F?= =?UTF-8?q?=20*):=20TS=20code?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 与下图及其他编程语言示例代码不一致 --- docs/chapter_tree/binary_tree.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/chapter_tree/binary_tree.md b/docs/chapter_tree/binary_tree.md index 9fc81812..08e267ba 100644 --- a/docs/chapter_tree/binary_tree.md +++ b/docs/chapter_tree/binary_tree.md @@ -461,7 +461,7 @@ comments: true ```typescript title="" /* 二叉树的数组表示 */ // 直接使用 null 来表示空位 - let tree = [1, 2, 3, 4, 5, 6, 7, null, null, null, null, null, null, null, null] + let tree: (number | null)[] = [1, 2, 3, 4, null, 6, 7, 8, 9, null, null, 12, null, null, 15]; ``` === "C" From eaa48b6b9f2865c78551c1d865b66147248534ae Mon Sep 17 00:00:00 2001 From: danielsss Date: Tue, 27 Dec 2022 16:52:19 +1100 Subject: [PATCH 29/43] Fixed wrong parameter of Hash Map Set --- docs/chapter_hashing/hash_map.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/chapter_hashing/hash_map.md b/docs/chapter_hashing/hash_map.md index 2e2e5726..d8244d80 100644 --- a/docs/chapter_hashing/hash_map.md +++ b/docs/chapter_hashing/hash_map.md @@ -646,7 +646,7 @@ $$ /* 添加操作 */ public set(key: number, val: string) { let index = this.hashFunc(key); - this.bucket[index] = new Entry(index, val); + this.bucket[index] = new Entry(key, val); } /* 删除操作 */ From 27bad89eeb517e9a50bd664d6477f59e2661db5d Mon Sep 17 00:00:00 2001 From: danielsss Date: Tue, 27 Dec 2022 16:59:25 +1100 Subject: [PATCH 30/43] Update binary search docs --- codes/typescript/chapter_searching/binary_search.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/codes/typescript/chapter_searching/binary_search.ts b/codes/typescript/chapter_searching/binary_search.ts index 0a96720d..74f011b7 100644 --- a/codes/typescript/chapter_searching/binary_search.ts +++ b/codes/typescript/chapter_searching/binary_search.ts @@ -29,9 +29,9 @@ const binarySearch1 = function (nums: number[], target: number): number { // 循环,当搜索区间为空时跳出(当 i = j 时为空) while (i < j) { const m = Math.floor(i + (j - i) / 2); // 计算中点索引 m - if (nums[m] < target) { // 此情况说明 target 在区间 [m+1, j) 中 + if (nums[m] < target) { // 此情况说明 target 在区间 [m+1, j] 中 i = m + 1; - } else if (nums[m] > target) { // 此情况说明 target 在区间 [i, m) 中 + } else if (nums[m] > target) { // 此情况说明 target 在区间 [i, m] 中 j = m; } else { // 找到目标元素,返回其索引 return m; From f79089d7295505644b73d3c4f7231015aea0a014 Mon Sep 17 00:00:00 2001 From: danielsss Date: Tue, 27 Dec 2022 17:06:39 +1100 Subject: [PATCH 31/43] Fixed inconsistent brackets --- .../chapter_searching/binary_search.ts | 2 +- docs/chapter_searching/binary_search.md | 40 +++++++++---------- 2 files changed, 21 insertions(+), 21 deletions(-) diff --git a/codes/typescript/chapter_searching/binary_search.ts b/codes/typescript/chapter_searching/binary_search.ts index 74f011b7..2a03994b 100644 --- a/codes/typescript/chapter_searching/binary_search.ts +++ b/codes/typescript/chapter_searching/binary_search.ts @@ -10,7 +10,7 @@ const binarySearch = function (nums: number[], target: number): number { let i = 0, j = nums.length - 1; // 循环,当搜索区间为空时跳出(当 i > j 时为空) while (i <= j) { - let m = Math.floor(i + (j - i) / 2); // 计算中点索引 m + const m = Math.floor(i + (j - i) / 2); // 计算中点索引 m if (nums[m] < target) { // 此情况说明 target 在区间 [m+1, j] 中 i = m + 1; } else if (nums[m] > target) { // 此情况说明 target 在区间 [i, m-1] 中 diff --git a/docs/chapter_searching/binary_search.md b/docs/chapter_searching/binary_search.md index a04b9515..35d6a321 100644 --- a/docs/chapter_searching/binary_search.md +++ b/docs/chapter_searching/binary_search.md @@ -167,12 +167,12 @@ $$ let i = 0, j = nums.length - 1; // 循环,当搜索区间为空时跳出(当 i > j 时为空) while (i <= j) { - let m = Math.floor(i + (j - i) / 2);// 计算中点索引 m - if (nums[m] < target) { // 此情况说明 target 在区间 [m+1, j] 中 + const m = Math.floor(i + (j - i) / 2); // 计算中点索引 m + if (nums[m] < target) { // 此情况说明 target 在区间 [m+1, j] 中 i = m + 1; - } else if (nums[m] > target) { // 此情况说明 target 在区间 [i, m-1] 中 + } else if (nums[m] > target) { // 此情况说明 target 在区间 [i, m-1] 中 j = m - 1; - } else { // 找到目标元素,返回其索引 + } else { // 找到目标元素,返回其索引 return m; } } @@ -224,9 +224,9 @@ $$ // 循环,当搜索区间为空时跳出(当 i = j 时为空) while (i < j) { int m = (i + j) / 2; // 计算中点索引 m - if (nums[m] < target) // 此情况说明 target 在区间 [m+1, j) 中 + if (nums[m] < target) // 此情况说明 target 在区间 [m+1, j] 中 i = m + 1; - else if (nums[m] > target) // 此情况说明 target 在区间 [i, m) 中 + else if (nums[m] > target) // 此情况说明 target 在区间 [i, m] 中 j = m; else // 找到目标元素,返回其索引 return m; @@ -246,9 +246,9 @@ $$ // 循环,当搜索区间为空时跳出(当 i = j 时为空) while (i < j) { int m = (i + j) / 2; // 计算中点索引 m - if (nums[m] < target) // 此情况说明 target 在区间 [m+1, j) 中 + if (nums[m] < target) // 此情况说明 target 在区间 [m+1, j] 中 i = m + 1; - else if (nums[m] > target) // 此情况说明 target 在区间 [i, m) 中 + else if (nums[m] > target) // 此情况说明 target 在区间 [i, m] 中 j = m; else // 找到目标元素,返回其索引 return m; @@ -268,9 +268,9 @@ $$ # 循环,当搜索区间为空时跳出(当 i = j 时为空) while i < j: m = (i + j) // 2 # 计算中点索引 m - if nums[m] < target: # 此情况说明 target 在区间 [m+1, j) 中 + if nums[m] < target: # 此情况说明 target 在区间 [m+1, j] 中 i = m + 1 - elif nums[m] > target: # 此情况说明 target 在区间 [i, m) 中 + elif nums[m] > target: # 此情况说明 target 在区间 [i, m] 中 j = m else: # 找到目标元素,返回其索引 return m @@ -287,9 +287,9 @@ $$ // 循环,当搜索区间为空时跳出(当 i = j 时为空) for i < j { m := (i + j) / 2 // 计算中点索引 m - if nums[m] < target { // 此情况说明 target 在区间 [m+1, j) 中 + if nums[m] < target { // 此情况说明 target 在区间 [m+1, j] 中 i = m + 1 - } else if nums[m] > target { // 此情况说明 target 在区间 [i, m) 中 + } else if nums[m] > target { // 此情况说明 target 在区间 [i, m] 中 j = m } else { // 找到目标元素,返回其索引 return m @@ -310,9 +310,9 @@ $$ // 循环,当搜索区间为空时跳出(当 i = j 时为空) while (i < j) { let m = parseInt((i + j) / 2); // 计算中点索引 m ,在 JS 中需使用 parseInt 函数取整 - if (nums[m] < target) // 此情况说明 target 在区间 [m+1, j) 中 + if (nums[m] < target) // 此情况说明 target 在区间 [m+1, j] 中 i = m + 1; - else if (nums[m] > target) // 此情况说明 target 在区间 [i, m) 中 + else if (nums[m] > target) // 此情况说明 target 在区间 [i, m] 中 j = m; else // 找到目标元素,返回其索引 return m; @@ -331,12 +331,12 @@ $$ let i = 0, j = nums.length; // 循环,当搜索区间为空时跳出(当 i = j 时为空) while (i < j) { - let m = Math.floor(i + (j - i) / 2);// 计算中点索引 m - if (nums[m] < target) { // 此情况说明 target 在区间 [m+1, j) 中 + const m = Math.floor(i + (j - i) / 2); // 计算中点索引 m + if (nums[m] < target) { // 此情况说明 target 在区间 [m+1, j] 中 i = m + 1; - } else if (nums[m] > target) { // 此情况说明 target 在区间 [i, m) 中 + } else if (nums[m] > target) { // 此情况说明 target 在区间 [i, m] 中 j = m; - } else { // 找到目标元素,返回其索引 + } else { // 找到目标元素,返回其索引 return m; } } @@ -362,9 +362,9 @@ $$ while (i < j) { int m = (i + j) / 2; // 计算中点索引 m - if (nums[m] < target) // 此情况说明 target 在区间 [m+1, j) 中 + if (nums[m] < target) // 此情况说明 target 在区间 [m+1, j] 中 i = m + 1; - else if (nums[m] > target) // 此情况说明 target 在区间 [i, m) 中 + else if (nums[m] > target) // 此情况说明 target 在区间 [i, m] 中 j = m; else // 找到目标元素,返回其索引 return m; From 8e9bfabae2804568a5ae80b0ea9b35d1aabb4f4e Mon Sep 17 00:00:00 2001 From: Yudong Jin Date: Tue, 27 Dec 2022 17:10:23 +0800 Subject: [PATCH 32/43] Fix binary search tree. --- docs/chapter_tree/binary_search_tree.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/chapter_tree/binary_search_tree.md b/docs/chapter_tree/binary_search_tree.md index c2551e74..f33294bf 100644 --- a/docs/chapter_tree/binary_search_tree.md +++ b/docs/chapter_tree/binary_search_tree.md @@ -761,14 +761,14 @@ comments: true - **查找元素:** 由于数组是无序的,因此需要遍历数组来确定,使用 $O(n)$ 时间; - **插入元素:** 只需将元素添加至数组尾部即可,使用 $O(1)$ 时间; -- **删除元素:** 先查找元素,使用 $O(\log n)$ 时间,再在数组中删除该元素,使用 $O(n)$ 时间; +- **删除元素:** 先查找元素,使用 $O(n)$ 时间,再在数组中删除该元素,使用 $O(n)$ 时间; - **获取最小 / 最大元素:** 需要遍历数组来确定,使用 $O(n)$ 时间; 为了得到先验信息,我们也可以预先将数组元素进行排序,得到一个「排序数组」,此时操作效率为: -- **查找元素:** 由于数组已排序,可以使用二分查找,使用 $O(\log n)$ 时间; -- **插入元素:** 为了保持数组是有序的,需插入到数组某位置,平均使用 $O(n)$ 时间; -- **删除元素:** 与无序数组中的情况相同,使用 $O(n)$ 时间; +- **查找元素:** 由于数组已排序,可以使用二分查找,平均使用 $O(\log n)$ 时间; +- **插入元素:** 先查找插入位置,使用 $O(\log n)$ 时间,再插入到指定位置,使用 $O(n)$ 时间; +- **删除元素:** 先查找元素,使用 $O(\log n)$ 时间,再在数组中删除该元素,使用 $O(n)$ 时间; - **获取最小 / 最大元素:** 数组头部和尾部元素即是最小和最大元素,使用 $O(1)$ 时间; 观察发现,无序数组和有序数组中的各项操作的时间复杂度是“偏科”的,即有的快有的慢;**而二叉搜索树的各项操作的时间复杂度都是对数阶,在数据量 $n$ 很大时有巨大优势**。 From 8b401c2acbd11b637fa0d413b64dc5b07c3b8882 Mon Sep 17 00:00:00 2001 From: a16su <33782391+a16su@users.noreply.github.com> Date: Tue, 27 Dec 2022 18:34:12 +0800 Subject: [PATCH 33/43] fix format error --- codes/python/chapter_tree/avl_tree.py | 159 +++++--------- .../python/chapter_tree/binary_search_tree.py | 76 +++---- codes/python/chapter_tree/binary_tree.py | 4 +- codes/python/chapter_tree/binary_tree_bfs.py | 21 +- codes/python/chapter_tree/binary_tree_dfs.py | 60 +++--- codes/python/include/binary_tree.py | 16 +- docs/chapter_tree/avl_tree.md | 194 ++++++------------ docs/chapter_tree/binary_search_tree.md | 35 ++-- docs/chapter_tree/binary_tree.md | 46 +++-- 9 files changed, 248 insertions(+), 363 deletions(-) diff --git a/codes/python/chapter_tree/avl_tree.py b/codes/python/chapter_tree/avl_tree.py index 4e6e3572..20cad94b 100644 --- a/codes/python/chapter_tree/avl_tree.py +++ b/codes/python/chapter_tree/avl_tree.py @@ -1,3 +1,9 @@ +""" +File: avl_tree.py +Created Time: 2022-12-20 +Author: a16su (lpluls001@gmail.com) +""" + import sys, os.path as osp import typing @@ -5,75 +11,36 @@ sys.path.append(osp.dirname(osp.dirname(osp.abspath(__file__)))) from include import * -class AVLTreeNode: - def __init__( - self, - val=None, - height: int = 0, - left: typing.Optional["AVLTreeNode"] = None, - right: typing.Optional["AVLTreeNode"] = None, - ): - self.val = val - self.height = height - self.left = left - self.right = right - - def __str__(self): - val = self.val - left_val = self.left.val if self.left else None - right_val = self.right.val if self.right else None - return "".format( - val, left_val, right_val - ) - - class AVLTree: - def __init__(self, root: typing.Optional[AVLTreeNode] = None): + def __init__(self, root: typing.Optional[TreeNode] = None): self.root = root - @staticmethod - def height(node: typing.Optional[AVLTreeNode]) -> int: - """ - 获取结点高度 - Args: - node:起始结点 + """ 获取结点高度 """ - Returns: 高度 or -1 - - """ + def height(self, node: typing.Optional[TreeNode]) -> int: # 空结点高度为 -1 ,叶结点高度为 0 if node is not None: return node.height return -1 - def __update_height(self, node: AVLTreeNode): - """ - 更新结点高度 - Args: - node: 要更新高度的结点 + """ 更新结点高度 """ - Returns: None - - """ + def __update_height(self, node: TreeNode): # 结点高度等于最高子树高度 + 1 node.height = max([self.height(node.left), self.height(node.right)]) + 1 - def balance_factor(self, node: AVLTreeNode) -> int: - """ - 获取结点平衡因子 - Args: - node: 要获取平衡因子的结点 + """ 获取平衡因子 """ - Returns: 平衡因子 - - """ + def balance_factor(self, node: TreeNode) -> int: # 空结点平衡因子为 0 if node is None: return 0 # 结点平衡因子 = 左子树高度 - 右子树高度 return self.height(node.left) - self.height(node.right) - def __right_rotate(self, node: AVLTreeNode) -> AVLTreeNode: + """ 右旋操作 """ + + def __right_rotate(self, node: TreeNode) -> TreeNode: child = node.left grand_child = child.right # 以 child 为原点,将 node 向右旋转 @@ -85,7 +52,9 @@ class AVLTree: # 返回旋转后子树的根节点 return child - def __left_rotate(self, node: AVLTreeNode) -> AVLTreeNode: + """ 左旋操作 """ + + def __left_rotate(self, node: TreeNode) -> TreeNode: child = node.right grand_child = child.left # 以 child 为原点,将 node 向左旋转 @@ -97,15 +66,9 @@ class AVLTree: # 返回旋转后子树的根节点 return child - def rotate(self, node: AVLTreeNode): - """ - 执行旋转操作,使该子树重新恢复平衡 - Args: - node: 要旋转的根结点 + """ 执行旋转操作,使该子树重新恢复平衡 """ - Returns: 旋转后的根结点 - - """ + def __rotate(self, node: TreeNode) -> TreeNode: # 获取结点 node 的平衡因子 balance_factor = self.balance_factor(node) # 左偏树 @@ -129,76 +92,46 @@ class AVLTree: # 平衡树,无需旋转,直接返回 return node - def insert(self, val) -> AVLTreeNode: - """ - 插入结点 - Args: - val: 结点的值 + """ 插入结点 """ - Returns: - node: 插入结点后的根结点 - """ - self.root = self.insert_helper(self.root, val) + def insert(self, val) -> TreeNode: + self.root = self.__insert_helper(self.root, val) return self.root - def insert_helper( - self, node: typing.Optional[AVLTreeNode], val: int - ) -> AVLTreeNode: - """ - 递归插入结点(辅助函数) - Args: - node: 要插入的根结点 - val: 要插入的结点的值 + """ 递归插入结点(辅助函数)""" - Returns: 插入结点后的根结点 - - """ + def __insert_helper(self, node: typing.Optional[TreeNode], val: int) -> TreeNode: if node is None: - return AVLTreeNode(val) + return TreeNode(val) # 1. 查找插入位置,并插入结点 if val < node.val: - node.left = self.insert_helper(node.left, val) + node.left = self.__insert_helper(node.left, val) elif val > node.val: - node.right = self.insert_helper(node.right, val) + node.right = self.__insert_helper(node.right, val) else: # 重复结点不插入,直接返回 return node # 更新结点高度 self.__update_height(node) # 2. 执行旋转操作,使该子树重新恢复平衡 - return self.rotate(node) + return self.__rotate(node) + + """ 删除结点 """ def remove(self, val: int): - """ - 删除结点 - Args: - val: 要删除的结点的值 - - Returns: - - """ - root = self.remove_helper(self.root, val) + root = self.__remove_helper(self.root, val) return root - def remove_helper( - self, node: typing.Optional[AVLTreeNode], val: int - ) -> typing.Optional[AVLTreeNode]: - """ - 递归删除结点(辅助函数) - Args: - node: 删除的起始结点 - val: 要删除的结点的值 + """ 递归删除结点(辅助函数) """ - Returns: 删除目标结点后的起始结点 - - """ + def __remove_helper(self, node: typing.Optional[TreeNode], val: int) -> typing.Optional[TreeNode]: if node is None: return None # 1. 查找结点,并删除之 if val < node.val: - node.left = self.remove_helper(node.left, val) + node.left = self.__remove_helper(node.left, val) elif val > node.val: - node.right = self.remove_helper(node.right, 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 @@ -210,17 +143,16 @@ class AVLTree: node = child else: # 子结点数量 = 2 ,则将中序遍历的下个结点删除,并用该结点替换当前结点 temp = self.min_node(node.right) - node.right = self.remove_helper(node.right, temp.val) + node.right = self.__remove_helper(node.right, temp.val) node.val = temp.val # 更新结点高度 self.__update_height(node) # 2. 执行旋转操作,使该子树重新恢复平衡 - return self.rotate(node) + return self.__rotate(node) - def min_node( - self, node: typing.Optional[AVLTreeNode] - ) -> typing.Optional[AVLTreeNode]: - # 获取最小结点 + """ 获取最小结点 """ + + def min_node(self, node: typing.Optional[TreeNode]) -> typing.Optional[TreeNode]: if node is None: return None # 循环访问左子结点,直到叶结点时为最小结点,跳出 @@ -228,15 +160,22 @@ class AVLTree: node = node.left return node + """ 查找结点 """ + def search(self, val: int): cur = self.root + # 循环查找,越过叶结点后跳出 while cur is not None: + # 目标结点在 root 的右子树中 if cur.val < val: cur = cur.right + # 目标结点在 root 的左子树中 elif cur.val > val: cur = cur.left + # 找到目标结点,跳出循环 else: break + # 返回目标结点 return cur diff --git a/codes/python/chapter_tree/binary_search_tree.py b/codes/python/chapter_tree/binary_search_tree.py index 211e7c0d..2123252c 100644 --- a/codes/python/chapter_tree/binary_search_tree.py +++ b/codes/python/chapter_tree/binary_search_tree.py @@ -1,43 +1,46 @@ """ File: binary_search_tree.py -Created Time: 2022-11-25 -Author: Krahets (krahets@163.com) +Created Time: 2022-12-20 +Author: a16su (lpluls001@gmail.com) """ import sys, os.path as osp +import typing sys.path.append(osp.dirname(osp.dirname(osp.abspath(__file__)))) from include import * +""" 二叉搜索树 """ + + class BinarySearchTree: - """ - 二叉搜索树 - """ - - def __init__(self, nums) -> None: + def __init__(self, nums: typing.List[int]) -> None: nums.sort() - self.__root = self.buildTree(nums, 0, len(nums) - 1) + self.__root = self.build_tree(nums, 0, len(nums) - 1) - def buildTree(self, nums, start_index, end_index): + """ 构建二叉搜索树 """ + + def build_tree(self, nums: typing.List[int], start_index: int, end_index: int) -> typing.Optional[TreeNode]: if start_index > end_index: return None + + # 将数组中间结点作为根结点 mid = (start_index + end_index) // 2 root = TreeNode(nums[mid]) - root.left = self.buildTree( - nums=nums, start_index=start_index, end_index=mid - 1 - ) - root.right = self.buildTree(nums=nums, start_index=mid + 1, end_index=end_index) + # 递归建立左子树和右子树 + root.left = self.build_tree(nums=nums, start_index=start_index, end_index=mid - 1) + root.right = self.build_tree(nums=nums, start_index=mid + 1, end_index=end_index) return root - def get_root(self): + @property + def root(self) -> typing.Optional[TreeNode]: return self.__root - def search(self, num): - """ - 查找结点 - """ - cur = self.get_root() + """ 查找结点 """ + + def search(self, num: int) -> typing.Optional[TreeNode]: + cur = self.root # 循环查找,越过叶结点后跳出 while cur is not None: # 目标结点在 root 的右子树中 @@ -51,11 +54,10 @@ class BinarySearchTree: break return cur - def insert(self, num): - """ - 插入结点 - """ - root = self.get_root() + """ 插入结点 """ + + def insert(self, num: int) -> typing.Optional[TreeNode]: + root = self.root # 若树为空,直接提前返回 if root is None: return None @@ -83,11 +85,10 @@ class BinarySearchTree: pre.left = node return node - def remove(self, num): - """ - 删除结点 - """ - root = self.get_root() + """ 删除结点 """ + + def remove(self, num: int) -> typing.Optional[TreeNode]: + root = self.root # 若树为空,直接提前返回 if root is None: return None @@ -130,10 +131,9 @@ class BinarySearchTree: cur.val = tmp return cur - def min(self, root): - """ - 获取最小结点 - """ + """ 获取最小结点 """ + + def min(self, root: typing.Optional[TreeNode]) -> typing.Optional[TreeNode]: if root is None: return root @@ -148,7 +148,7 @@ if __name__ == "__main__": nums = list(range(1, 16)) bst = BinarySearchTree(nums=nums) print("\n初始化的二叉树为\n") - print_tree(bst.get_root()) + print_tree(bst.root) # 查找结点 node = bst.search(5) @@ -157,17 +157,17 @@ if __name__ == "__main__": # 插入结点 ndoe = bst.insert(16) print("\n插入结点 16 后,二叉树为\n") - print_tree(bst.get_root()) + print_tree(bst.root) # 删除结点 bst.remove(1) print("\n删除结点 1 后,二叉树为\n") - print_tree(bst.get_root()) + print_tree(bst.root) bst.remove(2) print("\n删除结点 2 后,二叉树为\n") - print_tree(bst.get_root()) + print_tree(bst.root) bst.remove(4) print("\n删除结点 4 后,二叉树为\n") - print_tree(bst.get_root()) + print_tree(bst.root) diff --git a/codes/python/chapter_tree/binary_tree.py b/codes/python/chapter_tree/binary_tree.py index 2a892fae..b1d8a13e 100644 --- a/codes/python/chapter_tree/binary_tree.py +++ b/codes/python/chapter_tree/binary_tree.py @@ -1,7 +1,7 @@ """ File: binary_tree.py -Created Time: 2022-11-25 -Author: Krahets (krahets@163.com) +Created Time: 2022-12-20 +Author: a16su (lpluls001@gmail.com) """ import sys, os.path as osp diff --git a/codes/python/chapter_tree/binary_tree_bfs.py b/codes/python/chapter_tree/binary_tree_bfs.py index 57d15f91..d7865b6f 100644 --- a/codes/python/chapter_tree/binary_tree_bfs.py +++ b/codes/python/chapter_tree/binary_tree_bfs.py @@ -1,17 +1,22 @@ """ File: binary_tree_bfs.py -Created Time: 2022-11-25 -Author: Krahets (krahets@163.com) +Created Time: 2022-12-20 +Author: a16su (lpluls001@gmail.com) """ import sys, os.path as osp +import typing + sys.path.append(osp.dirname(osp.dirname(osp.abspath(__file__)))) from include import * -def hierOrder(root): +""" 层序遍历 """ + + +def hier_order(root: TreeNode): # 初始化队列,加入根结点 - queue = collections.deque() + queue: typing.Deque[TreeNode] = collections.deque() queue.append(root) # 初始化一个列表,用于保存遍历序列 result = [] @@ -33,13 +38,11 @@ def hierOrder(root): if __name__ == "__main__": # 初始化二叉树 # 这里借助了一个从数组直接生成二叉树的函数 - root = list_to_tree( - arr=[1, 2, 3, 4, 5, 6, 7, None, None, None, None, None, None, None, None] - ) + root = list_to_tree(arr=[1, 2, 3, 4, 5, 6, 7, None, None, None, None, None, None, None, None]) print("\n初始化二叉树\n") print_tree(root) # 层序遍历 - result = hierOrder(root) + result = hier_order(root) print("\n层序遍历的结点打印序列 = ", result) - assert result == [1, 2, 3, 4, 5, 6, 7] \ No newline at end of file + assert result == [1, 2, 3, 4, 5, 6, 7] diff --git a/codes/python/chapter_tree/binary_tree_dfs.py b/codes/python/chapter_tree/binary_tree_dfs.py index 6c5b92a3..31b16055 100644 --- a/codes/python/chapter_tree/binary_tree_dfs.py +++ b/codes/python/chapter_tree/binary_tree_dfs.py @@ -1,10 +1,12 @@ """ File: binary_tree_dfs.py -Created Time: 2022-11-25 -Author: Krahets (krahets@163.com) +Created Time: 2022-12-20 +Author: a16su (lpluls001@gmail.com) """ import sys, os.path as osp +import typing + sys.path.append(osp.dirname(osp.dirname(osp.abspath(__file__)))) from include import * @@ -12,42 +14,42 @@ from include import * result = [] -def preOrder(root): - """ - 前序遍历二叉树 - """ +""" 前序遍历二叉树 """ + + +def pre_order(root: typing.Optional[TreeNode]): if root is None: return # 访问优先级:根结点 -> 左子树 -> 右子树 result.append(root.val) - preOrder(root=root.left) - preOrder(root=root.right) + pre_order(root=root.left) + pre_order(root=root.right) -def inOrder(root): - """ - 中序遍历二叉树 - """ +""" 中序遍历二叉树 """ + + +def in_order(root: typing.Optional[TreeNode]): if root is None: return # 访问优先级:左子树 -> 根结点 -> 右子树 - inOrder(root=root.left) + in_order(root=root.left) result.append(root.val) - inOrder(root=root.right) + in_order(root=root.right) -def postOrder(root): - """ - 后序遍历二叉树 - """ +""" 后序遍历二叉树 """ + + +def post_order(root: typing.Optional[TreeNode]): if root is None: return # 访问优先级:左子树 -> 右子树 -> 根结点 - postOrder(root=root.left) - postOrder(root=root.right) + post_order(root=root.left) + post_order(root=root.right) result.append(root.val) @@ -55,26 +57,24 @@ def postOrder(root): if __name__ == "__main__": # 初始化二叉树 # 这里借助了一个从数组直接生成二叉树的函数 - root = list_to_tree( - arr=[1, 2, 3, 4, 5, 6, 7, None, None, None, None, None, None, None, None] - ) + root = list_to_tree(arr=[1, 2, 3, 4, 5, 6, 7, None, None, None, None, None, None, None, None]) print("\n初始化二叉树\n") print_tree(root) # 前序遍历 - result = [] - preOrder(root) + result.clear() + pre_order(root) print("\n前序遍历的结点打印序列 = ", result) assert result == [1, 2, 4, 5, 3, 6, 7] # 中序遍历 - result = [] - inOrder(root) + result.clear() + in_order(root) print("\n中序遍历的结点打印序列 = ", result) assert result == [4, 2, 5, 1, 6, 3, 7] # 后序遍历 - result = [] - postOrder(root) + result.clear() + post_order(root) print("\n后序遍历的结点打印序列 = ", result) - assert result == [4, 5, 2, 6, 7, 3, 1] \ No newline at end of file + assert result == [4, 5, 2, 6, 7, 3, 1] diff --git a/codes/python/include/binary_tree.py b/codes/python/include/binary_tree.py index bfe5b5f2..fe96f504 100644 --- a/codes/python/include/binary_tree.py +++ b/codes/python/include/binary_tree.py @@ -10,9 +10,19 @@ class TreeNode: """Definition for a binary tree node """ def __init__(self, val=None, left=None, right=None): - self.val = val - self.left = left - self.right = right + self.val = val # 结点值 + self.height = 0 # 结点高度, avl 树会用到 + self.left = left # 左子结点引用 + self.right = right # 右子结点引用 + + def __str__(self): # 直接print时会好看一点 + val = self.val + left_node_val = self.left.val if self.left else None + right_node_val = self.right.val if self.right else None + return "".format(val, left_node_val, right_node_val) + + __repr__ = __str__ + def list_to_tree(arr): """Generate a binary tree with a list diff --git a/docs/chapter_tree/avl_tree.md b/docs/chapter_tree/avl_tree.md index ef88975b..5f2cfb18 100644 --- a/docs/chapter_tree/avl_tree.md +++ b/docs/chapter_tree/avl_tree.md @@ -48,24 +48,21 @@ G. M. Adelson-Velsky 和 E. M. Landis 在其 1962 年发表的论文 "An algorit === "Python" ```python title="avl_tree.py" - class AVLTreeNode: - def __init__( - self, - val=None, - height: int = 0, - left: typing.Optional["AVLTreeNode"] = None, - right: typing.Optional["AVLTreeNode"] = None - ): - self.val = val - self.height = height - self.left = left - self.right = right + """ AVL 树结点类 """ + class TreeNode: + def __init__(self, val=None, left=None, right=None): + self.val = val # 结点值 + self.height = 0 # 结点高度, avl 树会用到 + self.left = left # 左子结点引用 + self.right = right # 右子结点引用 - def __str__(self): + def __str__(self): # 直接print时会好看一点 val = self.val - left_val = self.left.val if self.left else None - right_val = self.right.val if self.right else None - return "".format(val, left_val, right_val) + left_node_val = self.left.val if self.left else None + right_node_val = self.right.val if self.right else None + return "".format(val, left_node_val, right_node_val) + + __repr__ = __str__ ``` === "Go" @@ -125,31 +122,17 @@ G. M. Adelson-Velsky 和 E. M. Landis 在其 1962 年发表的论文 "An algorit === "Python" ```python title="avl_tree.py" - def height(node: typing.Optional[AVLTreeNode]) -> int: - """ - 获取结点高度 - Args: - node:起始结点 - - Returns: 高度 or -1 - - """ + """ 获取结点高度 """ + def height(self, node: typing.Optional[TreeNode]) -> int: # 空结点高度为 -1 ,叶结点高度为 0 if node is not None: return node.height return -1 - def update_height(node: AVLTreeNode): - """ - 更新结点高度 - Args: - node: 要更新高度的结点 - - Returns: None - - """ + """ 更新结点高度 """ + def __update_height(self, node: TreeNode): # 结点高度等于最高子树高度 + 1 - node.height = max([height(node.left), height(node.right)]) + 1 + node.height = max([self.height(node.left), self.height(node.right)]) + 1 ``` === "Go" @@ -207,20 +190,13 @@ G. M. Adelson-Velsky 和 E. M. Landis 在其 1962 年发表的论文 "An algorit === "Python" ```python title="avl_tree.py" - def balance_factor(node: AVLTreeNode) -> int: - """ - 获取结点平衡因子 - Args: - node: 要获取平衡因子的结点 - - Returns: 平衡因子 - - """ + """ 获取平衡因子 """ + def balance_factor(self, node: TreeNode) -> int: # 空结点平衡因子为 0 if node is None: return 0 # 结点平衡因子 = 左子树高度 - 右子树高度 - return height(node.left) - height(node.right) + return self.height(node.left) - self.height(node.right) ``` === "Go" @@ -309,15 +285,16 @@ AVL 树的独特之处在于「旋转 Rotation」的操作,其可 **在不影 === "Python" ```python title="avl_tree.py" - def rightRotate(node: AVLTreeNode): + """ 右旋操作 """ + def __right_rotate(self, node: TreeNode) -> TreeNode: child = node.left grand_child = child.right # 以 child 为原点,将 node 向右旋转 child.right = node node.left = grand_child # 更新结点高度 - update_height(node) - update_height(child) + self.__update_height(node) + self.__update_height(child) # 返回旋转后子树的根节点 return child ``` @@ -387,15 +364,16 @@ AVL 树的独特之处在于「旋转 Rotation」的操作,其可 **在不影 === "Python" ```python title="avl_tree.py" - def leftRotate(node: AVLTreeNode): + """ 左旋操作 """ + def __left_rotate(self, node: TreeNode) -> TreeNode: child = node.right grand_child = child.left # 以 child 为原点,将 node 向左旋转 child.left = node node.right = grand_child # 更新结点高度 - update_height(node) - update_height(child) + self.__update_height(node) + self.__update_height(child) # 返回旋转后子树的根节点 return child ``` @@ -506,35 +484,28 @@ AVL 树的独特之处在于「旋转 Rotation」的操作,其可 **在不影 === "Python" ```python title="avl_tree.py" - def rotate(node: AVLTreeNode): - """ - 执行旋转操作,使该子树重新恢复平衡 - Args: - node: 要旋转的根结点 - - Returns: 旋转后的根结点 - - """ + """ 执行旋转操作,使该子树重新恢复平衡 """ + def __rotate(self, node: TreeNode) -> TreeNode: # 获取结点 node 的平衡因子 - factor = balance_factor(node) + balance_factor = self.balance_factor(node) # 左偏树 - if factor > 1: - if balance_factor(node.left) >= 0: + if balance_factor > 1: + if self.balance_factor(node.left) >= 0: # 右旋 - return right_rotate(node) + return self.__right_rotate(node) else: # 先左旋后右旋 - node.left = left_rotate(node.left) - return right_rotate(node) + node.left = self.__left_rotate(node.left) + return self.__right_rotate(node) # 右偏树 - elif factor < -1: - if balance_factor(node.right) <= 0: + elif balance_factor < -1: + if self.balance_factor(node.right) <= 0: # 左旋 - return left_rotate(node) + return self.__left_rotate(node) else: # 先右旋后左旋 - node.right = right_rotate(node.right) - return left_rotate(node) + node.right = self.__right_rotate(node.right) + return self.__left_rotate(node) # 平衡树,无需旋转,直接返回 return node ``` @@ -611,42 +582,27 @@ AVL 树的独特之处在于「旋转 Rotation」的操作,其可 **在不影 === "Python" ```python title="avl_tree.py" - def insert(val) -> AVLTreeNode: - """ - 插入结点 - Args: - val: 结点的值 + """ 插入结点 """ + def insert(self, val) -> TreeNode: + self.root = self.__insert_helper(self.root, val) + return self.root - Returns: - node: 插入结点后的根结点 - """ - root = insert_helper(root, val) - return root - - def insert_helper(node: typing.Optional[AVLTreeNode], val: int) -> AVLTreeNode: - """ - 递归插入结点(辅助函数) - Args: - node: 要插入的根结点 - val: 要插入的结点的值 - - Returns: 插入结点后的根结点 - - """ + """ 递归插入结点(辅助函数)""" + def __insert_helper(self, node: typing.Optional[TreeNode], val: int) -> TreeNode: if node is None: - return AVLTreeNode(val) + return TreeNode(val) # 1. 查找插入位置,并插入结点 if val < node.val: - node.left = insert_helper(node.left, val) + node.left = self.__insert_helper(node.left, val) elif val > node.val: - node.right = insert_helper(node.right, val) + node.right = self.__insert_helper(node.right, val) else: # 重复结点不插入,直接返回 return node # 更新结点高度 - update_height(node) + self.__update_height(node) # 2. 执行旋转操作,使该子树重新恢复平衡 - return rotate(node) + return self.__rotate(node) ``` === "Go" @@ -743,35 +699,20 @@ AVL 树的独特之处在于「旋转 Rotation」的操作,其可 **在不影 === "Python" ```python title="avl_tree.py" - def remove(val: int): - """ - 删除结点 - Args: - val: 要删除的结点的值 - - Returns: - - """ - root = remove_helper(root, val) + """ 删除结点 """ + def remove(self, val: int): + root = self.__remove_helper(self.root, val) return root - def remove_helper(node: typing.Optional[AVLTreeNode], val: int) -> typing.Optional[AVLTreeNode]: - """ - 递归删除结点(辅助函数) - Args: - node: 删除的起始结点 - val: 要删除的结点的值 - - Returns: 删除目标结点后的起始结点 - - """ + """ 递归删除结点(辅助函数) """ + def __remove_helper(self, node: typing.Optional[TreeNode], val: int) -> typing.Optional[TreeNode]: if node is None: return None # 1. 查找结点,并删除之 if val < node.val: - node.left = remove_helper(node.left, val) + node.left = self.__remove_helper(node.left, val) elif val > node.val: - node.right = remove_helper(node.right, 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 @@ -781,18 +722,17 @@ AVL 树的独特之处在于「旋转 Rotation」的操作,其可 **在不影 # 子结点数量 = 1 ,直接删除 node else: node = child - else: # 子结点数量 = 2 ,则将中序遍历的下个结点删除,并用该结点替换当前结点 - temp = min_node(node.right) - node.right = remove_helper(node.right, temp.val) + else: # 子结点数量 = 2 ,则将中序遍历的下个结点删除,并用该结点替换当前结点 + temp = self.min_node(node.right) + node.right = self.__remove_helper(node.right, temp.val) node.val = temp.val # 更新结点高度 - update_height(node) + self.__update_height(node) # 2. 执行旋转操作,使该子树重新恢复平衡 - return rotate(node) + return self.__rotate(node) - - def min_node(node: typing.Optional[AVLTreeNode]) -> typing.Optional[AVLTreeNode]: - # 获取最小结点 + """ 获取最小结点 """ + def min_node(self, node: typing.Optional[TreeNode]) -> typing.Optional[TreeNode]: if node is None: return None # 循环访问左子结点,直到叶结点时为最小结点,跳出 diff --git a/docs/chapter_tree/binary_search_tree.md b/docs/chapter_tree/binary_search_tree.md index a9328ddc..08d16e4e 100644 --- a/docs/chapter_tree/binary_search_tree.md +++ b/docs/chapter_tree/binary_search_tree.md @@ -82,11 +82,9 @@ comments: true === "Python" ```python title="binary_search_tree.py" - def search(self, num): - """ - 查找结点 - """ - cur = self.get_root() + """ 查找结点 """ + def search(self, num: int) -> typing.Optional[TreeNode]: + cur = self.root # 循环查找,越过叶结点后跳出 while cur is not None: # 目标结点在 root 的右子树中 @@ -99,7 +97,6 @@ comments: true else: break return cur - ``` === "Go" @@ -245,11 +242,9 @@ comments: true === "Python" ```python title="binary_search_tree.py" - def insert(self, num): - """ - 插入结点 - """ - root = self.get_root() + """ 插入结点 """ + def insert(self, num: int) -> typing.Optional[TreeNode]: + root = self.root # 若树为空,直接提前返回 if root is None: return None @@ -530,15 +525,13 @@ comments: true === "Python" ```python title="binary_search_tree.py" - def remove(self, num): - """ - 删除结点 - """ - root = self.get_root() + """ 删除结点 """ + def remove(self, num: int) -> typing.Optional[TreeNode]: + root = self.root # 若树为空,直接提前返回 if root is None: return None - + cur = root pre = None @@ -574,13 +567,11 @@ comments: true # 递归删除结点 nex self.remove(nex.val) # 将 nex 的值复制给 cur - cur.val = tmp + cur.val = tmp return cur - def min(self, root): - """ - 获取最小结点 - """ + """ 获取最小结点 """ + def min(self, root: typing.Optional[TreeNode]) -> typing.Optional[TreeNode]: if root is None: return root diff --git a/docs/chapter_tree/binary_tree.md b/docs/chapter_tree/binary_tree.md index ab67e6f8..d1e7774a 100644 --- a/docs/chapter_tree/binary_tree.md +++ b/docs/chapter_tree/binary_tree.md @@ -33,12 +33,19 @@ comments: true === "Python" ```python title="" + """ 链表结点类 """ class TreeNode: - """ 链表结点类 """ def __init__(self, val=None, left=None, right=None): self.val = val # 结点值 self.left = left # 左子结点指针 self.right = right # 右子结点指针 + + def __str__(self): + val = self.val + left_node_val = self.left.val if self.left else None + right_node_val = self.right.val if self.right else None + return "".format(val, left_node_val, right_node_val) + ``` === "Go" @@ -423,7 +430,8 @@ comments: true === "Python" ```python title="binary_tree_bfs.py" - def hierOrder(root): + """ 层序遍历 """ + def hier_order(root): # 初始化队列,加入根结点 queue = collections.deque() queue.append(root) @@ -612,42 +620,36 @@ comments: true === "Python" ```python title="binary_tree_dfs.py" - def preOrder(root): - """ - 前序遍历二叉树 - """ + """ 前序遍历二叉树 """ + def pre_order(root: typing.Optional[TreeNode]): if root is None: return - + # 访问优先级:根结点 -> 左子树 -> 右子树 result.append(root.val) - preOrder(root=root.left) - preOrder(root=root.right) + pre_order(root=root.left) + pre_order(root=root.right) - def inOrder(root): - """ - 中序遍历二叉树 - """ + """ 中序遍历二叉树 """ + def in_order(root: typing.Optional[TreeNode]): if root is None: return # 访问优先级:左子树 -> 根结点 -> 右子树 - inOrder(root=root.left) + in_order(root=root.left) result.append(root.val) - inOrder(root=root.right) + in_order(root=root.right) - def postOrder(root): - """ - 后序遍历二叉树 - """ + """ 后序遍历二叉树 """ + def post_order(root: typing.Optional[TreeNode]): if root is None: return - + # 访问优先级:左子树 -> 右子树 -> 根结点 - postOrder(root=root.left) - postOrder(root=root.right) + post_order(root=root.left) + post_order(root=root.right) result.append(root.val) ``` From dbb25003ec9fec74e015a9019be0588df67523db Mon Sep 17 00:00:00 2001 From: Yudong Jin Date: Tue, 27 Dec 2022 19:24:43 +0800 Subject: [PATCH 34/43] Fine tune --- codes/python/chapter_tree/avl_tree.py | 18 +++--------------- .../python/chapter_tree/binary_search_tree.py | 8 +------- codes/python/chapter_tree/binary_tree.py | 3 +++ codes/python/chapter_tree/binary_tree_bfs.py | 2 -- codes/python/chapter_tree/binary_tree_dfs.py | 6 ------ 5 files changed, 7 insertions(+), 30 deletions(-) diff --git a/codes/python/chapter_tree/avl_tree.py b/codes/python/chapter_tree/avl_tree.py index 20cad94b..d0ff48cb 100644 --- a/codes/python/chapter_tree/avl_tree.py +++ b/codes/python/chapter_tree/avl_tree.py @@ -16,7 +16,6 @@ class AVLTree: self.root = root """ 获取结点高度 """ - def height(self, node: typing.Optional[TreeNode]) -> int: # 空结点高度为 -1 ,叶结点高度为 0 if node is not None: @@ -24,13 +23,11 @@ class AVLTree: return -1 """ 更新结点高度 """ - def __update_height(self, node: TreeNode): # 结点高度等于最高子树高度 + 1 node.height = max([self.height(node.left), self.height(node.right)]) + 1 """ 获取平衡因子 """ - def balance_factor(self, node: TreeNode) -> int: # 空结点平衡因子为 0 if node is None: @@ -39,7 +36,6 @@ class AVLTree: return self.height(node.left) - self.height(node.right) """ 右旋操作 """ - def __right_rotate(self, node: TreeNode) -> TreeNode: child = node.left grand_child = child.right @@ -53,7 +49,6 @@ class AVLTree: return child """ 左旋操作 """ - def __left_rotate(self, node: TreeNode) -> TreeNode: child = node.right grand_child = child.left @@ -67,7 +62,6 @@ class AVLTree: return child """ 执行旋转操作,使该子树重新恢复平衡 """ - def __rotate(self, node: TreeNode) -> TreeNode: # 获取结点 node 的平衡因子 balance_factor = self.balance_factor(node) @@ -93,13 +87,11 @@ class AVLTree: return node """ 插入结点 """ - def insert(self, val) -> TreeNode: self.root = self.__insert_helper(self.root, val) return self.root """ 递归插入结点(辅助函数)""" - def __insert_helper(self, node: typing.Optional[TreeNode], val: int) -> TreeNode: if node is None: return TreeNode(val) @@ -117,13 +109,11 @@ class AVLTree: return self.__rotate(node) """ 删除结点 """ - def remove(self, val: int): root = self.__remove_helper(self.root, val) return root """ 递归删除结点(辅助函数) """ - def __remove_helper(self, node: typing.Optional[TreeNode], val: int) -> typing.Optional[TreeNode]: if node is None: return None @@ -142,7 +132,7 @@ class AVLTree: else: node = child else: # 子结点数量 = 2 ,则将中序遍历的下个结点删除,并用该结点替换当前结点 - temp = self.min_node(node.right) + temp = self.__min_node(node.right) node.right = self.__remove_helper(node.right, temp.val) node.val = temp.val # 更新结点高度 @@ -151,8 +141,7 @@ class AVLTree: return self.__rotate(node) """ 获取最小结点 """ - - def min_node(self, node: typing.Optional[TreeNode]) -> typing.Optional[TreeNode]: + def __min_node(self, node: typing.Optional[TreeNode]) -> typing.Optional[TreeNode]: if node is None: return None # 循环访问左子结点,直到叶结点时为最小结点,跳出 @@ -161,7 +150,6 @@ class AVLTree: return node """ 查找结点 """ - def search(self, val: int): cur = self.root # 循环查找,越过叶结点后跳出 @@ -179,8 +167,8 @@ class AVLTree: return cur +""" Driver Code """ if __name__ == "__main__": - def test_insert(tree: AVLTree, val: int): tree.insert(val) print("\n插入结点 {} 后,AVL 树为".format(val)) diff --git a/codes/python/chapter_tree/binary_search_tree.py b/codes/python/chapter_tree/binary_search_tree.py index 2123252c..23e34185 100644 --- a/codes/python/chapter_tree/binary_search_tree.py +++ b/codes/python/chapter_tree/binary_search_tree.py @@ -12,15 +12,12 @@ from include import * """ 二叉搜索树 """ - - class BinarySearchTree: def __init__(self, nums: typing.List[int]) -> None: nums.sort() self.__root = self.build_tree(nums, 0, len(nums) - 1) """ 构建二叉搜索树 """ - def build_tree(self, nums: typing.List[int], start_index: int, end_index: int) -> typing.Optional[TreeNode]: if start_index > end_index: return None @@ -38,7 +35,6 @@ class BinarySearchTree: return self.__root """ 查找结点 """ - def search(self, num: int) -> typing.Optional[TreeNode]: cur = self.root # 循环查找,越过叶结点后跳出 @@ -55,7 +51,6 @@ class BinarySearchTree: return cur """ 插入结点 """ - def insert(self, num: int) -> typing.Optional[TreeNode]: root = self.root # 若树为空,直接提前返回 @@ -86,7 +81,6 @@ class BinarySearchTree: return node """ 删除结点 """ - def remove(self, num: int) -> typing.Optional[TreeNode]: root = self.root # 若树为空,直接提前返回 @@ -132,7 +126,6 @@ class BinarySearchTree: return cur """ 获取最小结点 """ - def min(self, root: typing.Optional[TreeNode]) -> typing.Optional[TreeNode]: if root is None: return root @@ -143,6 +136,7 @@ class BinarySearchTree: return root +""" Driver Code """ if __name__ == "__main__": # 初始化二叉搜索树 nums = list(range(1, 16)) diff --git a/codes/python/chapter_tree/binary_tree.py b/codes/python/chapter_tree/binary_tree.py index b1d8a13e..2b25e472 100644 --- a/codes/python/chapter_tree/binary_tree.py +++ b/codes/python/chapter_tree/binary_tree.py @@ -23,6 +23,7 @@ if __name__ == "__main__": n1.right = n3 n2.left = n4 n2.right = n5 + print("\n初始化二叉树\n") print_tree(n1) # 插入与删除结点 @@ -31,8 +32,10 @@ if __name__ == "__main__": # 在 n1 -> n2 中间插入节点 P n1.left = P P.left = n2 + print("\n插入结点 P 后\n") print_tree(n1) # 删除结点 n1.left = n2 + print("\n删除结点 P 后\n"); print_tree(n1) diff --git a/codes/python/chapter_tree/binary_tree_bfs.py b/codes/python/chapter_tree/binary_tree_bfs.py index d7865b6f..c6a73013 100644 --- a/codes/python/chapter_tree/binary_tree_bfs.py +++ b/codes/python/chapter_tree/binary_tree_bfs.py @@ -12,8 +12,6 @@ from include import * """ 层序遍历 """ - - def hier_order(root: TreeNode): # 初始化队列,加入根结点 queue: typing.Deque[TreeNode] = collections.deque() diff --git a/codes/python/chapter_tree/binary_tree_dfs.py b/codes/python/chapter_tree/binary_tree_dfs.py index 31b16055..b5dc9c9f 100644 --- a/codes/python/chapter_tree/binary_tree_dfs.py +++ b/codes/python/chapter_tree/binary_tree_dfs.py @@ -15,8 +15,6 @@ result = [] """ 前序遍历二叉树 """ - - def pre_order(root: typing.Optional[TreeNode]): if root is None: return @@ -28,8 +26,6 @@ def pre_order(root: typing.Optional[TreeNode]): """ 中序遍历二叉树 """ - - def in_order(root: typing.Optional[TreeNode]): if root is None: return @@ -41,8 +37,6 @@ def in_order(root: typing.Optional[TreeNode]): """ 后序遍历二叉树 """ - - def post_order(root: typing.Optional[TreeNode]): if root is None: return From 449258f0b06fcb666f73bf4d6488f0de9be46942 Mon Sep 17 00:00:00 2001 From: Yudong Jin Date: Tue, 27 Dec 2022 19:33:58 +0800 Subject: [PATCH 35/43] Add the code to the docs. --- codes/cpp/chapter_tree/binary_tree_bfs.cpp | 8 +-- codes/python/chapter_tree/binary_tree.py | 7 ++- codes/python/chapter_tree/binary_tree_bfs.py | 24 ++++----- codes/python/chapter_tree/binary_tree_dfs.py | 38 ++++++-------- docs/chapter_tree/binary_tree.md | 6 +-- docs/chapter_tree/binary_tree_traversal.md | 52 +++++++++++++++++--- 6 files changed, 81 insertions(+), 54 deletions(-) diff --git a/codes/cpp/chapter_tree/binary_tree_bfs.cpp b/codes/cpp/chapter_tree/binary_tree_bfs.cpp index eeec2a18..30c2d600 100644 --- a/codes/cpp/chapter_tree/binary_tree_bfs.cpp +++ b/codes/cpp/chapter_tree/binary_tree_bfs.cpp @@ -15,12 +15,12 @@ vector hierOrder(TreeNode* root) { vector vec; while (!queue.empty()) { TreeNode* node = queue.front(); - queue.pop(); // 队列出队 - vec.push_back(node->val); // 保存结点 + queue.pop(); // 队列出队 + vec.push_back(node->val); // 保存结点 if (node->left != nullptr) - queue.push(node->left); // 左子结点入队 + queue.push(node->left); // 左子结点入队 if (node->right != nullptr) - queue.push(node->right); // 右子结点入队 + queue.push(node->right); // 右子结点入队 } return vec; } diff --git a/codes/python/chapter_tree/binary_tree.py b/codes/python/chapter_tree/binary_tree.py index 2b25e472..d9902635 100644 --- a/codes/python/chapter_tree/binary_tree.py +++ b/codes/python/chapter_tree/binary_tree.py @@ -12,13 +12,14 @@ from include import * """ Driver Code """ if __name__ == "__main__": - # 初始化二叉树 + """ 初始化二叉树 """ # 初始化节点 n1 = TreeNode(val=1) n2 = TreeNode(val=2) n3 = TreeNode(val=3) n4 = TreeNode(val=4) n5 = TreeNode(val=5) + # 构建引用指向(即指针) n1.left = n2 n1.right = n3 n2.left = n4 @@ -26,15 +27,13 @@ if __name__ == "__main__": print("\n初始化二叉树\n") print_tree(n1) - # 插入与删除结点 + """ 插入与删除结点 """ P = TreeNode(0) - # 在 n1 -> n2 中间插入节点 P n1.left = P P.left = n2 print("\n插入结点 P 后\n") print_tree(n1) - # 删除结点 n1.left = n2 print("\n删除结点 P 后\n"); diff --git a/codes/python/chapter_tree/binary_tree_bfs.py b/codes/python/chapter_tree/binary_tree_bfs.py index c6a73013..0320a08d 100644 --- a/codes/python/chapter_tree/binary_tree_bfs.py +++ b/codes/python/chapter_tree/binary_tree_bfs.py @@ -14,22 +14,18 @@ from include import * """ 层序遍历 """ def hier_order(root: TreeNode): # 初始化队列,加入根结点 - queue: typing.Deque[TreeNode] = collections.deque() + queue = collections.deque() queue.append(root) # 初始化一个列表,用于保存遍历序列 - result = [] + res = [] while queue: - # 队列出队 - node = queue.popleft() - # 保存节点值 - result.append(node.val) + node = queue.popleft() # 队列出队 + res.append(node.val) # 保存节点值 if node.left is not None: - # 左子结点入队 - queue.append(node.left) + queue.append(node.left) # 左子结点入队 if node.right is not None: - # 右子结点入队 - queue.append(node.right) - return result + queue.append(node.right) # 右子结点入队 + return res """ Driver Code """ @@ -41,6 +37,6 @@ if __name__ == "__main__": print_tree(root) # 层序遍历 - result = hier_order(root) - print("\n层序遍历的结点打印序列 = ", result) - assert result == [1, 2, 3, 4, 5, 6, 7] + res = hier_order(root) + print("\n层序遍历的结点打印序列 = ", res) + assert res == [1, 2, 3, 4, 5, 6, 7] diff --git a/codes/python/chapter_tree/binary_tree_dfs.py b/codes/python/chapter_tree/binary_tree_dfs.py index b5dc9c9f..11ee8339 100644 --- a/codes/python/chapter_tree/binary_tree_dfs.py +++ b/codes/python/chapter_tree/binary_tree_dfs.py @@ -11,40 +11,34 @@ sys.path.append(osp.dirname(osp.dirname(osp.abspath(__file__)))) from include import * -result = [] +res = [] - -""" 前序遍历二叉树 """ +""" 前序遍历 """ def pre_order(root: typing.Optional[TreeNode]): if root is None: return - # 访问优先级:根结点 -> 左子树 -> 右子树 - result.append(root.val) + res.append(root.val) pre_order(root=root.left) pre_order(root=root.right) - -""" 中序遍历二叉树 """ +""" 中序遍历 """ def in_order(root: typing.Optional[TreeNode]): if root is None: return - # 访问优先级:左子树 -> 根结点 -> 右子树 in_order(root=root.left) - result.append(root.val) + res.append(root.val) in_order(root=root.right) - -""" 后序遍历二叉树 """ +""" 后序遍历 """ def post_order(root: typing.Optional[TreeNode]): if root is None: return - # 访问优先级:左子树 -> 右子树 -> 根结点 post_order(root=root.left) post_order(root=root.right) - result.append(root.val) + res.append(root.val) """ Driver Code """ @@ -56,19 +50,19 @@ if __name__ == "__main__": print_tree(root) # 前序遍历 - result.clear() + res.clear() pre_order(root) - print("\n前序遍历的结点打印序列 = ", result) - assert result == [1, 2, 4, 5, 3, 6, 7] + print("\n前序遍历的结点打印序列 = ", res) + assert res == [1, 2, 4, 5, 3, 6, 7] # 中序遍历 - result.clear() + res.clear() in_order(root) - print("\n中序遍历的结点打印序列 = ", result) - assert result == [4, 2, 5, 1, 6, 3, 7] + print("\n中序遍历的结点打印序列 = ", res) + assert res == [4, 2, 5, 1, 6, 3, 7] # 后序遍历 - result.clear() + res.clear() post_order(root) - print("\n后序遍历的结点打印序列 = ", result) - assert result == [4, 5, 2, 6, 7, 3, 1] + print("\n后序遍历的结点打印序列 = ", res) + assert res == [4, 5, 2, 6, 7, 3, 1] diff --git a/docs/chapter_tree/binary_tree.md b/docs/chapter_tree/binary_tree.md index 92539cc8..262b170b 100644 --- a/docs/chapter_tree/binary_tree.md +++ b/docs/chapter_tree/binary_tree.md @@ -182,7 +182,7 @@ comments: true === "Python" ```python title="binary_tree.py" - # 初始化二叉树 + """ 初始化二叉树 """ # 初始化节点 n1 = TreeNode(val=1) n2 = TreeNode(val=2) @@ -302,7 +302,7 @@ comments: true === "Python" ```python title="binary_tree.py" - # 插入与删除结点 + """ 插入与删除结点 """ p = TreeNode(0) # 在 n1 -> n2 中间插入结点 P n1.left = p @@ -461,7 +461,7 @@ comments: true === "Python" ```python title="" - “”“ 二叉树的数组表示 ”“” + """ 二叉树的数组表示 """ # 直接使用 None 来表示空位 tree = [1, 2, 3, 4, None, 6, 7, 8, 9, None, None, 12, None, None, 15] ``` diff --git a/docs/chapter_tree/binary_tree_traversal.md b/docs/chapter_tree/binary_tree_traversal.md index 971d24cc..f4634841 100644 --- a/docs/chapter_tree/binary_tree_traversal.md +++ b/docs/chapter_tree/binary_tree_traversal.md @@ -51,12 +51,12 @@ comments: true vector vec; while (!queue.empty()) { TreeNode* node = queue.front(); - queue.pop(); // 队列出队 - vec.push_back(node->val); // 保存结点 + queue.pop(); // 队列出队 + vec.push_back(node->val); // 保存结点 if (node->left != nullptr) - queue.push(node->left); // 左子结点入队 + queue.push(node->left); // 左子结点入队 if (node->right != nullptr) - queue.push(node->right); // 右子结点入队 + queue.push(node->right); // 右子结点入队 } return vec; } @@ -65,7 +65,21 @@ comments: true === "Python" ```python title="binary_tree_bfs.py" - + """ 层序遍历 """ + def hier_order(root: 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 ``` === "Go" @@ -256,7 +270,32 @@ comments: true === "Python" ```python title="binary_tree_dfs.py" - + """ 前序遍历 """ + def pre_order(root: typing.Optional[TreeNode]): + if root is None: + return + # 访问优先级:根结点 -> 左子树 -> 右子树 + res.append(root.val) + pre_order(root=root.left) + pre_order(root=root.right) + + """ 中序遍历 """ + def in_order(root: typing.Optional[TreeNode]): + if root is None: + return + # 访问优先级:左子树 -> 根结点 -> 右子树 + in_order(root=root.left) + res.append(root.val) + in_order(root=root.right) + + """ 后序遍历 """ + def post_order(root: typing.Optional[TreeNode]): + if root is None: + return + # 访问优先级:左子树 -> 右子树 -> 根结点 + post_order(root=root.left) + post_order(root=root.right) + res.append(root.val) ``` === "Go" @@ -402,7 +441,6 @@ comments: true postOrder(root.right); list.Add(root.val); } - ``` !!! note From f9cc3a50cff45451eea9b973f4ffe06f232ce4a1 Mon Sep 17 00:00:00 2001 From: Yudong Jin Date: Tue, 27 Dec 2022 19:38:14 +0800 Subject: [PATCH 36/43] Fine tune --- codes/python/include/binary_tree.py | 10 +++++----- docs/chapter_tree/binary_tree.md | 7 ------- 2 files changed, 5 insertions(+), 12 deletions(-) diff --git a/codes/python/include/binary_tree.py b/codes/python/include/binary_tree.py index 1e2eb034..670fd18c 100644 --- a/codes/python/include/binary_tree.py +++ b/codes/python/include/binary_tree.py @@ -9,13 +9,13 @@ import collections class TreeNode: """Definition for a binary tree node """ - def __init__(self, val=None, left=None, right=None): - self.val = val # 结点值 - self.height = 0 # 结点高度, avl 树会用到 - self.left = left # 左子结点引用 + def __init__(self, val=0, left=None, right=None): + self.val = val # 结点值 + self.height = 0 # 结点高度 + self.left = left # 左子结点引用 self.right = right # 右子结点引用 - def __str__(self): # 直接print时会好看一点 + def __str__(self): val = self.val left_node_val = self.left.val if self.left else None right_node_val = self.right.val if self.right else None diff --git a/docs/chapter_tree/binary_tree.md b/docs/chapter_tree/binary_tree.md index 262b170b..4de1e4c1 100644 --- a/docs/chapter_tree/binary_tree.md +++ b/docs/chapter_tree/binary_tree.md @@ -39,13 +39,6 @@ comments: true self.val = val # 结点值 self.left = left # 左子结点指针 self.right = right # 右子结点指针 - - def __str__(self): - val = self.val - left_node_val = self.left.val if self.left else None - right_node_val = self.right.val if self.right else None - return "".format(val, left_node_val, right_node_val) - ``` === "Go" From 466fdd494bab4ec95d2fd172e598d560d78adfed Mon Sep 17 00:00:00 2001 From: Yudong Jin Date: Tue, 27 Dec 2022 19:42:39 +0800 Subject: [PATCH 37/43] Update the chapter tree. --- docs/chapter_tree/avl_tree.md | 14 +++----------- docs/chapter_tree/binary_tree.md | 4 ++-- 2 files changed, 5 insertions(+), 13 deletions(-) diff --git a/docs/chapter_tree/avl_tree.md b/docs/chapter_tree/avl_tree.md index bc449352..e9a656be 100644 --- a/docs/chapter_tree/avl_tree.md +++ b/docs/chapter_tree/avl_tree.md @@ -51,18 +51,10 @@ G. M. Adelson-Velsky 和 E. M. Landis 在其 1962 年发表的论文 "An algorit """ AVL 树结点类 """ class TreeNode: def __init__(self, val=None, left=None, right=None): - self.val = val # 结点值 - self.height = 0 # 结点高度, avl 树会用到 - self.left = left # 左子结点引用 + self.val = val # 结点值 + self.height = 0 # 结点高度 + self.left = left # 左子结点引用 self.right = right # 右子结点引用 - - def __str__(self): # 直接print时会好看一点 - val = self.val - left_node_val = self.left.val if self.left else None - right_node_val = self.right.val if self.right else None - return "".format(val, left_node_val, right_node_val) - - __repr__ = __str__ ``` === "Go" diff --git a/docs/chapter_tree/binary_tree.md b/docs/chapter_tree/binary_tree.md index 4de1e4c1..07e31155 100644 --- a/docs/chapter_tree/binary_tree.md +++ b/docs/chapter_tree/binary_tree.md @@ -44,13 +44,13 @@ comments: true === "Go" ```go title="" - """ 链表结点类 """ + // 链表结点类 type TreeNode struct { Val int Left *TreeNode Right *TreeNode } - """ 结点初始化方法 """ + // 结点初始化方法 func NewTreeNode(v int) *TreeNode { return &TreeNode{ Left: nil, From 34ad07bfed3b09accc30b5328a82e74865b5b7d5 Mon Sep 17 00:00:00 2001 From: Yudong Jin Date: Tue, 27 Dec 2022 20:11:22 +0800 Subject: [PATCH 38/43] Fine tune --- codes/c/chapter_sorting/bubble_sort.c | 2 ++ codes/cpp/chapter_sorting/bubble_sort.cpp | 10 ++++------ docs/chapter_sorting/bubble_sort.md | 6 ++++-- 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/codes/c/chapter_sorting/bubble_sort.c b/codes/c/chapter_sorting/bubble_sort.c index f59b81d0..6b67bd72 100644 --- a/codes/c/chapter_sorting/bubble_sort.c +++ b/codes/c/chapter_sorting/bubble_sort.c @@ -48,6 +48,8 @@ void bubble_sort_with_flag(int nums[], int size) } } + +/* Driver Code */ int main() { int nums[6] = {4, 1, 3, 1, 5, 2}; diff --git a/codes/cpp/chapter_sorting/bubble_sort.cpp b/codes/cpp/chapter_sorting/bubble_sort.cpp index 07182745..87ca305d 100644 --- a/codes/cpp/chapter_sorting/bubble_sort.cpp +++ b/codes/cpp/chapter_sorting/bubble_sort.cpp @@ -14,9 +14,8 @@ void bubbleSort(vector& nums) { for (int j = 0; j < i; j++) { if (nums[j] > nums[j + 1]) { // 交换 nums[j] 与 nums[j + 1] - int tmp = nums[j]; - nums[j] = nums[j + 1]; - nums[j + 1] = tmp; + // 这里使用了 std::swap() 函数 + swap(nums[j], nums[j + 1]); } } } @@ -31,9 +30,8 @@ void bubbleSortWithFlag(vector& nums) { for (int j = 0; j < i; j++) { if (nums[j] > nums[j + 1]) { // 交换 nums[j] 与 nums[j + 1] - int tmp = nums[j]; - nums[j] = nums[j + 1]; - nums[j + 1] = tmp; + // 这里使用了 std::swap() 函数 + swap(nums[j], nums[j + 1]); flag = true; // 记录交换元素 } } diff --git a/docs/chapter_sorting/bubble_sort.md b/docs/chapter_sorting/bubble_sort.md index f71dce77..336f3c2d 100644 --- a/docs/chapter_sorting/bubble_sort.md +++ b/docs/chapter_sorting/bubble_sort.md @@ -85,7 +85,8 @@ comments: true for (int j = 0; j < i; j++) { if (nums[j] > nums[j + 1]) { // 交换 nums[j] 与 nums[j + 1] - std::swap(nums[j], nums[j+1]); + // 这里使用了 std::swap() 函数 + swap(nums[j], nums[j + 1]); } } } @@ -265,7 +266,8 @@ comments: true for (int j = 0; j < i; j++) { if (nums[j] > nums[j + 1]) { // 交换 nums[j] 与 nums[j + 1] - std::swap(nums[j], nums[j+1]); + // 这里使用了 std::swap() 函数 + swap(nums[j], nums[j + 1]); flag = true; // 记录交换元素 } } From bd5cfb1117e52e8b81d1a29de454041df7388c9b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=BE=9A=E5=9B=BD=E7=8E=AE?= Date: Wed, 28 Dec 2022 12:29:29 +0800 Subject: [PATCH 39/43] docs(binary_tree): fix comment style and punctuation --- docs/chapter_tree/binary_tree.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/chapter_tree/binary_tree.md b/docs/chapter_tree/binary_tree.md index 07e31155..0c858fd3 100644 --- a/docs/chapter_tree/binary_tree.md +++ b/docs/chapter_tree/binary_tree.md @@ -44,13 +44,13 @@ comments: true === "Go" ```go title="" - // 链表结点类 + /* 链表结点类 */ type TreeNode struct { Val int Left *TreeNode Right *TreeNode } - // 结点初始化方法 + /* 结点初始化方法 */ func NewTreeNode(v int) *TreeNode { return &TreeNode{ Left: nil, @@ -121,7 +121,7 @@ comments: true - 「根结点 Root Node」:二叉树最顶层的结点,其没有父结点; - 「叶结点 Leaf Node」:没有子结点的结点,其两个指针都指向 $\text{null}$ ; - 结点所处「层 Level」:从顶置底依次增加,根结点所处层为 1 ; -- 结点「度 Degree」:结点的子结点数量,二叉树中度的范围是 0, 1, 2 ; +- 结点「度 Degree」:结点的子结点数量。二叉树中,度的范围是 0, 1, 2 ; - 「边 Edge」:连接两个结点的边,即结点指针; - 二叉树「高度」:二叉树中根结点到最远叶结点走过边的数量; - 结点「深度 Depth」 :根结点到该结点走过边的数量; From af5497e70bae154f295ba1d6ff7c02af34b765c9 Mon Sep 17 00:00:00 2001 From: XC-Zero <55583209+XC-Zero@users.noreply.github.com> Date: Wed, 28 Dec 2022 14:11:36 +0800 Subject: [PATCH 40/43] Update data_and_memory.md add code for go --- docs/chapter_data_structure/data_and_memory.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/docs/chapter_data_structure/data_and_memory.md b/docs/chapter_data_structure/data_and_memory.md index 78fcac85..b4c8fbe5 100644 --- a/docs/chapter_data_structure/data_and_memory.md +++ b/docs/chapter_data_structure/data_and_memory.md @@ -74,7 +74,11 @@ comments: true === "Go" ```go title="" - + var numbers =[5]int{} + var decimals =[5]float64{} + // go 里没有char ,但有 rune/byte 代替 char + var characters =[5]byte{} + var booleans =[5]bool{} ``` === "JavaScript" From a4161b5fa2747be17be932d1b5d9227b08a8fad9 Mon Sep 17 00:00:00 2001 From: XC-Zero <55583209+XC-Zero@users.noreply.github.com> Date: Wed, 28 Dec 2022 14:27:28 +0800 Subject: [PATCH 41/43] Update data_and_memory.md update tab to space --- docs/chapter_data_structure/data_and_memory.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/chapter_data_structure/data_and_memory.md b/docs/chapter_data_structure/data_and_memory.md index b4c8fbe5..0a478784 100644 --- a/docs/chapter_data_structure/data_and_memory.md +++ b/docs/chapter_data_structure/data_and_memory.md @@ -74,11 +74,11 @@ comments: true === "Go" ```go title="" - var numbers =[5]int{} - var decimals =[5]float64{} - // go 里没有char ,但有 rune/byte 代替 char - var characters =[5]byte{} - var booleans =[5]bool{} + var numbers = [5]int{} + var decimals = [5]float64{} + // go 里没有char ,但有 rune/byte 用以代替 char + var characters = [5]byte{} + var booleans = [5]bool{} ``` === "JavaScript" From debcc984e1cc339f92c036b12cadbea7c65822ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=BE=9A=E5=9B=BD=E7=8E=AE?= Date: Wed, 28 Dec 2022 17:07:59 +0800 Subject: [PATCH 42/43] docs(binary_search_tree): variable name error Combining Context, Compare 'cur.val' and 'num', not 'cur.val' and 'val`. --- docs/chapter_tree/binary_search_tree.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/chapter_tree/binary_search_tree.md b/docs/chapter_tree/binary_search_tree.md index b341e3dc..629c051f 100644 --- a/docs/chapter_tree/binary_search_tree.md +++ b/docs/chapter_tree/binary_search_tree.md @@ -17,9 +17,9 @@ comments: true 给定目标结点值 `num` ,可以根据二叉搜索树的性质来查找。我们声明一个结点 `cur` ,从二叉树的根结点 `root` 出发,循环比较结点值 `cur.val` 和 `num` 之间的大小关系 -- 若 `cur.val < val` ,说明目标结点在 `cur` 的右子树中,因此执行 `cur = cur.right` ; -- 若 `cur.val > val` ,说明目标结点在 `cur` 的左子树中,因此执行 `cur = cur.left` ; -- 若 `cur.val = val` ,说明找到目标结点,跳出循环并返回该结点即可; +- 若 `cur.val < num` ,说明目标结点在 `cur` 的右子树中,因此执行 `cur = cur.right` ; +- 若 `cur.val > num` ,说明目标结点在 `cur` 的左子树中,因此执行 `cur = cur.left` ; +- 若 `cur.val = num` ,说明找到目标结点,跳出循环并返回该结点即可; === "Step 1" From 78c2b94422818e7c0bcc2dcedec12ce8306a2b49 Mon Sep 17 00:00:00 2001 From: Yudong Jin Date: Thu, 29 Dec 2022 00:49:50 +0800 Subject: [PATCH 43/43] Update data_and_memory.md --- docs/chapter_data_structure/data_and_memory.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/chapter_data_structure/data_and_memory.md b/docs/chapter_data_structure/data_and_memory.md index 0a478784..3e1e2167 100644 --- a/docs/chapter_data_structure/data_and_memory.md +++ b/docs/chapter_data_structure/data_and_memory.md @@ -74,9 +74,9 @@ comments: true === "Go" ```go title="" + // 使用多种「基本数据类型」来初始化「数组」 var numbers = [5]int{} var decimals = [5]float64{} - // go 里没有char ,但有 rune/byte 用以代替 char var characters = [5]byte{} var booleans = [5]bool{} ```