From 281c0c618a2be5b146512f6a66a4ded980f031f9 Mon Sep 17 00:00:00 2001 From: liuyuxin Date: Fri, 2 Jun 2023 14:56:29 +0800 Subject: [PATCH] feat: modify some Dart codes and add Dart code blocks to the docs (#543) --- .../chapter_array_and_linkedlist/array.dart | 18 +++---- .../linked_list.dart | 7 ++- .../chapter_array_and_linkedlist/list.dart | 4 +- .../chapter_array_and_linkedlist/my_list.dart | 4 +- .../space_complexity.dart | 3 +- .../time_complexity.dart | 5 +- .../worst_best_time_complexity.dart | 4 +- codes/dart/chapter_hashing/hash_map.dart | 3 +- codes/dart/chapter_stack_and_queue/deque.dart | 1 - docs/chapter_array_and_linkedlist/array.md | 4 +- .../linked_list.md | 28 ++++++++-- docs/chapter_array_and_linkedlist/list.md | 41 ++++++++++++-- .../backtracking_algorithm.md | 21 +++++++- .../space_complexity.md | 43 ++++++++++++++- .../time_complexity.md | 53 +++++++++++++++++-- .../basic_data_types.md | 6 ++- docs/chapter_hashing/hash_map.md | 31 +++++++++++ docs/chapter_heap/heap.md | 2 +- docs/chapter_preface/suggestions.md | 8 +-- docs/chapter_stack_and_queue/deque.md | 23 ++++++++ docs/chapter_stack_and_queue/queue.md | 21 ++++++++ docs/chapter_stack_and_queue/stack.md | 21 ++++++++ .../array_representation_of_tree.md | 4 +- docs/chapter_tree/avl_tree.md | 9 +++- docs/chapter_tree/binary_tree.md | 29 ++++++++-- 25 files changed, 339 insertions(+), 54 deletions(-) diff --git a/codes/dart/chapter_array_and_linkedlist/array.dart b/codes/dart/chapter_array_and_linkedlist/array.dart index e04748499..a78ee892b 100644 --- a/codes/dart/chapter_array_and_linkedlist/array.dart +++ b/codes/dart/chapter_array_and_linkedlist/array.dart @@ -6,9 +6,9 @@ import 'dart:math'; -/* 随机返回一个 数组元素 */ +/* 随机返回一个数组元素 */ int randomAccess(List nums) { - // 在区间[0,size) 中随机抽取一个数字 + // 在区间 [0, nums.length) 中随机抽取一个数字 int randomIndex = Random().nextInt(nums.length); // 获取并返回随机元素 int randomNum = nums[randomIndex]; @@ -17,9 +17,8 @@ int randomAccess(List nums) { /* 扩展数组长度 */ List extend(List nums, int enlarge) { - // 初始化一个扩展长度后的数组,元素初始值为0 + // 初始化一个扩展长度后的数组 List res = List.filled(nums.length + enlarge, 0); - // 将原数组中的所有元素复制到新数组 for (var i = 0; i < nums.length; i++) { res[i] = nums[i]; @@ -30,7 +29,7 @@ List extend(List nums, int enlarge) { /* 在数组的索引 index 处插入元素 num */ void insert(List nums, int num, int index) { - // 把索引index以及之后的所有元素向后移动一位 + // 把索引 index 以及之后的所有元素向后移动一位 for (var i = nums.length - 1; i > index; i--) { nums[i] = nums[i - 1]; } @@ -40,6 +39,7 @@ void insert(List nums, int num, int index) { /* 删除索引 index 处元素 */ void remove(List nums, int index) { + // 把索引 index 之后的所有元素向前移动一位 for (var i = index; i < nums.length - 1; i++) { nums[i] = nums[i + 1]; } @@ -56,7 +56,7 @@ void traverse(List nums) { for (var num in nums) { count++; } - // 通过forEach方法遍历数组 + // 通过 forEach 方法遍历数组 nums.forEach((element) { count++; }); @@ -71,8 +71,8 @@ int find(List nums, int target) { } /* Driver Code */ -int main() { - /* 初始化固定长度数组 */ +void main() { + /* 初始化数组 */ var arr = List.filled(5, 0); print('数组 arr = $arr'); List nums = [1, 3, 2, 5, 4]; @@ -100,6 +100,4 @@ int main() { /* 查找元素 */ int index = find(nums, 3); print("在 nums 中查找元素 3 ,得到索引 = $index"); - - return 0; } diff --git a/codes/dart/chapter_array_and_linkedlist/linked_list.dart b/codes/dart/chapter_array_and_linkedlist/linked_list.dart index 7fd9afac5..bcc6f9868 100644 --- a/codes/dart/chapter_array_and_linkedlist/linked_list.dart +++ b/codes/dart/chapter_array_and_linkedlist/linked_list.dart @@ -17,6 +17,7 @@ void insert(ListNode n0, ListNode P) { /* 删除链表的节点 n0 之后的首个节点 */ void remove(ListNode n0) { if (n0.next == null) return; + // n0 -> P -> n1 ListNode P = n0.next!; ListNode? n1 = P.next; n0.next = n1; @@ -45,9 +46,9 @@ int find(ListNode? head, int target) { } /* Driver Code */ -int main() { +void main() { // 初始化链表 - //初始化各个节点 + // 初始化各个节点 ListNode n0 = ListNode(1); ListNode n1 = ListNode(3); ListNode n2 = ListNode(2); @@ -79,6 +80,4 @@ int main() { /* 查找节点 */ int index = find(n0, 2); print('链表中值为 2 的节点的索引 = $index'); - - return 0; } diff --git a/codes/dart/chapter_array_and_linkedlist/list.dart b/codes/dart/chapter_array_and_linkedlist/list.dart index 4cad11d21..7617aabe3 100644 --- a/codes/dart/chapter_array_and_linkedlist/list.dart +++ b/codes/dart/chapter_array_and_linkedlist/list.dart @@ -5,7 +5,7 @@ */ /* Driver Code */ -int main() { +void main() { /* 初始化列表 */ List list = [1, 3, 2, 5, 4]; print('列表 list = $list'); @@ -57,6 +57,4 @@ int main() { /* 排序列表 */ list.sort(); print('排序列表后 list = $list'); - - return 0; } diff --git a/codes/dart/chapter_array_and_linkedlist/my_list.dart b/codes/dart/chapter_array_and_linkedlist/my_list.dart index 8d580c269..d7d7d671d 100644 --- a/codes/dart/chapter_array_and_linkedlist/my_list.dart +++ b/codes/dart/chapter_array_and_linkedlist/my_list.dart @@ -94,7 +94,7 @@ class MyList { } /* Driver Code */ -int main() { +void main() { /* 初始化列表 */ MyList list = MyList(); /* 尾部添加元素 */ @@ -129,6 +129,4 @@ int main() { } print( '扩容后的列表 list = ${list.toArray()} ,容量 = ${list.capacity()} ,长度 = ${list.size()}'); - - return 0; } diff --git a/codes/dart/chapter_computational_complexity/space_complexity.dart b/codes/dart/chapter_computational_complexity/space_complexity.dart index b8e010fcc..6b5d8c1aa 100644 --- a/codes/dart/chapter_computational_complexity/space_complexity.dart +++ b/codes/dart/chapter_computational_complexity/space_complexity.dart @@ -89,7 +89,7 @@ TreeNode? buildTree(int n) { } /* Driver Code */ -int main() { +void main() { int n = 5; // 常数阶 constant(n); @@ -102,5 +102,4 @@ int main() { // 指数阶 TreeNode? root = buildTree(n); printTree(root); - return 0; } diff --git a/codes/dart/chapter_computational_complexity/time_complexity.dart b/codes/dart/chapter_computational_complexity/time_complexity.dart index e8fc9e92e..c89b8bb91 100644 --- a/codes/dart/chapter_computational_complexity/time_complexity.dart +++ b/codes/dart/chapter_computational_complexity/time_complexity.dart @@ -50,7 +50,7 @@ int bubbleSort(List nums) { int count = 0; // 计数器 // 外循环:未排序区间为 [0, i] for (var i = nums.length - 1; i > 0; i--) { - // 内循环:将未排序区间 [0, i] 中的最大元素交换至该区间的最右端 + // 内循环:将未排序区间 [0, i] 中的最大元素交换至该区间的最右端 for (var j = 0; j < i; j++) { if (nums[j] > nums[j + 1]) { // 交换 nums[j] 与 nums[j + 1] @@ -122,7 +122,7 @@ int factorialRecur(int n) { } /* Driver Code */ -int main() { +void main() { // 可以修改 n 运行,体会一下各种复杂度的操作数量变化趋势 int n = 8; print('输入数据大小 n = $n'); @@ -160,5 +160,4 @@ int main() { count = factorialRecur(n); print('阶乘阶(递归实现)的计算操作数量 = $count'); - return 0; } diff --git a/codes/dart/chapter_computational_complexity/worst_best_time_complexity.dart b/codes/dart/chapter_computational_complexity/worst_best_time_complexity.dart index 35282fdca..541d3e4d9 100644 --- a/codes/dart/chapter_computational_complexity/worst_best_time_complexity.dart +++ b/codes/dart/chapter_computational_complexity/worst_best_time_complexity.dart @@ -29,7 +29,7 @@ int findOne(List nums) { } /* Driver Code */ -int main() { +void main() { for (var i = 0; i < 10; i++) { int n = 100; final nums = randomNumbers(n); @@ -37,6 +37,4 @@ int main() { print('\n数组 [ 1, 2, ..., n ] 被打乱后 = $nums'); print('数字 1 的索引为 + $index'); } - - return 0; } diff --git a/codes/dart/chapter_hashing/hash_map.dart b/codes/dart/chapter_hashing/hash_map.dart index d174251c4..455752320 100644 --- a/codes/dart/chapter_hashing/hash_map.dart +++ b/codes/dart/chapter_hashing/hash_map.dart @@ -34,7 +34,8 @@ void main() { print("\n遍历键值对 Key->Value"); map.forEach((key, value) => print("$key -> $value")); print("\n单独遍历键 Key"); - map.forEach((key, value) => print("$key")); + map.keys.forEach((key) => print(key)); print("\n单独遍历值 Value"); map.forEach((key, value) => print("$value")); + map.values.forEach((value) => print(value)); } diff --git a/codes/dart/chapter_stack_and_queue/deque.dart b/codes/dart/chapter_stack_and_queue/deque.dart index efbe8cc3b..2161f1041 100644 --- a/codes/dart/chapter_stack_and_queue/deque.dart +++ b/codes/dart/chapter_stack_and_queue/deque.dart @@ -27,7 +27,6 @@ void main() { print("元素 1 队首入队后 deque = $deque"); /* 元素出队 */ - final int popLast = deque.removeLast(); print("队尾出队元素 = $popLast,队尾出队后 deque = $deque"); final int popFirst = deque.removeFirst(); diff --git a/docs/chapter_array_and_linkedlist/array.md b/docs/chapter_array_and_linkedlist/array.md index 37537340b..d6ccb1728 100755 --- a/docs/chapter_array_and_linkedlist/array.md +++ b/docs/chapter_array_and_linkedlist/array.md @@ -95,7 +95,9 @@ === "Dart" ```dart title="array.dart" - + /* 初始化数组 */ + List arr = List.filled(5, 0); // [0, 0, 0, 0, 0] + List nums = [1, 3, 2, 5, 4]; ``` ## 数组优点 diff --git a/docs/chapter_array_and_linkedlist/linked_list.md b/docs/chapter_array_and_linkedlist/linked_list.md index 8753d77f3..f2401062e 100755 --- a/docs/chapter_array_and_linkedlist/linked_list.md +++ b/docs/chapter_array_and_linkedlist/linked_list.md @@ -156,7 +156,12 @@ === "Dart" ```dart title="" - + /* 链表节点类 */ + class ListNode { + int val; // 节点值 + ListNode? next; // 指向下一节点的指针(引用) + ListNode(this.val, [this.next]); // 构造函数 + } ``` !!! question "尾节点指向什么?" @@ -342,7 +347,18 @@ === "Dart" ```dart title="linked_list.dart" - + /* 初始化链表 1 -> 3 -> 2 -> 5 -> 4 */\ + // 初始化各个节点 + ListNode n0 = ListNode(1); + ListNode n1 = ListNode(3); + ListNode n2 = ListNode(2); + ListNode n3 = ListNode(5); + ListNode n4 = ListNode(4); + // 构建引用指向 + n0.next = n1; + n1.next = n2; + n2.next = n3; + n3.next = n4; ``` ## 链表优点 @@ -799,7 +815,13 @@ === "Dart" ```dart title="" - + /* 双向链表节点类 */ + class ListNode { + int val; // 节点值 + ListNode next; // 指向后继节点的指针(引用) + ListNode prev; // 指向前驱节点的指针(引用) + ListNode(this.val, [this.next, this.prev]); // 构造函数 + } ``` ![常见链表种类](linked_list.assets/linkedlist_common_types.png) diff --git a/docs/chapter_array_and_linkedlist/list.md b/docs/chapter_array_and_linkedlist/list.md index 2d3b06d9e..cb39bc8b5 100755 --- a/docs/chapter_array_and_linkedlist/list.md +++ b/docs/chapter_array_and_linkedlist/list.md @@ -109,7 +109,11 @@ === "Dart" ```dart title="list.dart" - + /* 初始化列表 */ + // 无初始值 + List list1 = []; + // 有初始值 + List list = [1, 3, 2, 5, 4]; ``` **访问与更新元素**。由于列表的底层数据结构是数组,因此可以在 $O(1)$ 时间内访问和更新元素,效率很高。 @@ -213,7 +217,11 @@ === "Dart" ```dart title="list.dart" + /* 访问元素 */ + int num = list[1]; // 访问索引 1 处的元素 + /* 更新元素 */ + list[1] = 0; // 将索引 1 处的元素更新为 0 ``` **在列表中添加、插入、删除元素**。相较于数组,列表可以自由地添加与删除元素。在列表尾部添加元素的时间复杂度为 $O(1)$ ,但插入和删除元素的效率仍与数组相同,时间复杂度为 $O(N)$ 。 @@ -407,7 +415,21 @@ === "Dart" ```dart title="list.dart" + /* 清空列表 */ + list.clear(); + + /* 尾部添加元素 */ + list.add(1); + list.add(3); + list.add(2); + list.add(5); + list.add(4); + /* 中间插入元素 */ + list.insert(3, 6); // 在索引 3 处插入数字 6 + + /* 删除元素 */ + list.removeAt(3); // 删除索引 3 处的元素 ``` **遍历列表**。与数组一样,列表可以根据索引遍历,也可以直接遍历各元素。 @@ -566,7 +588,17 @@ === "Dart" ```dart title="list.dart" + /* 通过索引遍历列表 */ + int count = 0; + for (int i = 0; i < list.length; i++) { + count++; + } + /* 直接遍历列表元素 */ + count = 0; + for (int n in list) { + count++; + } ``` **拼接两个列表**。给定一个新列表 `list1` ,我们可以将该列表拼接到原列表的尾部。 @@ -655,7 +687,9 @@ === "Dart" ```dart title="list.dart" - + /* 拼接两个列表 */ + List list1 = [6, 8, 7, 10, 9]; + list.addAll(list1); // 将列表 list1 拼接到 list 之后 ``` **排序列表**。排序也是常用的方法之一。完成列表排序后,我们便可以使用在数组类算法题中经常考察的「二分查找」和「双指针」算法。 @@ -732,7 +766,8 @@ === "Dart" ```dart title="list.dart" - + /* 排序列表 */ + list.sort(); // 排序后,列表元素从小到大排列 ``` ## 列表实现 * diff --git a/docs/chapter_backtracking/backtracking_algorithm.md b/docs/chapter_backtracking/backtracking_algorithm.md index b48e43770..a1b6f506a 100644 --- a/docs/chapter_backtracking/backtracking_algorithm.md +++ b/docs/chapter_backtracking/backtracking_algorithm.md @@ -526,7 +526,26 @@ === "Dart" ```dart title="" - + /* 回溯算法框架 */ + void backtrack(State state, List, List res) { + // 判断是否为解 + if (isSolution(state)) { + // 记录解 + recordSolution(state, res); + return; + } + // 遍历所有选择 + for (Choice choice in choices) { + // 剪枝:判断选择是否合法 + if (isValid(state, choice)) { + // 尝试:做出选择,更新状态 + makeChoice(state, choice); + backtrack(state, choices, res); + // 回退:撤销选择,恢复到之前的状态 + undoChoice(state, choice); + } + } + } ``` 下面,我们尝试基于此框架来解决例题三。在例题三中,状态 `state` 是节点遍历路径,选择 `choices` 是当前节点的左子节点和右子节点,结果 `res` 是路径列表,实现代码如下所示。 diff --git a/docs/chapter_computational_complexity/space_complexity.md b/docs/chapter_computational_complexity/space_complexity.md index 0cd426d64..6edc7e2a3 100755 --- a/docs/chapter_computational_complexity/space_complexity.md +++ b/docs/chapter_computational_complexity/space_complexity.md @@ -261,7 +261,26 @@ === "Dart" ```dart title="" + /* 类 */ + class Node { + int val; + Node next; + Node(this.val, [this.next]); + } + + /* 函数 */ + int function() { + // do something... + return 0; + } + int algorithm(int n) { // 输入数据 + const int a = 0; // 暂存数据(常量) + int b = 0; // 暂存数据(变量) + Node node = Node(0); // 暂存数据(对象) + int c = function(); // 栈帧空间(调用函数) + return a + b + c; // 输出数据 + } ``` ## 推算方法 @@ -389,7 +408,13 @@ === "Dart" ```dart title="" - + void algorithm(int n) { + int a = 0; // O(1) + List b = List.filled(10000, 0); // O(1) + if (n > 10) { + List nums = List.filled(n, 0); // O(n) + } + } ``` **在递归函数中,需要注意统计栈帧空间**。例如,函数 `loop()` 在循环中调用了 $n$ 次 `function()` ,每轮中的 `function()` 都返回并释放了栈帧空间,因此空间复杂度仍为 $O(1)$ 。而递归函数 `recur()` 在运行过程中会同时存在 $n$ 个未返回的 `recur()` ,从而占用 $O(n)$ 的栈帧空间。 @@ -594,7 +619,21 @@ === "Dart" ```dart title="" - + int function() { + // do something + return 0; + } + /* 循环 O(1) */ + void loop(int n) { + for (int i = 0; i < n; i++) { + function(); + } + } + /* 递归 O(n) */ + void recur(int n) { + if (n == 1) return; + return recur(n - 1); + } ``` ## 常见类型 diff --git a/docs/chapter_computational_complexity/time_complexity.md b/docs/chapter_computational_complexity/time_complexity.md index 58fd8be2a..259540fc1 100755 --- a/docs/chapter_computational_complexity/time_complexity.md +++ b/docs/chapter_computational_complexity/time_complexity.md @@ -158,7 +158,16 @@ $$ === "Dart" ```dart title="" - + // 在某运行平台下 + void algorithm(int n) { + int a = 2; // 1 ns + a = a + 1; // 1 ns + a = a * 2; // 10 ns + // 循环 n 次 + for (int i = 0; i < n; i++) { // 1 ns ,每轮都要执行 i++ + print(0); // 5 ns + } + } ``` 然而实际上,**统计算法的运行时间既不合理也不现实**。首先,我们不希望预估时间和运行平台绑定,因为算法需要在各种不同的平台上运行。其次,我们很难获知每种操作的运行时间,这给预估过程带来了极大的难度。 @@ -374,7 +383,22 @@ $$ === "Dart" ```dart title="" - + // 算法 A 时间复杂度:常数阶 + void algorithmA(int n) { + print(0); + } + // 算法 B 时间复杂度:线性阶 + void algorithmB(int n) { + for (int i = 0; i < n; i++) { + print(0); + } + } + // 算法 C 时间复杂度:常数阶 + void algorithmC(int n) { + for (int i = 0; i < 1000000; i++) { + print(0); + } + } ``` ![算法 A, B, C 的时间增长趋势](time_complexity.assets/time_complexity_simple_example.png) @@ -530,7 +554,15 @@ $$ === "Dart" ```dart title="" - + void algorithm(int n) { + int a = 1; // +1 + a = a + 1; // +1 + a = a * 2; // +1 + // 循环 n 次 + for (int i = 0; i < n; i++) { // +1(每轮都执行 i ++) + print(0); // +1 + } + } ``` $T(n)$ 是一次函数,说明时间增长趋势是线性的,因此可以得出时间复杂度是线性阶。 @@ -760,7 +792,20 @@ $$ === "Dart" ```dart title="" - + void algorithm(int n) { + int a = 1; // +0(技巧 1) + a = a + n; // +0(技巧 1) + // +n(技巧 2) + for (int i = 0; i < 5 * n + 1; i++) { + print(0); + } + // +n*n(技巧 3) + for (int i = 0; i < 2 * n; i++) { + for (int j = 0; j < n + 1; j++) { + print(0); + } + } + } ``` ### 2) 判断渐近上界 diff --git a/docs/chapter_data_structure/basic_data_types.md b/docs/chapter_data_structure/basic_data_types.md index d6f9e1043..d6001c3ae 100644 --- a/docs/chapter_data_structure/basic_data_types.md +++ b/docs/chapter_data_structure/basic_data_types.md @@ -133,5 +133,9 @@ === "Dart" ```dart title="" - + /* 使用多种「基本数据类型」来初始化「数组」 */ + List numbers = List.filled(5, 0); + List decimals = List.filled(5, 0.0); + List characters = List.filled(5, 'a'); + List booleans = List.filled(5, false); ``` diff --git a/docs/chapter_hashing/hash_map.md b/docs/chapter_hashing/hash_map.md index 801b6c77e..16771f86d 100755 --- a/docs/chapter_hashing/hash_map.md +++ b/docs/chapter_hashing/hash_map.md @@ -226,7 +226,24 @@ === "Dart" ```dart title="hash_map.dart" + /* 初始化哈希表 */ + Map map = {}; + /* 添加操作 */ + // 在哈希表中添加键值对 (key, value) + map[12836] = "小哈"; + map[15937] = "小啰"; + map[16750] = "小算"; + map[13276] = "小法"; + map[10583] = "小鸭"; + + /* 查询操作 */ + // 向哈希表输入键 key ,得到值 value + String name = map[15937]; + + /* 删除操作 */ + // 在哈希表中删除键值对 (key, value) + map.remove(10583); ``` 遍历哈希表有三种方式,即 **遍历键值对、遍历键、遍历值**。 @@ -390,7 +407,21 @@ === "Dart" ```dart title="hash_map.dart" + /* 遍历哈希表 */ + // 遍历键值对 Key->Value + map.forEach((key, value) { + print('$key -> $value'); + }); + // 单独遍历键 Key + map.keys.forEach((key) { + print(key); + }); + + // 单独遍历值 Value + map.values.forEach((value) { + print(value); + }); ``` ## 哈希函数 diff --git a/docs/chapter_heap/heap.md b/docs/chapter_heap/heap.md index ab20d8b75..69c6f5a30 100644 --- a/docs/chapter_heap/heap.md +++ b/docs/chapter_heap/heap.md @@ -304,7 +304,7 @@ === "Dart" ```dart title="heap.dart" - + // Dart 未提供内置 Heap 类 ``` ## 堆的实现 diff --git a/docs/chapter_preface/suggestions.md b/docs/chapter_preface/suggestions.md index 1551bb9bb..ff9649d0e 100644 --- a/docs/chapter_preface/suggestions.md +++ b/docs/chapter_preface/suggestions.md @@ -147,12 +147,14 @@ === "Dart" ```dart title="" - // 标题注释,用于标注函数、类、测试样例等 + /* 标题注释,用于标注函数、类、测试样例等 */ // 内容注释,用于详解代码 - // 多行 - // 注释 + /** + * 多行 + * 注释 + */ ``` ## 在动画图解中高效学习 diff --git a/docs/chapter_stack_and_queue/deque.md b/docs/chapter_stack_and_queue/deque.md index d761b6caa..9583f2a1e 100644 --- a/docs/chapter_stack_and_queue/deque.md +++ b/docs/chapter_stack_and_queue/deque.md @@ -286,7 +286,30 @@ === "Dart" ```dart title="deque.dart" + /* 初始化双向队列 */ + // 在 Dart 中,Queue 被定义为双向队列 + Queue deque = Queue(); + + /* 元素入队 */ + deque.addLast(2); // 添加至队尾 + deque.addLast(5); + deque.addLast(4); + deque.addFirst(3); // 添加至队首 + deque.addFirst(1); + + /* 访问元素 */ + int peekFirst = deque.first; // 队首元素 + int peekLast = deque.last; // 队尾元素 + /* 元素出队 */ + int popFirst = deque.removeFirst(); // 队首元素出队 + int popLast = deque.removeLast(); // 队尾元素出队 + + /* 获取双向队列的长度 */ + int size = deque.length; + + /* 判断双向队列是否为空 */ + bool isEmpty = deque.isEmpty;W ``` ## 双向队列实现 * diff --git a/docs/chapter_stack_and_queue/queue.md b/docs/chapter_stack_and_queue/queue.md index 6091944b9..e1a720b56 100755 --- a/docs/chapter_stack_and_queue/queue.md +++ b/docs/chapter_stack_and_queue/queue.md @@ -255,7 +255,28 @@ === "Dart" ```dart title="queue.dart" + /* 初始化队列 */ + // 在 Dart 中,队列类 Qeque 是双向队列,也可作为队列使用 + Queue queue = Queue(); + + /* 元素入队 */ + queue.add(1); + queue.add(3); + queue.add(2); + queue.add(5); + queue.add(4); + + /* 访问队首元素 */ + int peek = queue.first; + /* 元素出队 */ + int pop = queue.removeFirst(); + + /* 获取队列的长度 */ + int size = queue.length; + + /* 判断队列是否为空 */ + bool isEmpty = queue.isEmpty; ``` ## 队列实现 diff --git a/docs/chapter_stack_and_queue/stack.md b/docs/chapter_stack_and_queue/stack.md index 8f1574d9c..1c6b6d207 100755 --- a/docs/chapter_stack_and_queue/stack.md +++ b/docs/chapter_stack_and_queue/stack.md @@ -253,7 +253,28 @@ === "Dart" ```dart title="stack.dart" + /* 初始化栈 */ + // Dart 没有内置的栈类,可以把 List 当作栈来使用 + List stack = []; + + /* 元素入栈 */ + stack.add(1); + stack.add(3); + stack.add(2); + stack.add(5); + stack.add(4); + + /* 访问栈顶元素 */ + int peek = stack.last; + /* 元素出栈 */ + int pop = stack.removeLast(); + + /* 获取栈的长度 */ + int size = stack.length; + + /* 判断是否为空 */ + bool isEmpty = stack.isEmpty; ``` ## 栈的实现 diff --git a/docs/chapter_tree/array_representation_of_tree.md b/docs/chapter_tree/array_representation_of_tree.md index 952b08e60..8d4cf2727 100644 --- a/docs/chapter_tree/array_representation_of_tree.md +++ b/docs/chapter_tree/array_representation_of_tree.md @@ -103,7 +103,9 @@ === "Dart" ```dart title="" - + /* 二叉树的数组表示 */ + // 使用 int? 可空类型 ,就可以使用 null 来标记空位 + List tree = [1, 2, 3, 4, null, 6, 7, 8, 9, null, null, 12, null, null, 15]; ``` ![任意类型二叉树的数组表示](binary_tree.assets/array_representation_with_empty.png) diff --git a/docs/chapter_tree/avl_tree.md b/docs/chapter_tree/avl_tree.md index 90c2e094b..6c23d39a5 100644 --- a/docs/chapter_tree/avl_tree.md +++ b/docs/chapter_tree/avl_tree.md @@ -172,7 +172,14 @@ G. M. Adelson-Velsky 和 E. M. Landis 在其 1962 年发表的论文 "An algorit === "Dart" ```dart title="" - + /* AVL 树节点类 */ + class TreeNode { + int val; // 节点值 + int height; // 节点高度 + TreeNode? left; // 左子节点 + TreeNode? right; // 右子节点 + TreeNode(this.val, [this.height = 0, this.left, this.right]); + } ``` 「节点高度」是指从该节点到最远叶节点的距离,即所经过的“边”的数量。需要特别注意的是,叶节点的高度为 0 ,而空节点的高度为 -1 。我们将创建两个工具函数,分别用于获取和更新节点的高度。 diff --git a/docs/chapter_tree/binary_tree.md b/docs/chapter_tree/binary_tree.md index 4ed829eec..cdaf91ef9 100644 --- a/docs/chapter_tree/binary_tree.md +++ b/docs/chapter_tree/binary_tree.md @@ -146,7 +146,13 @@ === "Dart" ```dart title="" - + /* 二叉树节点类 */ + class TreeNode { + int val; // 节点值 + TreeNode? left; // 左子节点指针 + TreeNode? right; // 右子节点指针 + TreeNode(this.val, [this.left, this.right]); + } ``` 节点的两个指针分别指向「左子节点」和「右子节点」,同时该节点被称为这两个子节点的「父节点」。当给定一个二叉树的节点时,我们将该节点的左子节点及其以下节点形成的树称为该节点的「左子树」,同理可得「右子树」。 @@ -338,7 +344,18 @@ === "Dart" ```dart title="binary_tree.dart" - + /* 初始化二叉树 */ + // 初始化节点 + TreeNode n1 = new TreeNode(1); + TreeNode n2 = new TreeNode(2); + TreeNode n3 = new TreeNode(3); + TreeNode n4 = new TreeNode(4); + TreeNode n5 = new TreeNode(5); + // 构建引用指向(即指针) + n1.left = n2; + n1.right = n3; + n2.left = n4; + n2.right = n5; ``` **插入与删除节点**。与链表类似,通过修改指针来实现插入与删除节点。 @@ -460,7 +477,13 @@ === "Dart" ```dart title="binary_tree.dart" - + /* 插入与删除节点 */ + TreeNode P = new TreeNode(0); + // 在 n1 -> n2 中间插入节点 P + n1.left = P; + P.left = n2; + // 删除节点 P + n1.left = n2; ``` !!! note