diff --git a/README.md b/README.md index bac0bf373..6a6e165d7 100644 --- a/README.md +++ b/README.md @@ -39,29 +39,30 @@ - 代码导向,提供精简、可运行的算法代码; - 讨论学习,提问一般能在三日内得到回复; +如果感觉本书对你有所帮助,请点个 Star :star: 支持一下,谢谢! + +## 推荐语 + +> “一本通俗易懂的数据结构与算法入门书,引导读者手脑并用地学习,强烈推荐算法初学者阅读。” +> +> **—— 邓俊辉,清华大学计算机系教授** + +## 贡献 + 我们正在加速更新本书,期待您来[一起参与创作](https://www.hello-algo.com/chapter_preface/contribution/),以帮助其他读者获取更优质的学习内容: - 如果发现笔误、无效链接、内容缺失、文字歧义、解释不清晰等问题,烦请您帮忙修正; -- 欢迎您通过提交 Pull Request 来增添新内容,包括重写章节、新增章节、翻译代码至不同语言等; +- [代码翻译](https://github.com/krahets/hello-algo/issues/15) C++, Python, Go, JavaScript, TypeScript 正在进行中,期望您前来挑大梁; +- 欢迎您通过提交 Pull Request 来增添新内容,包括重写章节、新增章节等; > 有任何问题请与我联系 WeChat: krahets-jyd -如果感觉本书对你有所帮助,请点个 Star :star: 支持一下,谢谢! - -## 致谢 - 感谢本开源书的每一位撰稿人,是他们的无私奉献让这本书变得更好,他们是: -## To-Dos - -- [x] [代码翻译](https://github.com/krahets/hello-algo/issues/15):Java, C++, Python, Go, JavaScript 正在进行中,其他语言请求大佬挑大梁 -- [ ] 数据结构:散列表、堆(优先队列)、图 -- [ ] 算法:搜索与回溯、选择 / 堆排序、动态规划、贪心、分治 - ## License The texts, codes, images, photos, and videos in this repository are licensed under [CC BY-NC-SA-4.0](https://creativecommons.org/licenses/by-nc-sa/4.0/). diff --git a/codes/go/chapter_searching/binary_search.go b/codes/go/chapter_searching/binary_search.go new file mode 100644 index 000000000..cbaa85162 --- /dev/null +++ b/codes/go/chapter_searching/binary_search.go @@ -0,0 +1,43 @@ +// File: binary_search.go +// Created Time: 2022-12-05 +// Author: Slone123c (274325721@qq.com) + +package chapter_searching + +/* 二分查找(双闭区间) */ +func binarySearch(nums []int, target int) int { + // 初始化双闭区间 [0, n-1] ,即 i, j 分别指向数组首元素、尾元素 + i, j := 0, len(nums)-1 + // 循环,当搜索区间为空时跳出(当 i > j 时为空) + for i <= j { + m := (i + j) / 2 // 计算中点索引 m + if nums[m] < target { // 此情况说明 target 在区间 [m+1, j] 中 + i = m + 1 + } else if nums[m] > target { // 此情况说明 target 在区间 [i, m-1] 中 + j = m - 1 + } else { // 找到目标元素,返回其索引 + return m + } + } + // 未找到目标元素,返回 -1 + return -1 +} + +/* 二分查找(左闭右开) */ +func binarySearch1(nums []int, target int) int { + // 初始化左闭右开 [0, n) ,即 i, j 分别指向数组首元素、尾元素+1 + i, j := 0, len(nums) + // 循环,当搜索区间为空时跳出(当 i = j 时为空) + for i < j { + m := (i + j) / 2 // 计算中点索引 m + if nums[m] < target { // 此情况说明 target 在区间 [m+1, j) 中 + i = m + 1 + } else if nums[m] > target { // 此情况说明 target 在区间 [i, m) 中 + j = m + } else { // 找到目标元素,返回其索引 + return m + } + } + // 未找到目标元素,返回 -1 + return -1 +} diff --git a/codes/go/chapter_searching/binary_search_test.go b/codes/go/chapter_searching/binary_search_test.go new file mode 100644 index 000000000..3dada9593 --- /dev/null +++ b/codes/go/chapter_searching/binary_search_test.go @@ -0,0 +1,24 @@ +// File: binary_search_test.go +// Created Time: 2022-12-05 +// Author: Slone123c (274325721@qq.com) + +package chapter_searching + +import ( + "fmt" + "testing" +) + +func TestBinarySearch(t *testing.T) { + var ( + target = 3 + nums = []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10} + expected = 2 + ) + // 在数组中执行二分查找 + actual := binarySearch(nums, target) + fmt.Println("目标元素 3 的索引 =", actual) + if actual != expected { + t.Errorf("目标元素 3 的索引 = %d, 应该为 %d", actual, expected) + } +} diff --git a/codes/go/chapter_sorting/bubble_sort/bubble_sort.go b/codes/go/chapter_sorting/bubble_sort/bubble_sort.go new file mode 100644 index 000000000..a51d19925 --- /dev/null +++ b/codes/go/chapter_sorting/bubble_sort/bubble_sort.go @@ -0,0 +1,38 @@ +// File: bubble_sort.go +// Created Time: 2022-12-06 +// Author: Slone123c (274325721@qq.com) + +package bubble_sort + +/* 冒泡排序 */ +func bubbleSort(nums []int) { + // 外循环:待排序元素数量为 n-1, n-2, ..., 1 + for i := len(nums) - 1; i > 0; i-- { + // 内循环:冒泡操作 + for j := 0; j < i; j++ { + if nums[j] > nums[j+1] { + // 交换 nums[j] 与 nums[j + 1] + nums[j], nums[j+1] = nums[j+1], nums[j] + } + } + } +} + +/* 冒泡排序(标志优化)*/ +func bubbleSortWithFlag(nums []int) { + // 外循环:待排序元素数量为 n-1, n-2, ..., 1 + for i := len(nums) - 1; i > 0; i-- { + flag := false // 初始化标志位 + // 内循环:冒泡操作 + for j := 0; j < i; j++ { + if nums[j] > nums[j+1] { + // 交换 nums[j] 与 nums[j + 1] + nums[j], nums[j+1] = nums[j+1], nums[j] + flag = true // 记录交换元素 + } + } + if flag == false { // 此轮冒泡未交换任何元素,直接跳出 + break + } + } +} diff --git a/codes/go/chapter_sorting/bubble_sort/bubble_sort_test.go b/codes/go/chapter_sorting/bubble_sort/bubble_sort_test.go new file mode 100644 index 000000000..bab85139e --- /dev/null +++ b/codes/go/chapter_sorting/bubble_sort/bubble_sort_test.go @@ -0,0 +1,20 @@ +// File: bubble_sort_test.go +// Created Time: 2022-12-06 +// Author: Slone123c (274325721@qq.com) + +package bubble_sort + +import ( + "fmt" + "testing" +) + +func TestBubbleSort(t *testing.T) { + nums := []int{4, 1, 3, 1, 5, 2} + bubbleSort(nums) + fmt.Println("冒泡排序完成后 nums = ", nums) + + nums1 := []int{4, 1, 3, 1, 5, 2} + bubbleSortWithFlag(nums1) + fmt.Println("冒泡排序完成后 nums1 = ", nums) +} diff --git a/codes/java/chapter_hashing/array_hash_map.java b/codes/java/chapter_hashing/array_hash_map.java index 5fad6f3ea..89082c2f9 100644 --- a/codes/java/chapter_hashing/array_hash_map.java +++ b/codes/java/chapter_hashing/array_hash_map.java @@ -22,15 +22,15 @@ class ArrayHashMap { private List bucket; public ArrayHashMap() { // 初始化一个长度为 10 的桶(数组) - bucket = new ArrayList<>(10); - for (int i = 0; i < 10; i++) { + bucket = new ArrayList<>(); + for (int i = 0; i < 100; i++) { bucket.add(null); } } /* 哈希函数 */ private int hashFunc(int key) { - int index = key % 10000; + int index = key % 100; return index; } @@ -102,23 +102,23 @@ public class array_hash_map { /* 添加操作 */ // 在哈希表中添加键值对 (key, value) - map.put(10001, "小哈"); - map.put(10002, "小啰"); - map.put(10003, "小算"); - map.put(10004, "小法"); - map.put(10005, "小哇"); + map.put(12836, "小哈"); + map.put(15937, "小啰"); + map.put(16750, "小算"); + map.put(13276, "小法"); + map.put(10583, "小鸭"); System.out.println("\n添加完成后,哈希表为\nKey -> Value"); map.print(); /* 查询操作 */ // 向哈希表输入键 key ,得到值 value - String name = map.get(10002); - System.out.println("\n输入学号 10002 ,查询到姓名 " + name); + String name = map.get(15937); + System.out.println("\n输入学号 15937 ,查询到姓名 " + name); /* 删除操作 */ // 在哈希表中删除键值对 (key, value) - map.remove(10005); - System.out.println("\n删除 10005 后,哈希表为\nKey -> Value"); + map.remove(10583); + System.out.println("\n删除 10583 后,哈希表为\nKey -> Value"); map.print(); /* 遍历哈希表 */ diff --git a/codes/java/chapter_hashing/hash_map.java b/codes/java/chapter_hashing/hash_map.java index bd145b76e..bb72a4b0f 100644 --- a/codes/java/chapter_hashing/hash_map.java +++ b/codes/java/chapter_hashing/hash_map.java @@ -15,23 +15,23 @@ public class hash_map { /* 添加操作 */ // 在哈希表中添加键值对 (key, value) - map.put(10001, "小哈"); - map.put(10002, "小啰"); - map.put(10003, "小算"); - map.put(10004, "小法"); - map.put(10005, "小哇"); + map.put(12836, "小哈"); + map.put(15937, "小啰"); + map.put(16750, "小算"); + map.put(13276, "小法"); + map.put(10583, "小鸭"); System.out.println("\n添加完成后,哈希表为\nKey -> Value"); PrintUtil.printHashMap(map); /* 查询操作 */ // 向哈希表输入键 key ,得到值 value - String name = map.get(10002); - System.out.println("\n输入学号 10002 ,查询到姓名 " + name); + String name = map.get(15937); + System.out.println("\n输入学号 15937 ,查询到姓名 " + name); /* 删除操作 */ // 在哈希表中删除键值对 (key, value) - map.remove(10005); - System.out.println("\n删除 10005 后,哈希表为\nKey -> Value"); + map.remove(10583); + System.out.println("\n删除 10583 后,哈希表为\nKey -> Value"); PrintUtil.printHashMap(map); /* 遍历哈希表 */ diff --git a/codes/java/chapter_tree/avl_tree.java b/codes/java/chapter_tree/avl_tree.java new file mode 100644 index 000000000..5666b5d1d --- /dev/null +++ b/codes/java/chapter_tree/avl_tree.java @@ -0,0 +1,218 @@ +/* + * File: avl_tree.java + * Created Time: 2022-12-10 + * Author: Krahets (krahets@163.com) + */ + + package chapter_tree; + + import include.*; + + // Tree class + class AVLTree { + TreeNode root; // 根节点 + + /* 获取结点高度 */ + public int height(TreeNode node) { + // 空结点高度为 -1 ,叶结点高度为 0 + return node == null ? -1 : node.height; + } + + /* 更新结点高度 */ + private void updateHeight(TreeNode node) { + node.height = Math.max(height(node.left), height(node.right)) + 1; + } + + /* 获取平衡因子 */ + public int balanceFactor(TreeNode node) { + if (node == null) + return 0; + return height(node.left) - height(node.right); + } + + /* 右旋操作 */ + private TreeNode rightRotate(TreeNode node) { + TreeNode child = node.left; + TreeNode grandChild = child.right; + child.right = node; + node.left = grandChild; + updateHeight(node); + updateHeight(child); + return child; + } + + /* 左旋操作 */ + private TreeNode leftRotate(TreeNode node) { + TreeNode child = node.right; + TreeNode grandChild = child.left; + child.left = node; + node.right = grandChild; + updateHeight(node); + updateHeight(child); + return child; + } + + /* 执行旋转操作,使该子树重新恢复平衡 */ + private TreeNode rotate(TreeNode node) { + int balanceFactor = balanceFactor(node); + // 根据失衡情况分为四种操作:右旋、左旋、先左后右、先右后左 + if (balanceFactor > 1) { + if (balanceFactor(node.left) >= 0) { + // 右旋 + return rightRotate(node); + } else { + // 先左旋后右旋 + node.left = leftRotate(node.left); + return rightRotate(node); + } + } + if (balanceFactor < -1) { + if (balanceFactor(node.right) <= 0) { + // 左旋 + return leftRotate(node); + } else { + // 先右旋后左旋 + node.right = rightRotate(node.right); + return leftRotate(node); + } + } + return node; + } + + /* 插入结点 */ + public TreeNode insert(int val) { + root = insertHelper(root, val); + return root; + } + + /* 递归插入结点 */ + private TreeNode insertHelper(TreeNode node, int val) { + // 1. 查找插入位置,并插入结点 + if (node == null) + return new TreeNode(val); + if (val < node.val) + node.left = insertHelper(node.left, val); + else if (val > node.val) + node.right = insertHelper(node.right, val); + else + return node; // 重复结点则直接返回 + // 2. 更新结点高度 + updateHeight(node); + // 3. 执行旋转操作,使该子树重新恢复平衡 + node = rotate(node); + // 返回该子树的根节点 + return node; + } + + /* 删除结点 */ + public TreeNode remove(int val) { + root = removeHelper(root, val); + return root; + } + + /* 递归删除结点 */ + private TreeNode removeHelper(TreeNode node, int val) { + // 1. 查找结点,并删除之 + if (node == null) + return null; + if (val < node.val) + node.left = removeHelper(node.left, val); + else if (val > node.val) + node.right = removeHelper(node.right, val); + else { + if (node.left == null || node.right == null) { + TreeNode child = node.left != null ? node.left : node.right; + // 子结点数量 = 0 ,直接删除 node 并返回 + if (child == null) + return null; + // 子结点数量 = 1 ,直接删除 node + else + node = child; + } else { + // 子结点数量 = 2 ,则将中序遍历的下个结点删除,并用该结点替换当前结点 + TreeNode temp = minNode(node.right); + node.right = removeHelper(node.right, temp.val); + node.val = temp.val; + } + } + // 2. 更新结点高度 + updateHeight(node); + // 3. 执行旋转操作,使该子树重新恢复平衡 + node = rotate(node); + // 返回该子树的根节点 + return node; + } + + /* 获取最小结点 */ + private TreeNode minNode(TreeNode node) { + if (node == null) return node; + // 循环访问左子结点,直到叶结点时为最小结点,跳出 + while (node.left != null) { + node = node.left; + } + return node; + } + + /* 查找结点 */ + public TreeNode search(int val) { + TreeNode cur = root; + // 循环查找,越过叶结点后跳出 + while (cur != null) { + // 目标结点在 root 的右子树中 + if (cur.val < val) cur = cur.right; + // 目标结点在 root 的左子树中 + else if (cur.val > val) cur = cur.left; + // 找到目标结点,跳出循环 + else break; + } + // 返回目标结点 + return cur; + } + } + + + public class avl_tree { + static void testInsert(AVLTree tree, int val) { + tree.insert(val); + System.out.println("\n插入结点 " + val + " 后,AVL 树为"); + PrintUtil.printTree(tree.root); + } + + static void testRemove(AVLTree tree, int val) { + tree.remove(val); + System.out.println("\n删除结点 " + val + " 后,AVL 树为"); + PrintUtil.printTree(tree.root); + } + + public static void main(String[] args) { + /* 初始化空 AVL 树 */ + AVLTree avlTree = new AVLTree(); + + /* 插入结点 */ + // 请关注插入结点后,AVL 树是如何保持平衡的 + testInsert(avlTree, 1); + testInsert(avlTree, 2); + testInsert(avlTree, 3); + testInsert(avlTree, 4); + testInsert(avlTree, 5); + testInsert(avlTree, 8); + testInsert(avlTree, 7); + testInsert(avlTree, 9); + testInsert(avlTree, 10); + testInsert(avlTree, 6); + + /* 插入重复结点 */ + testInsert(avlTree, 7); + + /* 删除结点 */ + // 请关注删除结点后,AVL 树是如何保持平衡的 + testRemove(avlTree, 8); // 删除度为 0 的结点 + testRemove(avlTree, 5); // 删除度为 1 的结点 + testRemove(avlTree, 4); // 删除度为 2 的结点 + + /* 查询结点 */ + TreeNode node = avlTree.search(7); + System.out.println("\n查找到的结点对象为 " + node + ",结点值 = " + node.val); + } + } + \ No newline at end of file diff --git a/codes/java/include/TreeNode.java b/codes/java/include/TreeNode.java old mode 100755 new mode 100644 index 69aafd500..98b9f826e --- a/codes/java/include/TreeNode.java +++ b/codes/java/include/TreeNode.java @@ -12,10 +12,10 @@ import java.util.*; * Definition for a binary tree node. */ public class TreeNode { - public int val; - public int height; - public TreeNode left; - public TreeNode right; + public int val; // 结点值 + public int height; // 结点高度 + public TreeNode left; // 左子结点引用 + public TreeNode right; // 右子结点引用 public TreeNode(int x) { val = x; diff --git a/codes/javascript/chapter_stack_and_queue/array_stack.js b/codes/javascript/chapter_stack_and_queue/array_stack.js new file mode 100644 index 000000000..a83d16f0e --- /dev/null +++ b/codes/javascript/chapter_stack_and_queue/array_stack.js @@ -0,0 +1,84 @@ +/** + * File: array_stack.js + * Created Time: 2022-12-09 + * Author: S-N-O-R-L-A-X (snorlax.xu@outlook.com) + */ + + +/* 基于数组实现的栈 */ +class ArrayStack { + stack; + constructor() { + this.stack = []; + } + /* 获取栈的长度 */ + get size() { + return this.stack.length; + } + + /* 判断栈是否为空 */ + empty() { + return this.stack.length === 0; + } + + /* 入栈 */ + push(num) { + this.stack.push(num); + } + + /* 出栈 */ + pop() { + return this.stack.pop(); + } + + /* 访问栈顶元素 */ + top() { + return this.stack[this.stack.length - 1]; + } + + /* 访问索引 index 处元素 */ + get(index) { + return this.stack[index]; + } + + /* 返回 Array */ + toArray() { + return this.stack; + } +}; + + +/* Driver Code */ + +/* 初始化栈 */ +const stack = new ArrayStack(); + +/* 元素入栈 */ +stack.push(1); +stack.push(3); +stack.push(2); +stack.push(5); +stack.push(4); +console.log("栈 stack = "); +console.log(stack.toArray()); + +/* 访问栈顶元素 */ +const top = stack.top(); +console.log("栈顶元素 top = " + top); + +/* 访问索引 index 处元素 */ +const num = stack.get(3); +console.log("栈索引 3 处的元素为 num = " + num); + +/* 元素出栈 */ +const pop = stack.pop(); +console.log("出栈元素 pop = " + pop + ",出栈后 stack = "); +console.log(stack.toArray()); + +/* 获取栈的长度 */ +const size = stack.size; +console.log("栈的长度 size = " + size); + +/* 判断是否为空 */ +const empty = stack.empty(); +console.log("栈是否为空 = " + empty); diff --git a/codes/javascript/chapter_stack_and_queue/queue.js b/codes/javascript/chapter_stack_and_queue/queue.js new file mode 100644 index 000000000..5d26727f1 --- /dev/null +++ b/codes/javascript/chapter_stack_and_queue/queue.js @@ -0,0 +1,30 @@ +/** + * File: queue.js + * Created Time: 2022-12-05 + * Author: S-N-O-R-L-A-X (snorlax.xu@outlook.com) + */ + +/* 初始化队列 */ +// JavaScript 没有内置的队列,可以把 Array 当作队列来使用 +// 注意:由于是数组,所以 shift() 的时间复杂度是 O(n) +const queue = []; + +/* 元素入队 */ +queue.push(1); +queue.push(3); +queue.push(2); +queue.push(5); +queue.push(4); + +/* 访问队首元素 */ +const peek = queue[0]; + +/* 元素出队 */ +// O(n) +const poll = queue.shift(); + +/* 获取队列的长度 */ +const size = queue.length; + +/* 判断队列是否为空 */ +const empty = queue.length === 0; diff --git a/codes/python/chapter_stack_and_queue/queue.py b/codes/python/chapter_stack_and_queue/queue.py index 93729a868..740d9b1e1 100644 --- a/codes/python/chapter_stack_and_queue/queue.py +++ b/codes/python/chapter_stack_and_queue/queue.py @@ -1,5 +1,5 @@ ''' -File: que.py +File: queue.py Created Time: 2022-11-29 Author: Peng Chen (pengchzn@gmail.com) ''' diff --git a/codes/typescript/chapter_stack_and_queue/array_stack.ts b/codes/typescript/chapter_stack_and_queue/array_stack.ts new file mode 100644 index 000000000..5a57b6cf7 --- /dev/null +++ b/codes/typescript/chapter_stack_and_queue/array_stack.ts @@ -0,0 +1,86 @@ +/** + * File: array_stack.ts + * Created Time: 2022-12-08 + * Author: S-N-O-R-L-A-X (snorlax.xu@outlook.com) + */ + + +/* 基于数组实现的栈 */ +class ArrayStack { + private stack: number[]; + constructor() { + this.stack = []; + } + /* 获取栈的长度 */ + get size(): number { + return this.stack.length; + } + + /* 判断栈是否为空 */ + empty(): boolean { + return this.stack.length === 0; + } + + /* 入栈 */ + push(num: number): void { + this.stack.push(num); + } + + /* 出栈 */ + pop(): number | undefined { + return this.stack.pop(); + } + + /* 访问栈顶元素 */ + top(): number | undefined { + return this.stack[this.stack.length - 1]; + } + + /* 访问索引 index 处元素 */ + get(index: number): number | undefined { + return this.stack[index]; + } + + /* 返回 Array */ + toArray() { + return this.stack; + } +}; + + +/* Driver Code */ + +/* 初始化栈 */ +const stack = new ArrayStack(); + +/* 元素入栈 */ +stack.push(1); +stack.push(3); +stack.push(2); +stack.push(5); +stack.push(4); +console.log("栈 stack = "); +console.log(stack.toArray()); + +/* 访问栈顶元素 */ +const top = stack.top(); +console.log("栈顶元素 top = " + top); + +/* 访问索引 index 处元素 */ +const num = stack.get(3); +console.log("栈索引 3 处的元素为 num = " + num); + +/* 元素出栈 */ +const pop = stack.pop(); +console.log("出栈元素 pop = " + pop + ",出栈后 stack = "); +console.log(stack.toArray()); + +/* 获取栈的长度 */ +const size = stack.size; +console.log("栈的长度 size = " + size); + +/* 判断是否为空 */ +const empty = stack.empty(); +console.log("栈是否为空 = " + empty); + +export { }; \ No newline at end of file diff --git a/codes/typescript/chapter_stack_and_queue/queue.ts b/codes/typescript/chapter_stack_and_queue/queue.ts new file mode 100644 index 000000000..0701a9af5 --- /dev/null +++ b/codes/typescript/chapter_stack_and_queue/queue.ts @@ -0,0 +1,32 @@ +/** + * File: queue.ts + * Created Time: 2022-12-05 + * Author: S-N-O-R-L-A-X (snorlax.xu@outlook.com) + */ + +/* 初始化队列 */ +// TypeScript 没有内置的队列,可以把 Array 当作队列来使用 +// 注意:由于是数组,所以 shift() 的时间复杂度是 O(n) +const queue: number[] = []; + +/* 元素入队 */ +queue.push(1); +queue.push(3); +queue.push(2); +queue.push(5); +queue.push(4); + +/* 访问队首元素 */ +const peek = queue[0]; + +/* 元素出队 */ +// O(n) +const poll = queue.shift(); + +/* 获取队列的长度 */ +const size = queue.length; + +/* 判断队列是否为空 */ +const empty = queue.length === 0; + +export { }; diff --git a/docs/chapter_array_and_linkedlist/array.assets/array_definition.png b/docs/chapter_array_and_linkedlist/array.assets/array_definition.png index 401b06691..f5cb45aa0 100644 Binary files a/docs/chapter_array_and_linkedlist/array.assets/array_definition.png and b/docs/chapter_array_and_linkedlist/array.assets/array_definition.png differ diff --git a/docs/chapter_array_and_linkedlist/array.assets/array_insert_remove_element.png b/docs/chapter_array_and_linkedlist/array.assets/array_insert_remove_element.png index a35f52076..6e02d129b 100644 Binary files a/docs/chapter_array_and_linkedlist/array.assets/array_insert_remove_element.png and b/docs/chapter_array_and_linkedlist/array.assets/array_insert_remove_element.png differ diff --git a/docs/chapter_array_and_linkedlist/array.assets/array_memory_location_calculation.png b/docs/chapter_array_and_linkedlist/array.assets/array_memory_location_calculation.png index 3e1a08d75..6565145f8 100644 Binary files a/docs/chapter_array_and_linkedlist/array.assets/array_memory_location_calculation.png and b/docs/chapter_array_and_linkedlist/array.assets/array_memory_location_calculation.png differ diff --git a/docs/chapter_array_and_linkedlist/array.md b/docs/chapter_array_and_linkedlist/array.md index bba71f06b..c6f2feca7 100644 --- a/docs/chapter_array_and_linkedlist/array.md +++ b/docs/chapter_array_and_linkedlist/array.md @@ -65,13 +65,13 @@ comments: true === "C" ```c title="array.c" - + ``` === "C#" ```csharp title="array.cs" - + ``` ## 数组优点 @@ -131,7 +131,7 @@ elementAddr = firtstElementAddr + elementLength * elementIndex === "Go" ```go title="array.go" - + ``` === "JavaScript" @@ -163,13 +163,13 @@ elementAddr = firtstElementAddr + elementLength * elementIndex === "C" ```c title="array.c" - + ``` === "C#" ```csharp title="array.cs" - + ``` ## 数组缺点 @@ -227,7 +227,7 @@ elementAddr = firtstElementAddr + elementLength * elementIndex === "Go" ```go title="array.go" - + ``` === "JavaScript" @@ -265,19 +265,19 @@ elementAddr = firtstElementAddr + elementLength * elementIndex === "C" ```c title="array.c" - + ``` === "C#" ```csharp title="array.cs" - + ``` **数组中插入或删除元素效率低下。** 假设我们想要在数组中间某位置插入一个元素,由于数组元素在内存中是 “紧挨着的” ,它们之间没有空间再放任何数据。因此,我们不得不将此索引之后的所有元素都向后移动一位,然后再把元素赋值给该索引。删除元素也是类似,需要把此索引之后的元素都向前移动一位。总体看有以下缺点: - **时间复杂度高:** 数组的插入和删除的平均时间复杂度均为 $O(N)$ ,其中 $N$ 为数组长度。 -- **丢失元素或:** 由于数组的长度不可变,因此在插入元素后,数组原来的末尾元素会丢失。 +- **丢失元素:** 由于数组的长度不可变,因此在插入元素后,超出数组长度范围的元素会被丢失。 - **内存浪费:** 我们一般会初始化一个比较长的数组,只用前面一部分,这样在插入数据时,丢失的末尾元素都是我们不关心的,但这样做同时也会造成内存空间的浪费。 ![array_insert_remove_element](array.assets/array_insert_remove_element.png) @@ -318,7 +318,7 @@ elementAddr = firtstElementAddr + elementLength * elementIndex // 将 num 赋给 index 处元素 nums[index] = num; } - + /* 删除索引 index 处元素 */ void remove(int* nums, int size, int index) { // 把索引 index 之后的所有元素向前移动一位 @@ -338,7 +338,7 @@ elementAddr = firtstElementAddr + elementLength * elementIndex nums[i] = nums[i - 1] # 将 num 赋给 index 处元素 nums[index] = num - + """ 删除索引 index 处元素 """ def remove(nums, index): # 把索引 index 之后的所有元素向前移动一位 @@ -349,7 +349,7 @@ elementAddr = firtstElementAddr + elementLength * elementIndex === "Go" ```go title="array.go" - + ``` === "JavaScript" @@ -364,7 +364,7 @@ elementAddr = firtstElementAddr + elementLength * elementIndex // 将 num 赋给 index 处元素 nums[index] = num; } - + /* 删除索引 index 处元素 */ function remove(nums, index){ // 把索引 index 之后的所有元素向前移动一位 @@ -386,7 +386,7 @@ elementAddr = firtstElementAddr + elementLength * elementIndex // 将 num 赋给 index 处元素 nums[index] = num } - + /* 删除索引 index 处元素 */ function remove(nums: number[], index: number): void { // 把索引 index 之后的所有元素向前移动一位 @@ -399,13 +399,13 @@ elementAddr = firtstElementAddr + elementLength * elementIndex === "C" ```c title="array.c" - + ``` === "C#" ```csharp title="array.cs" - + ``` ## 数组常用操作 @@ -459,7 +459,7 @@ elementAddr = firtstElementAddr + elementLength * elementIndex === "Go" ```go title="array.go" - + ``` === "JavaScript" @@ -499,13 +499,13 @@ elementAddr = firtstElementAddr + elementLength * elementIndex === "C" ```c title="array.c" - + ``` === "C#" ```csharp title="array.cs" - + ``` **数组查找。** 通过遍历数组,查找数组内的指定元素,并输出对应索引。 @@ -550,7 +550,7 @@ elementAddr = firtstElementAddr + elementLength * elementIndex === "Go" ```go title="array.go" - + ``` === "JavaScript" @@ -583,13 +583,13 @@ elementAddr = firtstElementAddr + elementLength * elementIndex === "C" ```c title="array.c" - + ``` === "C#" ```csharp title="array.cs" - + ``` ## 数组典型应用 diff --git a/docs/chapter_array_and_linkedlist/linked_list.assets/linkedlist_common_types.png b/docs/chapter_array_and_linkedlist/linked_list.assets/linkedlist_common_types.png index 3ced93c65..ec04fe46c 100644 Binary files a/docs/chapter_array_and_linkedlist/linked_list.assets/linkedlist_common_types.png and b/docs/chapter_array_and_linkedlist/linked_list.assets/linkedlist_common_types.png differ diff --git a/docs/chapter_array_and_linkedlist/linked_list.assets/linkedlist_definition.png b/docs/chapter_array_and_linkedlist/linked_list.assets/linkedlist_definition.png index 73120e956..66d82b4f2 100644 Binary files a/docs/chapter_array_and_linkedlist/linked_list.assets/linkedlist_definition.png and b/docs/chapter_array_and_linkedlist/linked_list.assets/linkedlist_definition.png differ diff --git a/docs/chapter_array_and_linkedlist/linked_list.assets/linkedlist_insert_remove_node.png b/docs/chapter_array_and_linkedlist/linked_list.assets/linkedlist_insert_remove_node.png index 3fcda1f63..3ab4da38c 100644 Binary files a/docs/chapter_array_and_linkedlist/linked_list.assets/linkedlist_insert_remove_node.png and b/docs/chapter_array_and_linkedlist/linked_list.assets/linkedlist_insert_remove_node.png differ diff --git a/docs/chapter_computational_complexity/performance_evaluation.md b/docs/chapter_computational_complexity/performance_evaluation.md index 84c3dc80d..45031b2f8 100644 --- a/docs/chapter_computational_complexity/performance_evaluation.md +++ b/docs/chapter_computational_complexity/performance_evaluation.md @@ -30,7 +30,7 @@ comments: true ### 理论估算 -既然实际测试具有很大的局限性,那么我们是否可以仅通过一些计算,就获知算法的效率水平呢?答案是肯定的,我们将此估算方法称为「复杂度分析 Complexity Analysis」或「渐进复杂度分析 Asymptotic Complexity Analysis」。 +既然实际测试具有很大的局限性,那么我们是否可以仅通过一些计算,就获知算法的效率水平呢?答案是肯定的,我们将此估算方法称为「复杂度分析 Complexity Analysis」或「渐近复杂度分析 Asymptotic Complexity Analysis」。 **复杂度分析评估随着输入数据量的增长,算法的运行时间和占用空间的增长趋势** 。根据时间和空间两方面,复杂度可分为「时间复杂度 Time Complexity」和「空间复杂度 Space Complexity」。 diff --git a/docs/chapter_computational_complexity/space_complexity.assets/space_complexity_common_types.png b/docs/chapter_computational_complexity/space_complexity.assets/space_complexity_common_types.png index 59773c1bd..65c79e98e 100644 Binary files a/docs/chapter_computational_complexity/space_complexity.assets/space_complexity_common_types.png and b/docs/chapter_computational_complexity/space_complexity.assets/space_complexity_common_types.png differ diff --git a/docs/chapter_computational_complexity/space_complexity.assets/space_complexity_exponential.png b/docs/chapter_computational_complexity/space_complexity.assets/space_complexity_exponential.png index 83731cc1e..c26da8461 100644 Binary files a/docs/chapter_computational_complexity/space_complexity.assets/space_complexity_exponential.png and b/docs/chapter_computational_complexity/space_complexity.assets/space_complexity_exponential.png differ diff --git a/docs/chapter_computational_complexity/space_complexity.assets/space_complexity_recursive_linear.png b/docs/chapter_computational_complexity/space_complexity.assets/space_complexity_recursive_linear.png index 01826bc0c..951a4f4b5 100644 Binary files a/docs/chapter_computational_complexity/space_complexity.assets/space_complexity_recursive_linear.png and b/docs/chapter_computational_complexity/space_complexity.assets/space_complexity_recursive_linear.png differ diff --git a/docs/chapter_computational_complexity/space_complexity.assets/space_complexity_recursive_quadratic.png b/docs/chapter_computational_complexity/space_complexity.assets/space_complexity_recursive_quadratic.png index ae82d12a1..457b583a6 100644 Binary files a/docs/chapter_computational_complexity/space_complexity.assets/space_complexity_recursive_quadratic.png and b/docs/chapter_computational_complexity/space_complexity.assets/space_complexity_recursive_quadratic.png differ diff --git a/docs/chapter_computational_complexity/space_complexity.assets/space_types.png b/docs/chapter_computational_complexity/space_complexity.assets/space_types.png index 1854e9ee2..713a510a8 100644 Binary files a/docs/chapter_computational_complexity/space_complexity.assets/space_types.png and b/docs/chapter_computational_complexity/space_complexity.assets/space_types.png differ diff --git a/docs/chapter_computational_complexity/summary.md b/docs/chapter_computational_complexity/summary.md index 6550e776c..7e76d2c15 100644 --- a/docs/chapter_computational_complexity/summary.md +++ b/docs/chapter_computational_complexity/summary.md @@ -13,8 +13,8 @@ comments: true ### 时间复杂度 - 「时间复杂度」统计算法运行时间随着数据量变大时的增长趋势,可以有效评估算法效率,但在某些情况下可能失效,比如在输入数据量较小或时间复杂度相同时,无法精确对比算法效率的优劣性。 -- 「最差时间复杂度」使用大 $O$ 符号表示,即函数渐进上界,其反映当 $n$ 趋于正无穷时,$T(n)$ 处于何种增长级别。 -- 推算时间复杂度分为两步,首先统计计算操作数量,再判断渐进上界。 +- 「最差时间复杂度」使用大 $O$ 符号表示,即函数渐近上界,其反映当 $n$ 趋于正无穷时,$T(n)$ 处于何种增长级别。 +- 推算时间复杂度分为两步,首先统计计算操作数量,再判断渐近上界。 - 常见时间复杂度从小到大排列有 $O(1)$ , $O(\log n)$ , $O(n)$ , $O(n \log n)$ , $O(n^2)$ , $O(2^n)$ , $O(n!)$ 。 - 某些算法的时间复杂度不是恒定的,而是与输入数据的分布有关。时间复杂度分为「最差时间复杂度」和「最佳时间复杂度」,后者几乎不用,因为输入数据需要满足苛刻的条件才能达到最佳情况。 - 「平均时间复杂度」可以反映在随机数据输入下的算法效率,最贴合实际使用情况下的算法性能。计算平均时间复杂度需要统计输入数据的分布,以及综合后的数学期望。 diff --git a/docs/chapter_computational_complexity/time_complexity.assets/asymptotic_upper_bound.png b/docs/chapter_computational_complexity/time_complexity.assets/asymptotic_upper_bound.png index fabba5364..59399bfcc 100644 Binary files a/docs/chapter_computational_complexity/time_complexity.assets/asymptotic_upper_bound.png and b/docs/chapter_computational_complexity/time_complexity.assets/asymptotic_upper_bound.png differ diff --git a/docs/chapter_computational_complexity/time_complexity.assets/time_complexity_common_types.png b/docs/chapter_computational_complexity/time_complexity.assets/time_complexity_common_types.png index f165f0022..f0108530f 100644 Binary files a/docs/chapter_computational_complexity/time_complexity.assets/time_complexity_common_types.png and b/docs/chapter_computational_complexity/time_complexity.assets/time_complexity_common_types.png differ diff --git a/docs/chapter_computational_complexity/time_complexity.assets/time_complexity_constant_linear_quadratic.png b/docs/chapter_computational_complexity/time_complexity.assets/time_complexity_constant_linear_quadratic.png index ea71ea894..e4e839c90 100644 Binary files a/docs/chapter_computational_complexity/time_complexity.assets/time_complexity_constant_linear_quadratic.png and b/docs/chapter_computational_complexity/time_complexity.assets/time_complexity_constant_linear_quadratic.png differ diff --git a/docs/chapter_computational_complexity/time_complexity.assets/time_complexity_exponential.png b/docs/chapter_computational_complexity/time_complexity.assets/time_complexity_exponential.png index 9a96a58e0..3c9466574 100644 Binary files a/docs/chapter_computational_complexity/time_complexity.assets/time_complexity_exponential.png and b/docs/chapter_computational_complexity/time_complexity.assets/time_complexity_exponential.png differ diff --git a/docs/chapter_computational_complexity/time_complexity.assets/time_complexity_factorial.png b/docs/chapter_computational_complexity/time_complexity.assets/time_complexity_factorial.png index de7deeed3..7c86dfd3f 100644 Binary files a/docs/chapter_computational_complexity/time_complexity.assets/time_complexity_factorial.png and b/docs/chapter_computational_complexity/time_complexity.assets/time_complexity_factorial.png differ diff --git a/docs/chapter_computational_complexity/time_complexity.assets/time_complexity_first_example.png b/docs/chapter_computational_complexity/time_complexity.assets/time_complexity_first_example.png index 004f54c45..f2358b7cc 100644 Binary files a/docs/chapter_computational_complexity/time_complexity.assets/time_complexity_first_example.png and b/docs/chapter_computational_complexity/time_complexity.assets/time_complexity_first_example.png differ diff --git a/docs/chapter_computational_complexity/time_complexity.assets/time_complexity_logarithmic.png b/docs/chapter_computational_complexity/time_complexity.assets/time_complexity_logarithmic.png index 3a57fc016..a4df4527f 100644 Binary files a/docs/chapter_computational_complexity/time_complexity.assets/time_complexity_logarithmic.png and b/docs/chapter_computational_complexity/time_complexity.assets/time_complexity_logarithmic.png differ diff --git a/docs/chapter_computational_complexity/time_complexity.assets/time_complexity_logarithmic_linear.png b/docs/chapter_computational_complexity/time_complexity.assets/time_complexity_logarithmic_linear.png index 9f4f51539..6f336f4b5 100644 Binary files a/docs/chapter_computational_complexity/time_complexity.assets/time_complexity_logarithmic_linear.png and b/docs/chapter_computational_complexity/time_complexity.assets/time_complexity_logarithmic_linear.png differ diff --git a/docs/chapter_computational_complexity/time_complexity.md b/docs/chapter_computational_complexity/time_complexity.md index 9ee13d8db..ab55268c5 100644 --- a/docs/chapter_computational_complexity/time_complexity.md +++ b/docs/chapter_computational_complexity/time_complexity.md @@ -203,7 +203,7 @@ $$ **时间复杂度也存在一定的局限性。** 比如,虽然算法 `A` 和 `C` 的时间复杂度相同,但是实际的运行时间有非常大的差别。再比如,虽然算法 `B` 比 `C` 的时间复杂度要更高,但在输入数据大小 $n$ 比较小时,算法 `B` 是要明显优于算法 `C` 的。即使存在这些问题,计算复杂度仍然是评判算法效率的最有效、最常用方法。 -## 函数渐进上界 +## 函数渐近上界 设算法「计算操作数量」为 $T(n)$ ,其是一个关于输入数据大小 $n$ 的函数。例如,以下算法的操作数量为 @@ -284,34 +284,34 @@ $$ $T(n)$ 是个一次函数,说明时间增长趋势是线性的,因此易得时间复杂度是线性阶。 -我们将线性阶的时间复杂度记为 $O(n)$ ,这个数学符号被称为「大 $O$ 记号 Big-$O$ Notation」,代表函数 $T(n)$ 的「渐进上界 asymptotic upper bound」。 +我们将线性阶的时间复杂度记为 $O(n)$ ,这个数学符号被称为「大 $O$ 记号 Big-$O$ Notation」,代表函数 $T(n)$ 的「渐近上界 asymptotic upper bound」。 -我们要推算时间复杂度,本质上是在计算「操作数量函数 $T(n)$ 」的渐进上界。下面我们先来看看函数渐进上界的数学定义。 +我们要推算时间复杂度,本质上是在计算「操作数量函数 $T(n)$ 」的渐近上界。下面我们先来看看函数渐近上界的数学定义。 -!!! abstract "函数渐进上界" +!!! abstract "函数渐近上界" 若存在正实数 $c$ 和实数 $n_0$ ,使得对于所有的 $n > n_0$ ,均有 $$ T(n) \leq c \cdot f(n) $$ - 则可认为 $f(n)$ 给出了 $T(n)$ 的一个渐进上界,记为 + 则可认为 $f(n)$ 给出了 $T(n)$ 的一个渐近上界,记为 $$ T(n) = O(f(n)) $$ ![asymptotic_upper_bound](time_complexity.assets/asymptotic_upper_bound.png) -

Fig. 函数的渐进上界

+

Fig. 函数的渐近上界

-本质上看,计算渐进上界就是在找一个函数 $f(n)$ ,**使得在 $n$ 趋向于无穷大时,$T(n)$ 和 $f(n)$ 处于相同的增长级别(仅相差一个常数项 $c$ 的倍数)**。 +本质上看,计算渐近上界就是在找一个函数 $f(n)$ ,**使得在 $n$ 趋向于无穷大时,$T(n)$ 和 $f(n)$ 处于相同的增长级别(仅相差一个常数项 $c$ 的倍数)**。 !!! tip - 渐进上界的数学味儿有点重,如果你感觉没有完全理解,无需担心,因为在实际使用中我们只需要会推算即可,数学意义可以慢慢领悟。 + 渐近上界的数学味儿有点重,如果你感觉没有完全理解,无需担心,因为在实际使用中我们只需要会推算即可,数学意义可以慢慢领悟。 ## 推算方法 -推算出 $f(n)$ 后,我们就得到时间复杂度 $O(f(n))$ 。那么,如何来确定渐进上界 $f(n)$ 呢?总体分为两步,首先「统计操作数量」,然后「判断渐进上界」。 +推算出 $f(n)$ 后,我们就得到时间复杂度 $O(f(n))$ 。那么,如何来确定渐近上界 $f(n)$ 呢?总体分为两步,首先「统计操作数量」,然后「判断渐近上界」。 ### 1. 统计操作数量 @@ -416,7 +416,7 @@ $$ ``` -### 2. 判断渐进上界 +### 2. 判断渐近上界 **时间复杂度由多项式 $T(n)$ 中最高阶的项来决定**。这是因为在 $n$ 趋于无穷大时,最高阶的项将处于主导作用,其它项的影响都可以被忽略。 @@ -1330,7 +1330,7 @@ $$ - 当 `nums = [?, ?, ..., 1]`,即当末尾元素是 $1$ 时,则需完整遍历数组,此时达到 **最差时间复杂度 $O(n)$** ; - 当 `nums = [1, ?, ?, ...]` ,即当首个数字为 $1$ 时,无论数组多长都不需要继续遍历,此时达到 **最佳时间复杂度 $\Omega(1)$** ; -「函数渐进上界」使用大 $O$ 记号表示,代表「最差时间复杂度」。与之对应,「函数渐进下界」用 $\Omega$ 记号(Omega Notation)来表示,代表「最佳时间复杂度」。 +「函数渐近上界」使用大 $O$ 记号表示,代表「最差时间复杂度」。与之对应,「函数渐近下界」用 $\Omega$ 记号(Omega Notation)来表示,代表「最佳时间复杂度」。 === "Java" diff --git a/docs/chapter_data_structure/classification_of_data_strcuture.assets/classification_logic_structure.png b/docs/chapter_data_structure/classification_of_data_strcuture.assets/classification_logic_structure.png index 3158e6a79..7375e43c3 100644 Binary files a/docs/chapter_data_structure/classification_of_data_strcuture.assets/classification_logic_structure.png and b/docs/chapter_data_structure/classification_of_data_strcuture.assets/classification_logic_structure.png differ diff --git a/docs/chapter_data_structure/classification_of_data_strcuture.assets/classification_phisical_structure.png b/docs/chapter_data_structure/classification_of_data_strcuture.assets/classification_phisical_structure.png index 697627b41..29ef8bb22 100644 Binary files a/docs/chapter_data_structure/classification_of_data_strcuture.assets/classification_phisical_structure.png and b/docs/chapter_data_structure/classification_of_data_strcuture.assets/classification_phisical_structure.png differ diff --git a/docs/chapter_data_structure/data_and_memory.assets/computer_memory_location.png b/docs/chapter_data_structure/data_and_memory.assets/computer_memory_location.png index 2111f4903..900643191 100644 Binary files a/docs/chapter_data_structure/data_and_memory.assets/computer_memory_location.png and b/docs/chapter_data_structure/data_and_memory.assets/computer_memory_location.png differ diff --git a/docs/chapter_hashing/hash_map.assets/hash_collision.png b/docs/chapter_hashing/hash_map.assets/hash_collision.png new file mode 100644 index 000000000..e94330064 Binary files /dev/null and b/docs/chapter_hashing/hash_map.assets/hash_collision.png differ diff --git a/docs/chapter_hashing/hash_map.assets/hash_function.png b/docs/chapter_hashing/hash_map.assets/hash_function.png new file mode 100644 index 000000000..b15d22515 Binary files /dev/null and b/docs/chapter_hashing/hash_map.assets/hash_function.png differ diff --git a/docs/chapter_hashing/hash_map.assets/hash_map.png b/docs/chapter_hashing/hash_map.assets/hash_map.png new file mode 100644 index 000000000..5c36a2a18 Binary files /dev/null and b/docs/chapter_hashing/hash_map.assets/hash_map.png differ diff --git a/docs/chapter_hashing/hash_map.md b/docs/chapter_hashing/hash_map.md index 62725faae..77bc82321 100644 --- a/docs/chapter_hashing/hash_map.md +++ b/docs/chapter_hashing/hash_map.md @@ -4,9 +4,34 @@ comments: true # 哈希表 -哈希表通过建立「键 Key」和「值 Value」之间的映射,实现高效的元素查找。具体地,查询操作(给定一个 Key 查询得到 Value)的时间复杂度为 $O(1)$ 。 +哈希表通过建立「键 Key」和「值 Value」之间的映射,实现高效的元素查找。具体地,输入一个 Key ,在哈希表中查询并获取 Value ,时间复杂度为 $O(1)$ 。 -(图) +例如,给定一个包含 $n$ 个学生的数据库,每个学生有 "姓名 `name` ” 和 “学号 `id` ” 两项数据,希望实现一个查询功能:**输入一个学号,返回对应的姓名**,则可以使用哈希表实现。 + +![hash_map](hash_map.assets/hash_map.png) + +

Fig. 哈希表抽象表示

+ +## 哈希表优势 + +除了哈希表之外,还可以使用以下数据结构来实现上述查询功能: + +- **无序数组:** 每个元素为 `[学号, 姓名]` ; +- **有序数组:** 将 `1.` 中的数组按照学号从小到大排序; +- **链表:** 每个结点的值为 `[学号, 姓名]` ; +- **二叉搜索树:** 每个结点的值为 `[学号, 姓名]` ,根据学号大小来构建树; + +使用上述方法,各项操作的时间复杂度如下表所示(在此不做赘述,详解可见 [二叉搜索树章节](https://www.hello-algo.com/chapter_tree/binary_search_tree/#_6))。无论是查找元素、还是增删元素,哈希表的时间复杂度都是 $O(1)$ ,全面胜出! + +
+ +| | 无序数组 | 有序数组 | 链表 | 二叉搜索树 | 哈希表 | +| -------- | -------- | ----------- | ------ | ----------- | ------ | +| 查找元素 | $O(n)$ | $O(\log n)$ | $O(n)$ | $O(\log n)$ | $O(1)$ | +| 插入元素 | $O(1)$ | $O(n)$ | $O(1)$ | $O(\log n)$ | $O(1)$ | +| 删除元素 | $O(n)$ | $O(n)$ | $O(n)$ | $O(\log n)$ | $O(1)$ | + +
## 哈希表常用操作 @@ -18,19 +43,19 @@ Map map = new HashMap<>(); /* 添加操作 */ // 在哈希表中添加键值对 (key, value) -map.put(10001, "小哈"); -map.put(10002, "小啰"); -map.put(10003, "小算"); -map.put(10004, "小法"); -map.put(10005, "小哇"); +map.put(12836, "小哈"); +map.put(15937, "小啰"); +map.put(16750, "小算"); +map.put(13276, "小法"); +map.put(10583, "小鸭"); /* 查询操作 */ // 向哈希表输入键 key ,得到值 value -String name = map.get(10002); +String name = map.get(15937); /* 删除操作 */ // 在哈希表中删除键值对 (key, value) -map.remove(10005); +map.remove(10583); ``` 遍历哈希表有三种方式,即 **遍历键值对、遍历键、遍历值**。 @@ -51,28 +76,6 @@ for (String val: map.values()) { } ``` -## 哈希表优势 - -给定一个包含 $n$ 个学生的数据库,每个学生有 "姓名 `name` ” 和 “学号 `id` ” 两项数据,希望实现一个查询功能,即 **输入一个学号,返回对应的姓名**,那么可以使用哪些数据结构来存储呢? - -- **无序数组:** 每个元素为 `[学号, 姓名]` ; -- **有序数组:** 将 `1.` 中的数组按照学号从小到大排序; -- **链表:** 每个结点的值为 `[学号, 姓名]` ; -- **二叉搜索树:** 每个结点的值为 `[学号, 姓名]` ,根据学号大小来构建树; -- **哈希表:** 以学号为 Key 、姓名为 Value 。 - -使用上述方法,各项操作的时间复杂度如下表所示(在此不做赘述,详解可见 [二叉搜索树章节](https://www.hello-algo.com/chapter_tree/binary_search_tree/#_6)),**哈希表全面胜出!** - -
- -| | 无序数组 | 有序数组 | 链表 | 二叉搜索树 | 哈希表 | -| ------------ | -------- | ----------- | ------ | ----------- | ------ | -| 查找指定元素 | $O(n)$ | $O(\log n)$ | $O(n)$ | $O(\log n)$ | $O(1)$ | -| 插入元素 | $O(1)$ | $O(n)$ | $O(1)$ | $O(\log n)$ | $O(1)$ | -| 删除元素 | $O(n)$ | $O(n)$ | $O(n)$ | $O(\log n)$ | $O(1)$ | - -
- ## 哈希函数 哈希表中存储元素的数据结构被称为「桶 Bucket」,底层实现可能是数组、链表、二叉树(红黑树),或是它们的组合。 @@ -87,10 +90,12 @@ for (String val: map.values()) { 以上述学生数据 `Key 学号 -> Value 姓名` 为例,我们可以将「哈希函数」设计为 $$ -f(x) = x \% 10000 +f(x) = x \% 100 $$ -(图) +![hash_function](hash_map.assets/hash_function.png) + +

Fig. 哈希函数

```java title="array_hash_map.java" /* 键值对 int->String */ @@ -107,16 +112,16 @@ class Entry { class ArrayHashMap { private List bucket; public ArrayHashMap() { - // 初始化一个长度为 10 的桶(数组) + // 初始化一个长度为 100 的桶(数组) bucket = new ArrayList<>(); - for (int i = 0; i < 10; i++) { + for (int i = 0; i < 100; i++) { bucket.add(null); } } /* 哈希函数 */ private int hashFunc(int key) { - int index = key % 10000; + int index = key % 100; return index; } @@ -146,8 +151,18 @@ class ArrayHashMap { ## 哈希冲突 -细心的同学可能会发现,哈希函数 $f(x) = x \% 10000$ 会在某些情况下失效。例如,当输入的 Key 为 10001, 20001, 30001, ... 时,哈希函数的计算结果都是 1 ,指向同一个 Value ,表明不同学号指向了同一个人,这明显是不对的。 +细心的同学可能会发现,**哈希函数 $f(x) = x \% 100$ 会在某些情况下失效**。具体地,当输入的 Key 后两位相同时,哈希函数的计算结果也相同,指向同一个 Value 。例如,分别查询两个学号 12836 和 20336 ,则有 +$$ +f(12836) = f(20336) = 36 +$$ +导致两个学号指向了同一个姓名,这明显是不对的。我们将这种现象称为「哈希冲突 Hash Collision」,其会严重影响查询的正确性,我们将如何避免哈希冲突的问题留在下章讨论。 + +![hash_collision](hash_map.assets/hash_collision.png) + +

Fig. 哈希冲突

-上述现象被称为「哈希冲突 Hash Collision」,其会严重影响查询的正确性,我们将如何避免哈希冲突的问题留在下章讨论。 +综上所述,一个优秀的「哈希函数」应该具备以下特性: -(图) +- 尽量少地发生哈希冲突; +- 时间复杂度 $O(1)$ ,计算尽可能高效; +- 空间使用率高,即 “键值对占用空间 / 哈希表总占用空间” 尽可能大; diff --git a/docs/chapter_introduction/index.assets/look_up_dictionary.png b/docs/chapter_introduction/index.assets/look_up_dictionary.png deleted file mode 100644 index 0a24f6153..000000000 Binary files a/docs/chapter_introduction/index.assets/look_up_dictionary.png and /dev/null differ diff --git a/docs/chapter_introduction/index.assets/look_up_dictionary_step_1.png b/docs/chapter_introduction/index.assets/look_up_dictionary_step_1.png index b76e3db0c..f05b05178 100644 Binary files a/docs/chapter_introduction/index.assets/look_up_dictionary_step_1.png and b/docs/chapter_introduction/index.assets/look_up_dictionary_step_1.png differ diff --git a/docs/chapter_introduction/index.assets/look_up_dictionary_step_2.png b/docs/chapter_introduction/index.assets/look_up_dictionary_step_2.png index 08f0bf2d2..c4cc5d9d4 100644 Binary files a/docs/chapter_introduction/index.assets/look_up_dictionary_step_2.png and b/docs/chapter_introduction/index.assets/look_up_dictionary_step_2.png differ diff --git a/docs/chapter_introduction/index.assets/look_up_dictionary_step_3.png b/docs/chapter_introduction/index.assets/look_up_dictionary_step_3.png index 6b91df4e5..828c62606 100644 Binary files a/docs/chapter_introduction/index.assets/look_up_dictionary_step_3.png and b/docs/chapter_introduction/index.assets/look_up_dictionary_step_3.png differ diff --git a/docs/chapter_introduction/index.assets/look_up_dictionary_step_4.png b/docs/chapter_introduction/index.assets/look_up_dictionary_step_4.png index fd3f43333..c13db8dac 100644 Binary files a/docs/chapter_introduction/index.assets/look_up_dictionary_step_4.png and b/docs/chapter_introduction/index.assets/look_up_dictionary_step_4.png differ diff --git a/docs/chapter_introduction/index.assets/look_up_dictionary_step_5.png b/docs/chapter_introduction/index.assets/look_up_dictionary_step_5.png index 4eff15e80..ccd4f7ffa 100644 Binary files a/docs/chapter_introduction/index.assets/look_up_dictionary_step_5.png and b/docs/chapter_introduction/index.assets/look_up_dictionary_step_5.png differ diff --git a/docs/chapter_introduction/index.assets/relationship_between_data_structure_and_algorithm.png b/docs/chapter_introduction/index.assets/relationship_between_data_structure_and_algorithm.png index 82e610a96..1ab8721df 100644 Binary files a/docs/chapter_introduction/index.assets/relationship_between_data_structure_and_algorithm.png and b/docs/chapter_introduction/index.assets/relationship_between_data_structure_and_algorithm.png differ diff --git a/docs/chapter_preface/about_me.md b/docs/chapter_preface/about_me.md index 1b6dc2a18..29bd0bdb9 100644 --- a/docs/chapter_preface/about_me.md +++ b/docs/chapter_preface/about_me.md @@ -10,4 +10,4 @@ comments: true

力扣(LeetCode)全网阅读量最高博主

分享近百道算法题解,累积回复数千读者的评论问题

-

创作 LeetBook《图解算法数据结构》,已免费售出 21 万本

+

创作 LeetBook《图解算法数据结构》,已免费售出 22 万本

diff --git a/docs/chapter_preface/index.md b/docs/chapter_preface/index.md index 0defc4a99..896f6e0c5 100644 --- a/docs/chapter_preface/index.md +++ b/docs/chapter_preface/index.md @@ -44,7 +44,7 @@ comments: true 首先介绍数据结构与算法的评价维度、算法效率的评估方法,引出了计算复杂度概念。 -接下来,从 **函数渐进上界** 入手,分别介绍了 **时间复杂度** 和 **空间复杂度** ,包括推算方法、常见类型、示例等。同时,剖析了 **最差、最佳、平均** 时间复杂度的联系与区别。 +接下来,从 **函数渐近上界** 入手,分别介绍了 **时间复杂度** 和 **空间复杂度** ,包括推算方法、常见类型、示例等。同时,剖析了 **最差、最佳、平均** 时间复杂度的联系与区别。 ### 数据结构 diff --git a/docs/chapter_preface/suggestions.assets/learning_route.png b/docs/chapter_preface/suggestions.assets/learning_route.png index 7423808d6..1f9e39844 100644 Binary files a/docs/chapter_preface/suggestions.assets/learning_route.png and b/docs/chapter_preface/suggestions.assets/learning_route.png differ diff --git a/docs/chapter_searching/binary_search.assets/binary_search_step1.png b/docs/chapter_searching/binary_search.assets/binary_search_step1.png index 6c26916e7..7748b3437 100644 Binary files a/docs/chapter_searching/binary_search.assets/binary_search_step1.png and b/docs/chapter_searching/binary_search.assets/binary_search_step1.png differ diff --git a/docs/chapter_searching/binary_search.assets/binary_search_step2.png b/docs/chapter_searching/binary_search.assets/binary_search_step2.png index 6f100faf9..fba2f959a 100644 Binary files a/docs/chapter_searching/binary_search.assets/binary_search_step2.png and b/docs/chapter_searching/binary_search.assets/binary_search_step2.png differ diff --git a/docs/chapter_searching/binary_search.assets/binary_search_step3.png b/docs/chapter_searching/binary_search.assets/binary_search_step3.png index afc4b2ad3..663ffcd26 100644 Binary files a/docs/chapter_searching/binary_search.assets/binary_search_step3.png and b/docs/chapter_searching/binary_search.assets/binary_search_step3.png differ diff --git a/docs/chapter_searching/binary_search.assets/binary_search_step4.png b/docs/chapter_searching/binary_search.assets/binary_search_step4.png index 71988301b..728b4cb1a 100644 Binary files a/docs/chapter_searching/binary_search.assets/binary_search_step4.png and b/docs/chapter_searching/binary_search.assets/binary_search_step4.png differ diff --git a/docs/chapter_searching/binary_search.assets/binary_search_step5.png b/docs/chapter_searching/binary_search.assets/binary_search_step5.png index 8cd4c64b7..1710f2433 100644 Binary files a/docs/chapter_searching/binary_search.assets/binary_search_step5.png and b/docs/chapter_searching/binary_search.assets/binary_search_step5.png differ diff --git a/docs/chapter_searching/binary_search.assets/binary_search_step6.png b/docs/chapter_searching/binary_search.assets/binary_search_step6.png index a82323c25..b0f6ab1b8 100644 Binary files a/docs/chapter_searching/binary_search.assets/binary_search_step6.png and b/docs/chapter_searching/binary_search.assets/binary_search_step6.png differ diff --git a/docs/chapter_searching/binary_search.assets/binary_search_step7.png b/docs/chapter_searching/binary_search.assets/binary_search_step7.png index f34257e38..20bbcec0f 100644 Binary files a/docs/chapter_searching/binary_search.assets/binary_search_step7.png and b/docs/chapter_searching/binary_search.assets/binary_search_step7.png differ diff --git a/docs/chapter_searching/binary_search.md b/docs/chapter_searching/binary_search.md index d0e4a6db9..0a407ff91 100644 --- a/docs/chapter_searching/binary_search.md +++ b/docs/chapter_searching/binary_search.md @@ -123,7 +123,24 @@ $$ === "Go" ```go title="binary_search.go" - + /* 二分查找(左闭右开) */ + func binarySearch1(nums []int, target int) int { + // 初始化左闭右开 [0, n) ,即 i, j 分别指向数组首元素、尾元素+1 + i, j := 0, len(nums) + // 循环,当搜索区间为空时跳出(当 i = j 时为空) + for i < j { + m := (i + j) / 2 // 计算中点索引 m + if nums[m] < target { // 此情况说明 target 在区间 [m+1, j) 中 + i = m + 1 + } else if nums[m] > target { // 此情况说明 target 在区间 [i, m) 中 + j = m + } else { // 找到目标元素,返回其索引 + return m + } + } + // 未找到目标元素,返回 -1 + return -1 + } ``` === "JavaScript" @@ -220,7 +237,24 @@ $$ === "Go" ```go title="binary_search.go" - + /* 二分查找(左闭右开) */ + func binarySearch1(nums []int, target int) int { + // 初始化左闭右开 [0, n) ,即 i, j 分别指向数组首元素、尾元素+1 + i, j := 0, len(nums) + // 循环,当搜索区间为空时跳出(当 i = j 时为空) + for i < j { + m := (i + j) / 2 // 计算中点索引 m + if nums[m] < target { // 此情况说明 target 在区间 [m+1, j) 中 + i = m + 1 + } else if nums[m] > target { // 此情况说明 target 在区间 [i, m) 中 + j = m + } else { // 找到目标元素,返回其索引 + return m + } + } + // 未找到目标元素,返回 -1 + return -1 + } ``` === "JavaScript" @@ -294,7 +328,10 @@ $$ === "Go" ```go title="" - + // (i + j) 有可能超出 int 的取值范围 + m := (i + j) / 2 + // 更换为此写法则不会越界 + m := i + (j - i) / 2 ``` === "JavaScript" diff --git a/docs/chapter_searching/hashing_search.assets/hash_search_index.png b/docs/chapter_searching/hashing_search.assets/hash_search_index.png index 51dcebc6c..ab9f0b6b4 100644 Binary files a/docs/chapter_searching/hashing_search.assets/hash_search_index.png and b/docs/chapter_searching/hashing_search.assets/hash_search_index.png differ diff --git a/docs/chapter_searching/hashing_search.assets/hash_search_listnode.png b/docs/chapter_searching/hashing_search.assets/hash_search_listnode.png index 26f3c0ba7..dd1ed8fab 100644 Binary files a/docs/chapter_searching/hashing_search.assets/hash_search_listnode.png and b/docs/chapter_searching/hashing_search.assets/hash_search_listnode.png differ diff --git a/docs/chapter_searching/linear_search.assets/linear_search.png b/docs/chapter_searching/linear_search.assets/linear_search.png index 722904e3c..01c26cbea 100644 Binary files a/docs/chapter_searching/linear_search.assets/linear_search.png and b/docs/chapter_searching/linear_search.assets/linear_search.png differ diff --git a/docs/chapter_sorting/bubble_sort.assets/bubble_operation_step1.png b/docs/chapter_sorting/bubble_sort.assets/bubble_operation_step1.png index f1790fc4c..9b72415ed 100644 Binary files a/docs/chapter_sorting/bubble_sort.assets/bubble_operation_step1.png and b/docs/chapter_sorting/bubble_sort.assets/bubble_operation_step1.png differ diff --git a/docs/chapter_sorting/bubble_sort.assets/bubble_operation_step2.png b/docs/chapter_sorting/bubble_sort.assets/bubble_operation_step2.png index 653f78047..b4d9588d2 100644 Binary files a/docs/chapter_sorting/bubble_sort.assets/bubble_operation_step2.png and b/docs/chapter_sorting/bubble_sort.assets/bubble_operation_step2.png differ diff --git a/docs/chapter_sorting/bubble_sort.assets/bubble_operation_step3.png b/docs/chapter_sorting/bubble_sort.assets/bubble_operation_step3.png index 3a1bfb57c..bc44269ce 100644 Binary files a/docs/chapter_sorting/bubble_sort.assets/bubble_operation_step3.png and b/docs/chapter_sorting/bubble_sort.assets/bubble_operation_step3.png differ diff --git a/docs/chapter_sorting/bubble_sort.assets/bubble_operation_step4.png b/docs/chapter_sorting/bubble_sort.assets/bubble_operation_step4.png index 5d1a6abf2..126f24db7 100644 Binary files a/docs/chapter_sorting/bubble_sort.assets/bubble_operation_step4.png and b/docs/chapter_sorting/bubble_sort.assets/bubble_operation_step4.png differ diff --git a/docs/chapter_sorting/bubble_sort.assets/bubble_operation_step5.png b/docs/chapter_sorting/bubble_sort.assets/bubble_operation_step5.png index c0d00d9c0..0d4335767 100644 Binary files a/docs/chapter_sorting/bubble_sort.assets/bubble_operation_step5.png and b/docs/chapter_sorting/bubble_sort.assets/bubble_operation_step5.png differ diff --git a/docs/chapter_sorting/bubble_sort.assets/bubble_operation_step6.png b/docs/chapter_sorting/bubble_sort.assets/bubble_operation_step6.png index 94d187634..265b063f5 100644 Binary files a/docs/chapter_sorting/bubble_sort.assets/bubble_operation_step6.png and b/docs/chapter_sorting/bubble_sort.assets/bubble_operation_step6.png differ diff --git a/docs/chapter_sorting/bubble_sort.assets/bubble_operation_step7.png b/docs/chapter_sorting/bubble_sort.assets/bubble_operation_step7.png index bc565e742..3899ca716 100644 Binary files a/docs/chapter_sorting/bubble_sort.assets/bubble_operation_step7.png and b/docs/chapter_sorting/bubble_sort.assets/bubble_operation_step7.png differ diff --git a/docs/chapter_sorting/bubble_sort.assets/bubble_sort.png b/docs/chapter_sorting/bubble_sort.assets/bubble_sort.png index b6bd51f92..693d915a2 100644 Binary files a/docs/chapter_sorting/bubble_sort.assets/bubble_sort.png and b/docs/chapter_sorting/bubble_sort.assets/bubble_sort.png differ diff --git a/docs/chapter_sorting/bubble_sort.md b/docs/chapter_sorting/bubble_sort.md index 05ef478b0..488c57561 100644 --- a/docs/chapter_sorting/bubble_sort.md +++ b/docs/chapter_sorting/bubble_sort.md @@ -6,7 +6,7 @@ comments: true 「冒泡排序 Bubble Sort」是一种最基础的排序算法,非常适合作为第一个学习的排序算法。顾名思义,「冒泡」是该算法的核心操作。 -!!! tip "为什么叫 “冒泡”" +!!! question "为什么叫 “冒泡”" 在水中,越大的泡泡浮力越大,所以最大的泡泡会最先浮到水面。 @@ -112,7 +112,19 @@ comments: true === "Go" ```go title="bubble_sort.go" - + /* 冒泡排序 */ + func bubbleSort(nums []int) { + // 外循环:待排序元素数量为 n-1, n-2, ..., 1 + for i := len(nums) - 1; i > 0; i-- { + // 内循环:冒泡操作 + for j := 0; j < i; j++ { + if nums[j] > nums[j+1] { + // 交换 nums[j] 与 nums[j + 1] + nums[j], nums[j+1] = nums[j+1], nums[j] + } + } + } + } ``` === "JavaScript" @@ -239,7 +251,24 @@ comments: true === "Go" ```go title="bubble_sort.go" - + /* 冒泡排序(标志优化)*/ + func bubbleSortWithFlag(nums []int) { + // 外循环:待排序元素数量为 n-1, n-2, ..., 1 + for i := len(nums) - 1; i > 0; i-- { + flag := false // 初始化标志位 + // 内循环:冒泡操作 + for j := 0; j < i; j++ { + if nums[j] > nums[j+1] { + // 交换 nums[j] 与 nums[j + 1] + nums[j], nums[j+1] = nums[j+1], nums[j] + flag = true // 记录交换元素 + } + } + if flag == false { // 此轮冒泡未交换任何元素,直接跳出 + break + } + } + } ``` === "JavaScript" diff --git a/docs/chapter_sorting/insertion_sort.assets/insertion_operation.png b/docs/chapter_sorting/insertion_sort.assets/insertion_operation.png index 75c6e47a3..cdaaa4e1a 100644 Binary files a/docs/chapter_sorting/insertion_sort.assets/insertion_operation.png and b/docs/chapter_sorting/insertion_sort.assets/insertion_operation.png differ diff --git a/docs/chapter_sorting/insertion_sort.assets/insertion_sort.png b/docs/chapter_sorting/insertion_sort.assets/insertion_sort.png index 6e5ca0c08..61ee43dfe 100644 Binary files a/docs/chapter_sorting/insertion_sort.assets/insertion_sort.png and b/docs/chapter_sorting/insertion_sort.assets/insertion_sort.png differ diff --git a/docs/chapter_sorting/quick_sort.assets/pivot_division_step8.png b/docs/chapter_sorting/quick_sort.assets/pivot_division_step8.png index 418b17cb4..acb723b77 100644 Binary files a/docs/chapter_sorting/quick_sort.assets/pivot_division_step8.png and b/docs/chapter_sorting/quick_sort.assets/pivot_division_step8.png differ diff --git a/docs/chapter_sorting/quick_sort.assets/pivot_division_step9.png b/docs/chapter_sorting/quick_sort.assets/pivot_division_step9.png index 3e423596a..c07b45749 100644 Binary files a/docs/chapter_sorting/quick_sort.assets/pivot_division_step9.png and b/docs/chapter_sorting/quick_sort.assets/pivot_division_step9.png differ diff --git a/docs/chapter_stack_and_queue/deque.assets/deque_operations.png b/docs/chapter_stack_and_queue/deque.assets/deque_operations.png index 94ede7b2b..242ea98c5 100644 Binary files a/docs/chapter_stack_and_queue/deque.assets/deque_operations.png and b/docs/chapter_stack_and_queue/deque.assets/deque_operations.png differ diff --git a/docs/chapter_stack_and_queue/queue.assets/queue_operations.png b/docs/chapter_stack_and_queue/queue.assets/queue_operations.png index 61e433c5c..b165cd10d 100644 Binary files a/docs/chapter_stack_and_queue/queue.assets/queue_operations.png and b/docs/chapter_stack_and_queue/queue.assets/queue_operations.png differ diff --git a/docs/chapter_stack_and_queue/queue.md b/docs/chapter_stack_and_queue/queue.md index a663b9745..c27058519 100644 --- a/docs/chapter_stack_and_queue/queue.md +++ b/docs/chapter_stack_and_queue/queue.md @@ -20,13 +20,13 @@ comments: true
-| 方法 | 描述 | -| --------- | ------------------------ | -| offer() | 元素入队,即将元素添加至队尾 | -| poll() | 队首元素出队 | -| front() | 访问队首元素 | -| size() | 获取队列的长度 | -| isEmpty() | 判断队列是否为空 | +| 方法 | 描述 | +| --------- | ---------------------------- | +| offer() | 元素入队,即将元素添加至队尾 | +| poll() | 队首元素出队 | +| front() | 访问队首元素 | +| size() | 获取队列的长度 | +| isEmpty() | 判断队列是否为空 |
@@ -143,13 +143,59 @@ comments: true === "JavaScript" ```js title="queue.js" + /* 初始化队列 */ + // JavaScript 没有内置的队列,可以把 Array 当作队列来使用 + // 注意:由于是数组,所以 shift() 的时间复杂度是 O(n) + const queue = []; + + /* 元素入队 */ + queue.push(1); + queue.push(3); + queue.push(2); + queue.push(5); + queue.push(4); + /* 访问队首元素 */ + const peek = queue[0]; + + /* 元素出队 */ + // O(n) + const poll = queue.shift(); + + /* 获取队列的长度 */ + const size = queue.length; + + /* 判断队列是否为空 */ + const empty = queue.length === 0; ``` === "TypeScript" ```typescript title="queue.ts" + /* 初始化队列 */ + // TypeScript 没有内置的队列,可以把 Array 当作队列来使用 + // 注意:由于是数组,所以 shift() 的时间复杂度是 O(n) + const queue: number[] = []; + + /* 元素入队 */ + queue.push(1); + queue.push(3); + queue.push(2); + queue.push(5); + queue.push(4); + /* 访问队首元素 */ + const peek = queue[0]; + + /* 元素出队 */ + // O(n) + const poll = queue.shift(); + + /* 获取队列的长度 */ + const size = queue.length; + + /* 判断队列是否为空 */ + const empty = queue.length === 0; ``` === "C" diff --git a/docs/chapter_stack_and_queue/stack.assets/stack_operations.png b/docs/chapter_stack_and_queue/stack.assets/stack_operations.png index 3c42ee229..59acdacb9 100644 Binary files a/docs/chapter_stack_and_queue/stack.assets/stack_operations.png and b/docs/chapter_stack_and_queue/stack.assets/stack_operations.png differ diff --git a/docs/chapter_stack_and_queue/stack.md b/docs/chapter_stack_and_queue/stack.md index eed703353..d988bdfe7 100644 --- a/docs/chapter_stack_and_queue/stack.md +++ b/docs/chapter_stack_and_queue/stack.md @@ -397,13 +397,13 @@ comments: true === "JavaScript" ```js title="linkedlist_stack.js" - + ``` === "TypeScript" ```typescript title="linkedlist_stack.ts" - + ``` === "C" @@ -587,13 +587,93 @@ comments: true === "JavaScript" ```js title="array_stack.js" + /* 基于数组实现的栈 */ + class ArrayStack { + stack; + constructor() { + this.stack = []; + } + /* 获取栈的长度 */ + get size() { + return this.stack.length; + } + + /* 判断栈是否为空 */ + empty() { + return this.stack.length === 0; + } + /* 入栈 */ + push(num) { + this.stack.push(num); + } + + /* 出栈 */ + pop() { + return this.stack.pop(); + } + + /* 访问栈顶元素 */ + top() { + return this.stack[this.stack.length - 1]; + } + + /* 访问索引 index 处元素 */ + get(index) { + return this.stack[index]; + } + + /* 返回 Array */ + toArray() { + return this.stack; + } + }; ``` === "TypeScript" ```typescript title="array_stack.ts" + /* 基于数组实现的栈 */ + class ArrayStack { + private stack: number[]; + constructor() { + this.stack = []; + } + /* 获取栈的长度 */ + get size(): number { + return this.stack.length; + } + + /* 判断栈是否为空 */ + empty(): boolean { + return this.stack.length === 0; + } + + /* 入栈 */ + push(num: number): void { + this.stack.push(num); + } + /* 出栈 */ + pop(): number | undefined { + return this.stack.pop(); + } + + /* 访问栈顶元素 */ + top(): number | undefined { + return this.stack[this.stack.length - 1]; + } + + /* 访问索引 index 处元素 */ + get(index: number): number | undefined { + return this.stack[index]; + } + + /* 返回 Array */ + toArray() { + return this.stack; + } + }; ``` === "C" diff --git a/docs/chapter_tree/binary_search_tree.assets/binary_search_tree.png b/docs/chapter_tree/binary_search_tree.assets/binary_search_tree.png index 7903e3618..b1c71f14e 100644 Binary files a/docs/chapter_tree/binary_search_tree.assets/binary_search_tree.png and b/docs/chapter_tree/binary_search_tree.assets/binary_search_tree.png differ diff --git a/docs/chapter_tree/binary_search_tree.assets/bst_degradation.png b/docs/chapter_tree/binary_search_tree.assets/bst_degradation.png index 650ddafef..fcacaa028 100644 Binary files a/docs/chapter_tree/binary_search_tree.assets/bst_degradation.png and b/docs/chapter_tree/binary_search_tree.assets/bst_degradation.png differ diff --git a/docs/chapter_tree/binary_search_tree.assets/bst_insert.png b/docs/chapter_tree/binary_search_tree.assets/bst_insert.png index a1084f7be..8e64eac32 100644 Binary files a/docs/chapter_tree/binary_search_tree.assets/bst_insert.png and b/docs/chapter_tree/binary_search_tree.assets/bst_insert.png differ diff --git a/docs/chapter_tree/binary_search_tree.assets/bst_remove_case1.png b/docs/chapter_tree/binary_search_tree.assets/bst_remove_case1.png index 84e6ebb78..fd9f5cde8 100644 Binary files a/docs/chapter_tree/binary_search_tree.assets/bst_remove_case1.png and b/docs/chapter_tree/binary_search_tree.assets/bst_remove_case1.png differ diff --git a/docs/chapter_tree/binary_search_tree.assets/bst_remove_case2.png b/docs/chapter_tree/binary_search_tree.assets/bst_remove_case2.png index fb8f01739..daf11618e 100644 Binary files a/docs/chapter_tree/binary_search_tree.assets/bst_remove_case2.png and b/docs/chapter_tree/binary_search_tree.assets/bst_remove_case2.png differ diff --git a/docs/chapter_tree/binary_search_tree.assets/bst_remove_case3_1.png b/docs/chapter_tree/binary_search_tree.assets/bst_remove_case3_1.png index d328fa7c7..ce70ba330 100644 Binary files a/docs/chapter_tree/binary_search_tree.assets/bst_remove_case3_1.png and b/docs/chapter_tree/binary_search_tree.assets/bst_remove_case3_1.png differ diff --git a/docs/chapter_tree/binary_search_tree.assets/bst_remove_case3_2.png b/docs/chapter_tree/binary_search_tree.assets/bst_remove_case3_2.png index 6e8627e2e..1f1a2b99b 100644 Binary files a/docs/chapter_tree/binary_search_tree.assets/bst_remove_case3_2.png and b/docs/chapter_tree/binary_search_tree.assets/bst_remove_case3_2.png differ diff --git a/docs/chapter_tree/binary_search_tree.assets/bst_remove_case3_3.png b/docs/chapter_tree/binary_search_tree.assets/bst_remove_case3_3.png index a6c85e8af..d9ef7f749 100644 Binary files a/docs/chapter_tree/binary_search_tree.assets/bst_remove_case3_3.png and b/docs/chapter_tree/binary_search_tree.assets/bst_remove_case3_3.png differ diff --git a/docs/chapter_tree/binary_search_tree.assets/bst_remove_case3_4.png b/docs/chapter_tree/binary_search_tree.assets/bst_remove_case3_4.png index 7f4cf33e1..43da8c11b 100644 Binary files a/docs/chapter_tree/binary_search_tree.assets/bst_remove_case3_4.png and b/docs/chapter_tree/binary_search_tree.assets/bst_remove_case3_4.png differ diff --git a/docs/chapter_tree/binary_search_tree.assets/bst_search_1.png b/docs/chapter_tree/binary_search_tree.assets/bst_search_1.png index f40f22a6a..8257ef078 100644 Binary files a/docs/chapter_tree/binary_search_tree.assets/bst_search_1.png and b/docs/chapter_tree/binary_search_tree.assets/bst_search_1.png differ diff --git a/docs/chapter_tree/binary_search_tree.assets/bst_search_2.png b/docs/chapter_tree/binary_search_tree.assets/bst_search_2.png index 3e41330f5..3cab42e56 100644 Binary files a/docs/chapter_tree/binary_search_tree.assets/bst_search_2.png and b/docs/chapter_tree/binary_search_tree.assets/bst_search_2.png differ diff --git a/docs/chapter_tree/binary_search_tree.assets/bst_search_3.png b/docs/chapter_tree/binary_search_tree.assets/bst_search_3.png index 110a170ea..48d019dcc 100644 Binary files a/docs/chapter_tree/binary_search_tree.assets/bst_search_3.png and b/docs/chapter_tree/binary_search_tree.assets/bst_search_3.png differ diff --git a/docs/chapter_tree/binary_search_tree.assets/bst_search_4.png b/docs/chapter_tree/binary_search_tree.assets/bst_search_4.png index 6d8d5b679..a745e0a54 100644 Binary files a/docs/chapter_tree/binary_search_tree.assets/bst_search_4.png and b/docs/chapter_tree/binary_search_tree.assets/bst_search_4.png differ diff --git a/docs/chapter_tree/binary_tree.assets/binary_tree_add_remove.png b/docs/chapter_tree/binary_tree.assets/binary_tree_add_remove.png index f28476b96..b7922fcb3 100644 Binary files a/docs/chapter_tree/binary_tree.assets/binary_tree_add_remove.png and b/docs/chapter_tree/binary_tree.assets/binary_tree_add_remove.png differ diff --git a/docs/chapter_tree/binary_tree.assets/binary_tree_bfs.png b/docs/chapter_tree/binary_tree.assets/binary_tree_bfs.png index 0d9a11a67..9d2a4d039 100644 Binary files a/docs/chapter_tree/binary_tree.assets/binary_tree_bfs.png and b/docs/chapter_tree/binary_tree.assets/binary_tree_bfs.png differ diff --git a/docs/chapter_tree/binary_tree.assets/binary_tree_corner_cases.png b/docs/chapter_tree/binary_tree.assets/binary_tree_corner_cases.png index efe5b8a35..6832f68c9 100644 Binary files a/docs/chapter_tree/binary_tree.assets/binary_tree_corner_cases.png and b/docs/chapter_tree/binary_tree.assets/binary_tree_corner_cases.png differ diff --git a/docs/chapter_tree/binary_tree.assets/binary_tree_definition.png b/docs/chapter_tree/binary_tree.assets/binary_tree_definition.png index 408c1cf0c..94252aff8 100644 Binary files a/docs/chapter_tree/binary_tree.assets/binary_tree_definition.png and b/docs/chapter_tree/binary_tree.assets/binary_tree_definition.png differ diff --git a/docs/chapter_tree/binary_tree.assets/binary_tree_dfs.png b/docs/chapter_tree/binary_tree.assets/binary_tree_dfs.png index c9db5e09e..3104a0ba0 100644 Binary files a/docs/chapter_tree/binary_tree.assets/binary_tree_dfs.png and b/docs/chapter_tree/binary_tree.assets/binary_tree_dfs.png differ diff --git a/docs/chapter_tree/binary_tree.assets/binary_tree_terminology.png b/docs/chapter_tree/binary_tree.assets/binary_tree_terminology.png index 736ad22a1..08c0ccf20 100644 Binary files a/docs/chapter_tree/binary_tree.assets/binary_tree_terminology.png and b/docs/chapter_tree/binary_tree.assets/binary_tree_terminology.png differ diff --git a/docs/chapter_tree/binary_tree_types.assets/balanced_binary_tree.png b/docs/chapter_tree/binary_tree_types.assets/balanced_binary_tree.png index 030cd7abf..afc08723f 100644 Binary files a/docs/chapter_tree/binary_tree_types.assets/balanced_binary_tree.png and b/docs/chapter_tree/binary_tree_types.assets/balanced_binary_tree.png differ diff --git a/docs/chapter_tree/binary_tree_types.assets/complete_binary_tree.png b/docs/chapter_tree/binary_tree_types.assets/complete_binary_tree.png index fe796858d..8d26549a1 100644 Binary files a/docs/chapter_tree/binary_tree_types.assets/complete_binary_tree.png and b/docs/chapter_tree/binary_tree_types.assets/complete_binary_tree.png differ diff --git a/docs/chapter_tree/binary_tree_types.assets/full_binary_tree.png b/docs/chapter_tree/binary_tree_types.assets/full_binary_tree.png index 346ea747e..37043df95 100644 Binary files a/docs/chapter_tree/binary_tree_types.assets/full_binary_tree.png and b/docs/chapter_tree/binary_tree_types.assets/full_binary_tree.png differ diff --git a/docs/chapter_tree/binary_tree_types.assets/perfect_binary_tree.png b/docs/chapter_tree/binary_tree_types.assets/perfect_binary_tree.png index 323bd5be8..95f7194be 100644 Binary files a/docs/chapter_tree/binary_tree_types.assets/perfect_binary_tree.png and b/docs/chapter_tree/binary_tree_types.assets/perfect_binary_tree.png differ diff --git a/docs/index.md b/docs/index.md index 7ea936c19..b0a533086 100644 --- a/docs/index.md +++ b/docs/index.md @@ -56,6 +56,16 @@ hide: --- +## 推荐语 + +!!! quote + + “一本通俗易懂的数据结构与算法入门书,引导读者手脑并用地学习,强烈推荐算法初学者阅读。” + + **—— 邓俊辉,清华大学计算机系教授** + +## 致谢 + 感谢本开源书的每一位撰稿人,是他们的无私奉献让这本书变得更好,他们是: diff --git a/docs/log.md b/docs/log.md deleted file mode 100644 index 3a1d4d8ed..000000000 --- a/docs/log.md +++ /dev/null @@ -1,23 +0,0 @@ -# 更新日志 - -| 更新内容 | 日期 | -| ------------ | ---------- | -| 新增:算法无处不在 | 2022-10-10 | -| 新增:数组与链表 | 2022-10-15 | -| 新增:数据结构简介 | 2022-10-20 | -| 新增:前言 | 2022-10-23 | -| 新增:计算复杂度 | 2022-11-03 | -| 更新:配图 | 2022-11-04 | -| 新增:数据与内存 | 2022-11-05 | -| 更新:各章节 Java 代码 | 2022-11-06 | -| 更新:列表 Java 代码、配图 | 2022-11-07 | -| 新增:栈与队列 | 2022-11-09 | -| 新增:树 | 2022-11-12 | -| 新增:二叉搜索树
更新:二叉树、表格居中 | 2022-11-13 | -| 更新:二叉搜索树 | 2022-11-14 | -| 更新:首页介绍 | 2022-11-15 | -| 更新:关于本书
新增:如何使用本书
新增:一起参与创作 | 2022-11-16 | -| 新增:查找算法 | 2022-11-19 | -| 更新:Markdown Stylesheet
新增:冒泡排序、插入排序 | 2022-11-21 | -| 新增:快速排序 | 2022-11-22 | -| 新增:归并排序,更新:快速排序、关于本书 | 2022-11-23 |