mirror of
https://github.com/krahets/hello-algo.git
synced 2026-04-23 18:11:45 +08:00
Update the book based on the revised second edition (#1014)
* Revised the book * Update the book with the second revised edition * Revise base on the manuscript of the first edition
This commit is contained in:
@@ -67,7 +67,7 @@ class MyList {
|
||||
}
|
||||
// 更新元素数量
|
||||
_size--;
|
||||
// 返回被删除元素
|
||||
// 返回被删除的元素
|
||||
return _num;
|
||||
}
|
||||
|
||||
@@ -75,7 +75,7 @@ class MyList {
|
||||
void extendCapacity() {
|
||||
// 新建一个长度为原数组 _extendRatio 倍的新数组
|
||||
final _newNums = List.filled(_capacity * _extendRatio, 0);
|
||||
// 将原数组拷贝到新数组
|
||||
// 将原数组复制到新数组
|
||||
List.copyRange(_newNums, 0, _arr);
|
||||
// 更新 _arr 的引用
|
||||
_arr = _newNums;
|
||||
|
||||
@@ -25,10 +25,10 @@ void backtrack(
|
||||
}
|
||||
// 遍历所有列
|
||||
for (int col = 0; col < n; col++) {
|
||||
// 计算该格子对应的主对角线和副对角线
|
||||
// 计算该格子对应的主对角线和次对角线
|
||||
int diag1 = row - col + n - 1;
|
||||
int diag2 = row + col;
|
||||
// 剪枝:不允许该格子所在列、主对角线、副对角线上存在皇后
|
||||
// 剪枝:不允许该格子所在列、主对角线、次对角线上存在皇后
|
||||
if (!cols[col] && !diags1[diag1] && !diags2[diag2]) {
|
||||
// 尝试:将皇后放置在该格子
|
||||
state[row][col] = "Q";
|
||||
@@ -52,7 +52,7 @@ List<List<List<String>>> nQueens(int n) {
|
||||
List<List<String>> state = List.generate(n, (index) => List.filled(n, "#"));
|
||||
List<bool> cols = List.filled(n, false); // 记录列是否有皇后
|
||||
List<bool> diags1 = List.filled(2 * n - 1, false); // 记录主对角线上是否有皇后
|
||||
List<bool> diags2 = List.filled(2 * n - 1, false); // 记录副对角线上是否有皇后
|
||||
List<bool> diags2 = List.filled(2 * n - 1, false); // 记录次对角线上是否有皇后
|
||||
List<List<List<String>>> res = [];
|
||||
|
||||
backtrack(0, n, state, res, cols, diags1, diags2);
|
||||
|
||||
@@ -9,7 +9,7 @@ import 'dart:collection';
|
||||
import '../utils/vertex.dart';
|
||||
import 'graph_adjacency_list.dart';
|
||||
|
||||
/* 广度优先遍历 BFS */
|
||||
/* 广度优先遍历 */
|
||||
List<Vertex> graphBFS(GraphAdjList graph, Vertex startVet) {
|
||||
// 使用邻接表来表示图,以便获取指定顶点的所有邻接顶点
|
||||
// 顶点遍历序列
|
||||
@@ -59,7 +59,7 @@ void main() {
|
||||
print("\n初始化后,图为");
|
||||
graph.printAdjList();
|
||||
|
||||
/* 广度优先遍历 BFS */
|
||||
/* 广度优先遍历 */
|
||||
List<Vertex> res = graphBFS(graph, v[0]);
|
||||
print("\n广度优先遍历(BFS)顶点序列为");
|
||||
print(Vertex.vetsToVals(res));
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
import '../utils/vertex.dart';
|
||||
import 'graph_adjacency_list.dart';
|
||||
|
||||
/* 深度优先遍历 DFS 辅助函数 */
|
||||
/* 深度优先遍历辅助函数 */
|
||||
void dfs(
|
||||
GraphAdjList graph,
|
||||
Set<Vertex> visited,
|
||||
@@ -26,7 +26,7 @@ void dfs(
|
||||
}
|
||||
}
|
||||
|
||||
/* 深度优先遍历 DFS */
|
||||
/* 深度优先遍历 */
|
||||
List<Vertex> graphDFS(GraphAdjList graph, Vertex startVet) {
|
||||
// 顶点遍历序列
|
||||
List<Vertex> res = [];
|
||||
@@ -52,7 +52,7 @@ void main() {
|
||||
print("\n初始化后,图为");
|
||||
graph.printAdjList();
|
||||
|
||||
/* 深度优先遍历 DFS */
|
||||
/* 深度优先遍历 */
|
||||
List<Vertex> res = graphDFS(graph, v[0]);
|
||||
print("\n深度优先遍历(DFS)顶点序列为");
|
||||
print(Vertex.vetsToVals(res));
|
||||
|
||||
@@ -8,7 +8,7 @@ import 'dart:math';
|
||||
|
||||
/* 最大容量:贪心 */
|
||||
int maxCapacity(List<int> ht) {
|
||||
// 初始化 i, j 分列数组两端
|
||||
// 初始化 i, j,使其分列数组两端
|
||||
int i = 0, j = ht.length - 1;
|
||||
// 初始最大容量为 0
|
||||
int res = 0;
|
||||
|
||||
@@ -106,7 +106,7 @@ void main() {
|
||||
map.printHashMap();
|
||||
|
||||
/* 查询操作 */
|
||||
// 向哈希表输入键 key ,得到值 value
|
||||
// 向哈希表中输入键 key ,得到值 value
|
||||
String? name = map.get(15937);
|
||||
print("\n输入学号 15937 ,查询到姓名 $name");
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@ void main() {
|
||||
map.forEach((key, value) => print("$key -> $value"));
|
||||
|
||||
/* 查询操作 */
|
||||
// 向哈希表输入键 key ,得到值 value
|
||||
// 向哈希表中输入键 key ,得到值 value
|
||||
final String? name = map[15937];
|
||||
print("\n输入学号 15937 ,查询到姓名 $name");
|
||||
|
||||
|
||||
@@ -37,13 +37,13 @@ class HashMapChaining {
|
||||
String? get(int key) {
|
||||
int index = hashFunc(key);
|
||||
List<Pair> bucket = buckets[index];
|
||||
// 遍历桶,若找到 key 则返回对应 val
|
||||
// 遍历桶,若找到 key ,则返回对应 val
|
||||
for (Pair pair in bucket) {
|
||||
if (pair.key == key) {
|
||||
return pair.val;
|
||||
}
|
||||
}
|
||||
// 若未找到 key 则返回 null
|
||||
// 若未找到 key ,则返回 null
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -126,7 +126,7 @@ void main() {
|
||||
map.printHashMap();
|
||||
|
||||
/* 查询操作 */
|
||||
// 向哈希表输入键 key ,得到值 value
|
||||
// 向哈希表中输入键 key ,得到值 value
|
||||
String? name = map.get(13276);
|
||||
print("\n输入学号 13276 ,查询到姓名 ${name}");
|
||||
|
||||
|
||||
@@ -37,9 +37,9 @@ class HashMapOpenAddressing {
|
||||
int firstTombstone = -1;
|
||||
// 线性探测,当遇到空桶时跳出
|
||||
while (_buckets[index] != null) {
|
||||
// 若遇到 key ,返回对应桶索引
|
||||
// 若遇到 key ,返回对应的桶索引
|
||||
if (_buckets[index]!.key == key) {
|
||||
// 若之前遇到了删除标记,则将键值对移动至该索引
|
||||
// 若之前遇到了删除标记,则将键值对移动至该索引处
|
||||
if (firstTombstone != -1) {
|
||||
_buckets[firstTombstone] = _buckets[index];
|
||||
_buckets[index] = _TOMBSTONE;
|
||||
@@ -51,7 +51,7 @@ class HashMapOpenAddressing {
|
||||
if (firstTombstone == -1 && _buckets[index] == _TOMBSTONE) {
|
||||
firstTombstone = index;
|
||||
}
|
||||
// 计算桶索引,越过尾部返回头部
|
||||
// 计算桶索引,越过尾部则返回头部
|
||||
index = (index + 1) % _capacity;
|
||||
}
|
||||
// 若 key 不存在,则返回添加点的索引
|
||||
@@ -145,7 +145,7 @@ void main() {
|
||||
map.printHashMap();
|
||||
|
||||
/* 查询操作 */
|
||||
// 向哈希表输入键 key ,得到值 value
|
||||
// 向哈希表中输入键 key ,得到值 value
|
||||
String? name = map.get(13276);
|
||||
print("\n输入学号 13276 ,查询到姓名 $name");
|
||||
|
||||
|
||||
@@ -20,17 +20,17 @@ class MaxHeap {
|
||||
}
|
||||
}
|
||||
|
||||
/* 获取左子节点索引 */
|
||||
/* 获取左子节点的索引 */
|
||||
int _left(int i) {
|
||||
return 2 * i + 1;
|
||||
}
|
||||
|
||||
/* 获取右子节点索引 */
|
||||
/* 获取右子节点的索引 */
|
||||
int _right(int i) {
|
||||
return 2 * i + 2;
|
||||
}
|
||||
|
||||
/* 获取父节点索引 */
|
||||
/* 获取父节点的索引 */
|
||||
int _parent(int i) {
|
||||
return (i - 1) ~/ 2; // 向下整除
|
||||
}
|
||||
|
||||
@@ -50,17 +50,17 @@ class MinHeap {
|
||||
return _minHeap;
|
||||
}
|
||||
|
||||
/* 获取左子节点索引 */
|
||||
/* 获取左子节点的索引 */
|
||||
int _left(int i) {
|
||||
return 2 * i + 1;
|
||||
}
|
||||
|
||||
/* 获取右子节点索引 */
|
||||
/* 获取右子节点的索引 */
|
||||
int _right(int i) {
|
||||
return 2 * i + 2;
|
||||
}
|
||||
|
||||
/* 获取父节点索引 */
|
||||
/* 获取父节点的索引 */
|
||||
int _parent(int i) {
|
||||
return (i - 1) ~/ 2; // 向下整除
|
||||
}
|
||||
|
||||
@@ -35,7 +35,7 @@ void bubbleSortWithFlag(List<int> nums) {
|
||||
flag = true; // 记录交换元素
|
||||
}
|
||||
}
|
||||
if (!flag) break; // 此轮冒泡未交换任何元素,直接跳出
|
||||
if (!flag) break; // 此轮“冒泡”未交换任何元素,直接跳出
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -6,12 +6,12 @@
|
||||
|
||||
/* 合并左子数组和右子数组 */
|
||||
void merge(List<int> nums, int left, int mid, int right) {
|
||||
// 左子数组区间 [left, mid], 右子数组区间 [mid+1, right]
|
||||
// 左子数组区间为 [left, mid], 右子数组区间为 [mid+1, right]
|
||||
// 创建一个临时数组 tmp ,用于存放合并后的结果
|
||||
List<int> tmp = List.filled(right - left + 1, 0);
|
||||
// 初始化左子数组和右子数组的起始索引
|
||||
int i = left, j = mid + 1, k = 0;
|
||||
// 当左右子数组都还有元素时,比较并将较小的元素复制到临时数组中
|
||||
// 当左右子数组都还有元素时,进行比较并将较小的元素复制到临时数组中
|
||||
while (i <= mid && j <= right) {
|
||||
if (nums[i] <= nums[j])
|
||||
tmp[k++] = nums[i++];
|
||||
|
||||
@@ -47,7 +47,7 @@ class QuickSortMedian {
|
||||
nums[j] = tmp;
|
||||
}
|
||||
|
||||
/* 选取三个元素的中位数 */
|
||||
/* 选取三个候选元素的中位数 */
|
||||
static int _medianThree(List<int> nums, int left, int mid, int right) {
|
||||
// 此处使用异或运算来简化代码
|
||||
// 异或规则为 0 ^ 0 = 1 ^ 1 = 0, 0 ^ 1 = 1 ^ 0 = 1
|
||||
|
||||
@@ -45,7 +45,7 @@ class ArrayDeque {
|
||||
throw Exception("双向队列已满");
|
||||
}
|
||||
// 队首指针向左移动一位
|
||||
// 通过取余操作,实现 _front 越过数组头部后回到尾部
|
||||
// 通过取余操作实现 _front 越过数组头部后回到尾部
|
||||
_front = index(_front - 1);
|
||||
// 将 _num 添加至队首
|
||||
_nums[_front] = _num;
|
||||
@@ -57,7 +57,7 @@ class ArrayDeque {
|
||||
if (_queSize == capacity()) {
|
||||
throw Exception("双向队列已满");
|
||||
}
|
||||
// 计算尾指针,指向队尾索引 + 1
|
||||
// 计算队尾指针,指向队尾索引 + 1
|
||||
int rear = index(_front + _queSize);
|
||||
// 将 _num 添加至队尾
|
||||
_nums[rear] = _num;
|
||||
|
||||
@@ -35,8 +35,8 @@ class ArrayQueue {
|
||||
if (_queSize == capaCity()) {
|
||||
throw Exception("队列已满");
|
||||
}
|
||||
// 计算尾指针,指向队尾索引 + 1
|
||||
// 通过取余操作,实现 rear 越过数组尾部后回到头部
|
||||
// 计算队尾指针,指向队尾索引 + 1
|
||||
// 通过取余操作实现 rear 越过数组尾部后回到头部
|
||||
int rear = (_front + _queSize) % capaCity();
|
||||
// 将 _num 添加至队尾
|
||||
_nums[rear] = _num;
|
||||
@@ -46,7 +46,7 @@ class ArrayQueue {
|
||||
/* 出队 */
|
||||
int pop() {
|
||||
int _num = peek();
|
||||
// 队首指针向后移动一位,若越过尾部则返回到数组头部
|
||||
// 队首指针向后移动一位,若越过尾部,则返回到数组头部
|
||||
_front = (_front + 1) % capaCity();
|
||||
_queSize--;
|
||||
return _num;
|
||||
|
||||
@@ -29,7 +29,7 @@ class LinkedListQueue {
|
||||
|
||||
/* 入队 */
|
||||
void push(int _num) {
|
||||
// 尾节点后添加 _num
|
||||
// 在尾节点后添加 _num
|
||||
final node = ListNode(_num);
|
||||
// 如果队列为空,则令头、尾节点都指向该节点
|
||||
if (_front == null) {
|
||||
|
||||
@@ -102,7 +102,7 @@ class AVLTree {
|
||||
/* 递归插入节点(辅助方法) */
|
||||
TreeNode? insertHelper(TreeNode? node, int val) {
|
||||
if (node == null) return TreeNode(val);
|
||||
/* 1. 查找插入位置,并插入节点 */
|
||||
/* 1. 查找插入位置并插入节点 */
|
||||
if (val < node.val)
|
||||
node.left = insertHelper(node.left, val);
|
||||
else if (val > node.val)
|
||||
@@ -124,7 +124,7 @@ class AVLTree {
|
||||
/* 递归删除节点(辅助方法) */
|
||||
TreeNode? removeHelper(TreeNode? node, int val) {
|
||||
if (node == null) return null;
|
||||
/* 1. 查找节点,并删除之 */
|
||||
/* 1. 查找节点并删除 */
|
||||
if (val < node.val)
|
||||
node.left = removeHelper(node.left, val);
|
||||
else if (val > node.val)
|
||||
|
||||
Reference in New Issue
Block a user