mirror of
https://github.com/krahets/hello-algo.git
synced 2026-03-20 20:06:51 +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:
@@ -23,10 +23,10 @@ void backtrack(int row, int n, char state[MAX_SIZE][MAX_SIZE], char ***res, int
|
||||
}
|
||||
// 遍历所有列
|
||||
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 @@ char ***nQueens(int n, int *returnSize) {
|
||||
}
|
||||
bool cols[MAX_SIZE] = {false}; // 记录列是否有皇后
|
||||
bool diags1[2 * MAX_SIZE - 1] = {false}; // 记录主对角线上是否有皇后
|
||||
bool diags2[2 * MAX_SIZE - 1] = {false}; // 记录副对角线上是否有皇后
|
||||
bool diags2[2 * MAX_SIZE - 1] = {false}; // 记录次对角线上是否有皇后
|
||||
|
||||
char ***res = (char ***)malloc(sizeof(char **) * MAX_SIZE);
|
||||
*returnSize = 0;
|
||||
|
||||
@@ -52,7 +52,7 @@ int isVisited(Vertex **visited, int size, Vertex *vet) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* 广度优先遍历 BFS */
|
||||
/* 广度优先遍历 */
|
||||
// 使用邻接表来表示图,以便获取指定顶点的所有邻接顶点
|
||||
void graphBFS(GraphAdjList *graph, Vertex *startVet, Vertex **res, int *resSize, Vertex **visited, int *visitedSize) {
|
||||
// 队列用于实现 BFS
|
||||
@@ -98,7 +98,7 @@ int main() {
|
||||
printf("\n初始化后,图为\n");
|
||||
printGraph(graph);
|
||||
|
||||
// 广度优先遍历 BFS
|
||||
// 广度优先遍历
|
||||
// 顶点遍历序列
|
||||
Vertex *res[MAX_SIZE];
|
||||
int resSize = 0;
|
||||
|
||||
@@ -20,7 +20,7 @@ int isVisited(Vertex **res, int size, Vertex *vet) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* 深度优先遍历 DFS 辅助函数 */
|
||||
/* 深度优先遍历辅助函数 */
|
||||
void dfs(GraphAdjList *graph, Vertex **res, int *resSize, Vertex *vet) {
|
||||
// 记录访问顶点
|
||||
res[(*resSize)++] = vet;
|
||||
@@ -36,7 +36,7 @@ void dfs(GraphAdjList *graph, Vertex **res, int *resSize, Vertex *vet) {
|
||||
}
|
||||
}
|
||||
|
||||
/* 深度优先遍历 DFS */
|
||||
/* 深度优先遍历 */
|
||||
// 使用邻接表来表示图,以便获取指定顶点的所有邻接顶点
|
||||
void graphDFS(GraphAdjList *graph, Vertex *startVet, Vertex **res, int *resSize) {
|
||||
dfs(graph, res, resSize, startVet);
|
||||
@@ -61,7 +61,7 @@ int main() {
|
||||
printf("\n初始化后,图为\n");
|
||||
printGraph(graph);
|
||||
|
||||
// 深度优先遍历 DFS
|
||||
// 深度优先遍历
|
||||
Vertex *res[MAX_SIZE];
|
||||
int resSize = 0;
|
||||
graphDFS(graph, v[0], res, &resSize);
|
||||
|
||||
@@ -17,7 +17,7 @@ int myMax(int a, int b) {
|
||||
|
||||
/* 最大容量:贪心 */
|
||||
int maxCapacity(int ht[], int htLength) {
|
||||
// 初始化 i, j 分列数组两端
|
||||
// 初始化 i, j,使其分列数组两端
|
||||
int i = 0;
|
||||
int j = htLength - 1;
|
||||
// 初始最大容量为 0
|
||||
|
||||
@@ -173,7 +173,7 @@ int main() {
|
||||
print(hmap);
|
||||
|
||||
/* 查询操作 */
|
||||
// 向哈希表输入键 key ,得到值 value
|
||||
// 向哈希表中输入键 key ,得到值 value
|
||||
const char *name = get(hmap, 15937);
|
||||
printf("\n输入学号 15937 ,查询到姓名 %s\n", name);
|
||||
|
||||
|
||||
@@ -74,7 +74,7 @@ double loadFactor(HashMapChaining *hashMap) {
|
||||
/* 查询操作 */
|
||||
char *get(HashMapChaining *hashMap, int key) {
|
||||
int index = hashFunc(hashMap, key);
|
||||
// 遍历桶,若找到 key 则返回对应 val
|
||||
// 遍历桶,若找到 key ,则返回对应 val
|
||||
Node *cur = hashMap->buckets[index];
|
||||
while (cur) {
|
||||
if (cur->pair->key == key) {
|
||||
@@ -82,7 +82,7 @@ char *get(HashMapChaining *hashMap, int key) {
|
||||
}
|
||||
cur = cur->next;
|
||||
}
|
||||
return ""; // 若未找到 key 则返回空字符串
|
||||
return ""; // 若未找到 key ,则返回空字符串
|
||||
}
|
||||
|
||||
/* 添加操作 */
|
||||
@@ -196,7 +196,7 @@ int main() {
|
||||
print(hashMap);
|
||||
|
||||
/* 查询操作 */
|
||||
// 向哈希表输入键 key ,得到值 value
|
||||
// 向哈希表中输入键 key ,得到值 value
|
||||
char *name = get(hashMap, 13276);
|
||||
printf("\n输入学号 13276 ,查询到姓名 %s\n", name);
|
||||
|
||||
|
||||
@@ -67,9 +67,9 @@ int findBucket(HashMapOpenAddressing *hashMap, int key) {
|
||||
int firstTombstone = -1;
|
||||
// 线性探测,当遇到空桶时跳出
|
||||
while (hashMap->buckets[index] != NULL) {
|
||||
// 若遇到 key ,返回对应桶索引
|
||||
// 若遇到 key ,返回对应的桶索引
|
||||
if (hashMap->buckets[index]->key == key) {
|
||||
// 若之前遇到了删除标记,则将键值对移动至该索引
|
||||
// 若之前遇到了删除标记,则将键值对移动至该索引处
|
||||
if (firstTombstone != -1) {
|
||||
hashMap->buckets[firstTombstone] = hashMap->buckets[index];
|
||||
hashMap->buckets[index] = hashMap->TOMBSTONE;
|
||||
@@ -81,7 +81,7 @@ int findBucket(HashMapOpenAddressing *hashMap, int key) {
|
||||
if (firstTombstone == -1 && hashMap->buckets[index] == hashMap->TOMBSTONE) {
|
||||
firstTombstone = index;
|
||||
}
|
||||
// 计算桶索引,越过尾部返回头部
|
||||
// 计算桶索引,越过尾部则返回头部
|
||||
index = (index + 1) % hashMap->capacity;
|
||||
}
|
||||
// 若 key 不存在,则返回添加点的索引
|
||||
@@ -192,7 +192,7 @@ int main() {
|
||||
print(hashmap);
|
||||
|
||||
// 查询操作
|
||||
// 向哈希表输入键 key ,得到值 val
|
||||
// 向哈希表中输入键 key ,得到值 val
|
||||
char *name = get(hashmap, 13276);
|
||||
printf("\n输入学号 13276 ,查询到姓名 %s\n", name);
|
||||
|
||||
|
||||
@@ -40,17 +40,17 @@ void delMaxHeap(MaxHeap *maxHeap) {
|
||||
free(maxHeap);
|
||||
}
|
||||
|
||||
/* 获取左子节点索引 */
|
||||
/* 获取左子节点的索引 */
|
||||
int left(MaxHeap *maxHeap, int i) {
|
||||
return 2 * i + 1;
|
||||
}
|
||||
|
||||
/* 获取右子节点索引 */
|
||||
/* 获取右子节点的索引 */
|
||||
int right(MaxHeap *maxHeap, int i) {
|
||||
return 2 * i + 2;
|
||||
}
|
||||
|
||||
/* 获取父节点索引 */
|
||||
/* 获取父节点的索引 */
|
||||
int parent(MaxHeap *maxHeap, int i) {
|
||||
return (i - 1) / 2;
|
||||
}
|
||||
|
||||
@@ -8,13 +8,13 @@
|
||||
|
||||
/* 合并左子数组和右子数组 */
|
||||
void merge(int *nums, int left, int mid, int right) {
|
||||
// 左子数组区间 [left, mid], 右子数组区间 [mid+1, right]
|
||||
// 左子数组区间为 [left, mid], 右子数组区间为 [mid+1, right]
|
||||
// 创建一个临时数组 tmp ,用于存放合并后的结果
|
||||
int tmpSize = right - left + 1;
|
||||
int *tmp = (int *)malloc(tmpSize * sizeof(int));
|
||||
// 初始化左子数组和右子数组的起始索引
|
||||
int i = left, j = mid + 1, k = 0;
|
||||
// 当左右子数组都还有元素时,比较并将较小的元素复制到临时数组中
|
||||
// 当左右子数组都还有元素时,进行比较并将较小的元素复制到临时数组中
|
||||
while (i <= mid && j <= right) {
|
||||
if (nums[i] <= nums[j]) {
|
||||
tmp[k++] = nums[i++];
|
||||
|
||||
@@ -50,7 +50,7 @@ void quickSort(int nums[], int left, int right) {
|
||||
}
|
||||
|
||||
/* 快速排序类(中位基准数优化) */
|
||||
// 选取三个元素的中位数
|
||||
// 选取三个候选元素的中位数
|
||||
int medianThree(int nums[], int left, int mid, int right) {
|
||||
// 此处使用异或运算来简化代码
|
||||
// 异或规则为 0 ^ 0 = 1 ^ 1 = 0, 0 ^ 1 = 1 ^ 0 = 1
|
||||
|
||||
@@ -60,7 +60,7 @@ void pushFirst(ArrayDeque *deque, int num) {
|
||||
return;
|
||||
}
|
||||
// 队首指针向左移动一位
|
||||
// 通过取余操作,实现 front 越过数组头部回到尾部
|
||||
// 通过取余操作实现 front 越过数组头部回到尾部
|
||||
deque->front = dequeIndex(deque, deque->front - 1);
|
||||
// 将 num 添加到队首
|
||||
deque->nums[deque->front] = num;
|
||||
@@ -73,7 +73,7 @@ void pushLast(ArrayDeque *deque, int num) {
|
||||
printf("双向队列已满\r\n");
|
||||
return;
|
||||
}
|
||||
// 计算尾指针,指向队尾索引 + 1
|
||||
// 计算队尾指针,指向队尾索引 + 1
|
||||
int rear = dequeIndex(deque, deque->front + deque->queSize);
|
||||
// 将 num 添加至队尾
|
||||
deque->nums[rear] = num;
|
||||
|
||||
@@ -58,7 +58,7 @@ void push(ArrayQueue *queue, int num) {
|
||||
return;
|
||||
}
|
||||
// 计算队尾指针,指向队尾索引 + 1
|
||||
// 通过取余操作,实现 rear 越过数组尾部后回到头部
|
||||
// 通过取余操作实现 rear 越过数组尾部后回到头部
|
||||
int rear = (queue->front + queue->queSize) % queue->queCapacity;
|
||||
// 将 num 添加至队尾
|
||||
queue->nums[rear] = num;
|
||||
@@ -68,7 +68,7 @@ void push(ArrayQueue *queue, int num) {
|
||||
/* 出队 */
|
||||
int pop(ArrayQueue *queue) {
|
||||
int num = peek(queue);
|
||||
// 队首指针向后移动一位,若越过尾部则返回到数组头部
|
||||
// 队首指针向后移动一位,若越过尾部,则返回到数组头部
|
||||
queue->front = (queue->front + 1) % queue->queCapacity;
|
||||
queue->queSize--;
|
||||
return num;
|
||||
|
||||
@@ -120,7 +120,7 @@ TreeNode *insertHelper(TreeNode *node, int val) {
|
||||
if (node == NULL) {
|
||||
return newTreeNode(val);
|
||||
}
|
||||
/* 1. 查找插入位置,并插入节点 */
|
||||
/* 1. 查找插入位置并插入节点 */
|
||||
if (val < node->val) {
|
||||
node->left = insertHelper(node->left, val);
|
||||
} else if (val > node->val) {
|
||||
@@ -148,7 +148,7 @@ 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) {
|
||||
|
||||
@@ -37,7 +37,7 @@ class MyList {
|
||||
|
||||
/* 访问元素 */
|
||||
int get(int index) {
|
||||
// 索引如果越界则抛出异常,下同
|
||||
// 索引如果越界,则抛出异常,下同
|
||||
if (index < 0 || index >= size())
|
||||
throw out_of_range("索引越界");
|
||||
return arr[index];
|
||||
@@ -87,7 +87,7 @@ class MyList {
|
||||
}
|
||||
// 更新元素数量
|
||||
arrSize--;
|
||||
// 返回被删除元素
|
||||
// 返回被删除的元素
|
||||
return num;
|
||||
}
|
||||
|
||||
|
||||
@@ -16,10 +16,10 @@ void backtrack(int row, int n, vector<vector<string>> &state, vector<vector<vect
|
||||
}
|
||||
// 遍历所有列
|
||||
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";
|
||||
@@ -39,7 +39,7 @@ vector<vector<vector<string>>> nQueens(int n) {
|
||||
vector<vector<string>> state(n, vector<string>(n, "#"));
|
||||
vector<bool> cols(n, false); // 记录列是否有皇后
|
||||
vector<bool> diags1(2 * n - 1, false); // 记录主对角线上是否有皇后
|
||||
vector<bool> diags2(2 * n - 1, false); // 记录副对角线上是否有皇后
|
||||
vector<bool> diags2(2 * n - 1, false); // 记录次对角线上是否有皇后
|
||||
vector<vector<vector<string>>> res;
|
||||
|
||||
backtrack(0, n, state, res, cols, diags1, diags2);
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
#include "../utils/common.hpp"
|
||||
#include "./graph_adjacency_list.cpp"
|
||||
|
||||
/* 广度优先遍历 BFS */
|
||||
/* 广度优先遍历 */
|
||||
// 使用邻接表来表示图,以便获取指定顶点的所有邻接顶点
|
||||
vector<Vertex *> graphBFS(GraphAdjList &graph, Vertex *startVet) {
|
||||
// 顶点遍历序列
|
||||
@@ -45,7 +45,7 @@ int main() {
|
||||
cout << "\n初始化后,图为\\n";
|
||||
graph.print();
|
||||
|
||||
/* 广度优先遍历 BFS */
|
||||
/* 广度优先遍历 */
|
||||
vector<Vertex *> res = graphBFS(graph, v[0]);
|
||||
cout << "\n广度优先遍历(BFS)顶点序列为" << endl;
|
||||
printVector(vetsToVals(res));
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
#include "../utils/common.hpp"
|
||||
#include "./graph_adjacency_list.cpp"
|
||||
|
||||
/* 深度优先遍历 DFS 辅助函数 */
|
||||
/* 深度优先遍历辅助函数 */
|
||||
void dfs(GraphAdjList &graph, unordered_set<Vertex *> &visited, vector<Vertex *> &res, Vertex *vet) {
|
||||
res.push_back(vet); // 记录访问顶点
|
||||
visited.emplace(vet); // 标记该顶点已被访问
|
||||
@@ -20,7 +20,7 @@ void dfs(GraphAdjList &graph, unordered_set<Vertex *> &visited, vector<Vertex *>
|
||||
}
|
||||
}
|
||||
|
||||
/* 深度优先遍历 DFS */
|
||||
/* 深度优先遍历 */
|
||||
// 使用邻接表来表示图,以便获取指定顶点的所有邻接顶点
|
||||
vector<Vertex *> graphDFS(GraphAdjList &graph, Vertex *startVet) {
|
||||
// 顶点遍历序列
|
||||
@@ -41,7 +41,7 @@ int main() {
|
||||
cout << "\n初始化后,图为" << endl;
|
||||
graph.print();
|
||||
|
||||
/* 深度优先遍历 DFS */
|
||||
/* 深度优先遍历 */
|
||||
vector<Vertex *> res = graphDFS(graph, v[0]);
|
||||
cout << "\n深度优先遍历(DFS)顶点序列为" << endl;
|
||||
printVector(vetsToVals(res));
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
|
||||
/* 最大容量:贪心 */
|
||||
int maxCapacity(vector<int> &ht) {
|
||||
// 初始化 i, j 分列数组两端
|
||||
// 初始化 i, j,使其分列数组两端
|
||||
int i = 0, j = ht.size() - 1;
|
||||
// 初始最大容量为 0
|
||||
int res = 0;
|
||||
|
||||
@@ -22,7 +22,7 @@ int main() {
|
||||
map.print();
|
||||
|
||||
/* 查询操作 */
|
||||
// 向哈希表输入键 key ,得到值 value
|
||||
// 向哈希表中输入键 key ,得到值 value
|
||||
string name = map.get(15937);
|
||||
cout << "\n输入学号 15937 ,查询到姓名 " << name << endl;
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@ int main() {
|
||||
printHashMap(map);
|
||||
|
||||
/* 查询操作 */
|
||||
// 向哈希表输入键 key ,得到值 value
|
||||
// 向哈希表中输入键 key ,得到值 value
|
||||
string name = map[15937];
|
||||
cout << "\n输入学号 15937 ,查询到姓名 " << name << endl;
|
||||
|
||||
|
||||
@@ -44,13 +44,13 @@ class HashMapChaining {
|
||||
/* 查询操作 */
|
||||
string get(int key) {
|
||||
int index = hashFunc(key);
|
||||
// 遍历桶,若找到 key 则返回对应 val
|
||||
// 遍历桶,若找到 key ,则返回对应 val
|
||||
for (Pair *pair : buckets[index]) {
|
||||
if (pair->key == key) {
|
||||
return pair->val;
|
||||
}
|
||||
}
|
||||
// 若未找到 key 则返回空字符串
|
||||
// 若未找到 key ,则返回空字符串
|
||||
return "";
|
||||
}
|
||||
|
||||
@@ -136,7 +136,7 @@ int main() {
|
||||
map.print();
|
||||
|
||||
/* 查询操作 */
|
||||
// 向哈希表输入键 key ,得到值 value
|
||||
// 向哈希表中输入键 key ,得到值 value
|
||||
string name = map.get(13276);
|
||||
cout << "\n输入学号 13276 ,查询到姓名 " << name << endl;
|
||||
|
||||
|
||||
@@ -47,9 +47,9 @@ class HashMapOpenAddressing {
|
||||
int firstTombstone = -1;
|
||||
// 线性探测,当遇到空桶时跳出
|
||||
while (buckets[index] != nullptr) {
|
||||
// 若遇到 key ,返回对应桶索引
|
||||
// 若遇到 key ,返回对应的桶索引
|
||||
if (buckets[index]->key == key) {
|
||||
// 若之前遇到了删除标记,则将键值对移动至该索引
|
||||
// 若之前遇到了删除标记,则将键值对移动至该索引处
|
||||
if (firstTombstone != -1) {
|
||||
buckets[firstTombstone] = buckets[index];
|
||||
buckets[index] = TOMBSTONE;
|
||||
@@ -61,7 +61,7 @@ class HashMapOpenAddressing {
|
||||
if (firstTombstone == -1 && buckets[index] == TOMBSTONE) {
|
||||
firstTombstone = index;
|
||||
}
|
||||
// 计算桶索引,越过尾部返回头部
|
||||
// 计算桶索引,越过尾部则返回头部
|
||||
index = (index + 1) % capacity;
|
||||
}
|
||||
// 若 key 不存在,则返回添加点的索引
|
||||
@@ -157,7 +157,7 @@ int main() {
|
||||
hashmap.print();
|
||||
|
||||
// 查询操作
|
||||
// 向哈希表输入键 key ,得到值 val
|
||||
// 向哈希表中输入键 key ,得到值 val
|
||||
string name = hashmap.get(13276);
|
||||
cout << "\n输入学号 13276 ,查询到姓名 " << name << endl;
|
||||
|
||||
|
||||
@@ -12,17 +12,17 @@ class MaxHeap {
|
||||
// 使用动态数组,这样无须考虑扩容问题
|
||||
vector<int> 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; // 向下整除
|
||||
}
|
||||
|
||||
@@ -36,7 +36,7 @@ void bubbleSortWithFlag(vector<int> &nums) {
|
||||
}
|
||||
}
|
||||
if (!flag)
|
||||
break; // 此轮冒泡未交换任何元素,直接跳出
|
||||
break; // 此轮“冒泡”未交换任何元素,直接跳出
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -8,12 +8,12 @@
|
||||
|
||||
/* 合并左子数组和右子数组 */
|
||||
void merge(vector<int> &nums, int left, int mid, int right) {
|
||||
// 左子数组区间 [left, mid], 右子数组区间 [mid+1, right]
|
||||
// 左子数组区间为 [left, mid], 右子数组区间为 [mid+1, right]
|
||||
// 创建一个临时数组 tmp ,用于存放合并后的结果
|
||||
vector<int> tmp(right - left + 1);
|
||||
// 初始化左子数组和右子数组的起始索引
|
||||
int i = left, j = mid + 1, k = 0;
|
||||
// 当左右子数组都还有元素时,比较并将较小的元素复制到临时数组中
|
||||
// 当左右子数组都还有元素时,进行比较并将较小的元素复制到临时数组中
|
||||
while (i <= mid && j <= right) {
|
||||
if (nums[i] <= nums[j])
|
||||
tmp[k++] = nums[i++];
|
||||
|
||||
@@ -55,7 +55,7 @@ class QuickSortMedian {
|
||||
nums[j] = tmp;
|
||||
}
|
||||
|
||||
/* 选取三个元素的中位数 */
|
||||
/* 选取三个候选元素的中位数 */
|
||||
static int medianThree(vector<int> &nums, int left, int mid, int right) {
|
||||
// 此处使用异或运算来简化代码
|
||||
// 异或规则为 0 ^ 0 = 1 ^ 1 = 0, 0 ^ 1 = 1 ^ 0 = 1
|
||||
|
||||
@@ -50,7 +50,7 @@ class ArrayDeque {
|
||||
return;
|
||||
}
|
||||
// 队首指针向左移动一位
|
||||
// 通过取余操作,实现 front 越过数组头部后回到尾部
|
||||
// 通过取余操作实现 front 越过数组头部后回到尾部
|
||||
front = index(front - 1);
|
||||
// 将 num 添加至队首
|
||||
nums[front] = num;
|
||||
@@ -63,7 +63,7 @@ class ArrayDeque {
|
||||
cout << "双向队列已满" << endl;
|
||||
return;
|
||||
}
|
||||
// 计算尾指针,指向队尾索引 + 1
|
||||
// 计算队尾指针,指向队尾索引 + 1
|
||||
int rear = index(front + queSize);
|
||||
// 将 num 添加至队尾
|
||||
nums[rear] = num;
|
||||
|
||||
@@ -48,7 +48,7 @@ class ArrayQueue {
|
||||
return;
|
||||
}
|
||||
// 计算队尾指针,指向队尾索引 + 1
|
||||
// 通过取余操作,实现 rear 越过数组尾部后回到头部
|
||||
// 通过取余操作实现 rear 越过数组尾部后回到头部
|
||||
int rear = (front + queSize) % queCapacity;
|
||||
// 将 num 添加至队尾
|
||||
nums[rear] = num;
|
||||
@@ -58,7 +58,7 @@ class ArrayQueue {
|
||||
/* 出队 */
|
||||
int pop() {
|
||||
int num = peek();
|
||||
// 队首指针向后移动一位,若越过尾部则返回到数组头部
|
||||
// 队首指针向后移动一位,若越过尾部,则返回到数组头部
|
||||
front = (front + 1) % queCapacity;
|
||||
queSize--;
|
||||
return num;
|
||||
|
||||
@@ -36,7 +36,7 @@ class LinkedListQueue {
|
||||
|
||||
/* 入队 */
|
||||
void push(int num) {
|
||||
// 尾节点后添加 num
|
||||
// 在尾节点后添加 num
|
||||
ListNode *node = new ListNode(num);
|
||||
// 如果队列为空,则令头、尾节点都指向该节点
|
||||
if (front == nullptr) {
|
||||
|
||||
@@ -79,7 +79,7 @@ class AVLTree {
|
||||
TreeNode *insertHelper(TreeNode *node, int val) {
|
||||
if (node == nullptr)
|
||||
return new TreeNode(val);
|
||||
/* 1. 查找插入位置,并插入节点 */
|
||||
/* 1. 查找插入位置并插入节点 */
|
||||
if (val < node->val)
|
||||
node->left = insertHelper(node->left, val);
|
||||
else if (val > node->val)
|
||||
@@ -97,7 +97,7 @@ class AVLTree {
|
||||
TreeNode *removeHelper(TreeNode *node, int val) {
|
||||
if (node == nullptr)
|
||||
return nullptr;
|
||||
/* 1. 查找节点,并删除之 */
|
||||
/* 1. 查找节点并删除 */
|
||||
if (val < node->val)
|
||||
node->left = removeHelper(node->left, val);
|
||||
else if (val > node->val)
|
||||
|
||||
@@ -30,7 +30,7 @@ class MyList {
|
||||
|
||||
/* 访问元素 */
|
||||
public int Get(int index) {
|
||||
// 索引如果越界则抛出异常,下同
|
||||
// 索引如果越界,则抛出异常,下同
|
||||
if (index < 0 || index >= arrSize)
|
||||
throw new IndexOutOfRangeException("索引越界");
|
||||
return arr[index];
|
||||
@@ -80,13 +80,13 @@ class MyList {
|
||||
}
|
||||
// 更新元素数量
|
||||
arrSize--;
|
||||
// 返回被删除元素
|
||||
// 返回被删除的元素
|
||||
return num;
|
||||
}
|
||||
|
||||
/* 列表扩容 */
|
||||
public void ExtendCapacity() {
|
||||
// 新建一个长度为 arrCapacity * extendRatio 的数组,并将原数组拷贝到新数组
|
||||
// 新建一个长度为 arrCapacity * extendRatio 的数组,并将原数组复制到新数组
|
||||
Array.Resize(ref arr, arrCapacity * extendRatio);
|
||||
// 更新列表容量
|
||||
arrCapacity = arr.Length;
|
||||
|
||||
@@ -21,10 +21,10 @@ public class n_queens {
|
||||
}
|
||||
// 遍历所有列
|
||||
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";
|
||||
@@ -51,7 +51,7 @@ public class n_queens {
|
||||
}
|
||||
bool[] cols = new bool[n]; // 记录列是否有皇后
|
||||
bool[] diags1 = new bool[2 * n - 1]; // 记录主对角线上是否有皇后
|
||||
bool[] diags2 = new bool[2 * n - 1]; // 记录副对角线上是否有皇后
|
||||
bool[] diags2 = new bool[2 * n - 1]; // 记录次对角线上是否有皇后
|
||||
List<List<List<string>>> res = [];
|
||||
|
||||
Backtrack(0, n, state, res, cols, diags1, diags2);
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
namespace hello_algo.chapter_graph;
|
||||
|
||||
public class graph_bfs {
|
||||
/* 广度优先遍历 BFS */
|
||||
/* 广度优先遍历 */
|
||||
// 使用邻接表来表示图,以便获取指定顶点的所有邻接顶点
|
||||
List<Vertex> GraphBFS(GraphAdjList graph, Vertex startVet) {
|
||||
// 顶点遍历序列
|
||||
@@ -50,7 +50,7 @@ public class graph_bfs {
|
||||
Console.WriteLine("\n初始化后,图为");
|
||||
graph.Print();
|
||||
|
||||
/* 广度优先遍历 BFS */
|
||||
/* 广度优先遍历 */
|
||||
List<Vertex> res = GraphBFS(graph, v[0]);
|
||||
Console.WriteLine("\n广度优先遍历(BFS)顶点序列为");
|
||||
Console.WriteLine(string.Join(" ", Vertex.VetsToVals(res)));
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
namespace hello_algo.chapter_graph;
|
||||
|
||||
public class graph_dfs {
|
||||
/* 深度优先遍历 DFS 辅助函数 */
|
||||
/* 深度优先遍历辅助函数 */
|
||||
void DFS(GraphAdjList graph, HashSet<Vertex> visited, List<Vertex> res, Vertex vet) {
|
||||
res.Add(vet); // 记录访问顶点
|
||||
visited.Add(vet); // 标记该顶点已被访问
|
||||
@@ -21,7 +21,7 @@ public class graph_dfs {
|
||||
}
|
||||
}
|
||||
|
||||
/* 深度优先遍历 DFS */
|
||||
/* 深度优先遍历 */
|
||||
// 使用邻接表来表示图,以便获取指定顶点的所有邻接顶点
|
||||
List<Vertex> GraphDFS(GraphAdjList graph, Vertex startVet) {
|
||||
// 顶点遍历序列
|
||||
@@ -46,7 +46,7 @@ public class graph_dfs {
|
||||
Console.WriteLine("\n初始化后,图为");
|
||||
graph.Print();
|
||||
|
||||
/* 深度优先遍历 DFS */
|
||||
/* 深度优先遍历 */
|
||||
List<Vertex> res = GraphDFS(graph, v[0]);
|
||||
Console.WriteLine("\n深度优先遍历(DFS)顶点序列为");
|
||||
Console.WriteLine(string.Join(" ", Vertex.VetsToVals(res)));
|
||||
|
||||
@@ -9,7 +9,7 @@ namespace hello_algo.chapter_greedy;
|
||||
public class max_capacity {
|
||||
/* 最大容量:贪心 */
|
||||
int MaxCapacity(int[] ht) {
|
||||
// 初始化 i, j 分列数组两端
|
||||
// 初始化 i, j,使其分列数组两端
|
||||
int i = 0, j = ht.Length - 1;
|
||||
// 初始最大容量为 0
|
||||
int res = 0;
|
||||
|
||||
@@ -107,7 +107,7 @@ public class array_hash_map {
|
||||
map.Print();
|
||||
|
||||
/* 查询操作 */
|
||||
// 向哈希表输入键 key ,得到值 value
|
||||
// 向哈希表中输入键 key ,得到值 value
|
||||
string? name = map.Get(15937);
|
||||
Console.WriteLine("\n输入学号 15937 ,查询到姓名 " + name);
|
||||
|
||||
|
||||
@@ -24,7 +24,7 @@ public class hash_map {
|
||||
PrintUtil.PrintHashMap(map);
|
||||
|
||||
/* 查询操作 */
|
||||
// 向哈希表输入键 key ,得到值 value
|
||||
// 向哈希表中输入键 key ,得到值 value
|
||||
string name = map[15937];
|
||||
Console.WriteLine("\n输入学号 15937 ,查询到姓名 " + name);
|
||||
|
||||
|
||||
@@ -39,13 +39,13 @@ class HashMapChaining {
|
||||
/* 查询操作 */
|
||||
public string? Get(int key) {
|
||||
int index = HashFunc(key);
|
||||
// 遍历桶,若找到 key 则返回对应 val
|
||||
// 遍历桶,若找到 key ,则返回对应 val
|
||||
foreach (Pair pair in buckets[index]) {
|
||||
if (pair.key == key) {
|
||||
return pair.val;
|
||||
}
|
||||
}
|
||||
// 若未找到 key 则返回 null
|
||||
// 若未找到 key ,则返回 null
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -131,7 +131,7 @@ public class hash_map_chaining {
|
||||
map.Print();
|
||||
|
||||
/* 查询操作 */
|
||||
// 向哈希表输入键 key ,得到值 value
|
||||
// 向哈希表中输入键 key ,得到值 value
|
||||
string? name = map.Get(13276);
|
||||
Console.WriteLine("\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 不存在,则返回添加点的索引
|
||||
@@ -146,7 +146,7 @@ public class hash_map_open_addressing {
|
||||
map.Print();
|
||||
|
||||
/* 查询操作 */
|
||||
// 向哈希表输入键 key ,得到值 value
|
||||
// 向哈希表中输入键 key ,得到值 value
|
||||
string? name = map.Get(13276);
|
||||
Console.WriteLine("\n输入学号 13276 ,查询到姓名 " + name);
|
||||
|
||||
|
||||
@@ -27,17 +27,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; // 向下整除
|
||||
}
|
||||
|
||||
@@ -34,7 +34,7 @@ public class bubble_sort {
|
||||
flag = true; // 记录交换元素
|
||||
}
|
||||
}
|
||||
if (!flag) break; // 此轮冒泡未交换任何元素,直接跳出
|
||||
if (!flag) break; // 此轮“冒泡”未交换任何元素,直接跳出
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -9,12 +9,12 @@ namespace hello_algo.chapter_sorting;
|
||||
public class merge_sort {
|
||||
/* 合并左子数组和右子数组 */
|
||||
void Merge(int[] nums, int left, int mid, int right) {
|
||||
// 左子数组区间 [left, mid], 右子数组区间 [mid+1, right]
|
||||
// 左子数组区间为 [left, mid], 右子数组区间为 [mid+1, right]
|
||||
// 创建一个临时数组 tmp ,用于存放合并后的结果
|
||||
int[] tmp = new int[right - left + 1];
|
||||
// 初始化左子数组和右子数组的起始索引
|
||||
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], nums[i]) = (nums[i], nums[j]);
|
||||
}
|
||||
|
||||
/* 选取三个元素的中位数 */
|
||||
/* 选取三个候选元素的中位数 */
|
||||
static int MedianThree(int[] nums, int left, int mid, int right) {
|
||||
// 此处使用异或运算来简化代码
|
||||
// 异或规则为 0 ^ 0 = 1 ^ 1 = 0, 0 ^ 1 = 1 ^ 0 = 1
|
||||
|
||||
@@ -48,7 +48,7 @@ public class ArrayDeque {
|
||||
return;
|
||||
}
|
||||
// 队首指针向左移动一位
|
||||
// 通过取余操作,实现 front 越过数组头部后回到尾部
|
||||
// 通过取余操作实现 front 越过数组头部后回到尾部
|
||||
front = Index(front - 1);
|
||||
// 将 num 添加至队首
|
||||
nums[front] = num;
|
||||
@@ -61,7 +61,7 @@ public class ArrayDeque {
|
||||
Console.WriteLine("双向队列已满");
|
||||
return;
|
||||
}
|
||||
// 计算尾指针,指向队尾索引 + 1
|
||||
// 计算队尾指针,指向队尾索引 + 1
|
||||
int rear = Index(front + queSize);
|
||||
// 将 num 添加至队尾
|
||||
nums[rear] = num;
|
||||
|
||||
@@ -38,8 +38,8 @@ class ArrayQueue {
|
||||
Console.WriteLine("队列已满");
|
||||
return;
|
||||
}
|
||||
// 计算尾指针,指向队尾索引 + 1
|
||||
// 通过取余操作,实现 rear 越过数组尾部后回到头部
|
||||
// 计算队尾指针,指向队尾索引 + 1
|
||||
// 通过取余操作实现 rear 越过数组尾部后回到头部
|
||||
int rear = (front + queSize) % Capacity();
|
||||
// 将 num 添加至队尾
|
||||
nums[rear] = num;
|
||||
@@ -49,7 +49,7 @@ class ArrayQueue {
|
||||
/* 出队 */
|
||||
public int Pop() {
|
||||
int num = Peek();
|
||||
// 队首指针向后移动一位,若越过尾部则返回到数组头部
|
||||
// 队首指针向后移动一位,若越过尾部,则返回到数组头部
|
||||
front = (front + 1) % Capacity();
|
||||
queSize--;
|
||||
return num;
|
||||
|
||||
@@ -28,7 +28,7 @@ class LinkedListQueue {
|
||||
|
||||
/* 入队 */
|
||||
public void Push(int num) {
|
||||
// 尾节点后添加 num
|
||||
// 在尾节点后添加 num
|
||||
ListNode node = new(num);
|
||||
// 如果队列为空,则令头、尾节点都指向该节点
|
||||
if (front == null) {
|
||||
|
||||
@@ -96,7 +96,7 @@ class AVLTree {
|
||||
/* 递归插入节点(辅助方法) */
|
||||
TreeNode? InsertHelper(TreeNode? node, int val) {
|
||||
if (node == null) return new TreeNode(val);
|
||||
/* 1. 查找插入位置,并插入节点 */
|
||||
/* 1. 查找插入位置并插入节点 */
|
||||
if (val < node.val)
|
||||
node.left = InsertHelper(node.left, val);
|
||||
else if (val > node.val)
|
||||
@@ -118,7 +118,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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -34,7 +34,7 @@ func (l *myList) capacity() int {
|
||||
|
||||
/* 访问元素 */
|
||||
func (l *myList) get(index int) int {
|
||||
// 索引如果越界则抛出异常,下同
|
||||
// 索引如果越界,则抛出异常,下同
|
||||
if index < 0 || index >= l.arrSize {
|
||||
panic("索引越界")
|
||||
}
|
||||
@@ -90,13 +90,13 @@ func (l *myList) remove(index int) int {
|
||||
}
|
||||
// 更新元素数量
|
||||
l.arrSize--
|
||||
// 返回被删除元素
|
||||
// 返回被删除的元素
|
||||
return num
|
||||
}
|
||||
|
||||
/* 列表扩容 */
|
||||
func (l *myList) extendCapacity() {
|
||||
// 新建一个长度为原数组 extendRatio 倍的新数组,并将原数组拷贝到新数组
|
||||
// 新建一个长度为原数组 extendRatio 倍的新数组,并将原数组复制到新数组
|
||||
l.arr = append(l.arr, make([]int, l.arrCapacity*(l.extendRatio-1))...)
|
||||
// 更新列表容量
|
||||
l.arrCapacity = len(l.arr)
|
||||
|
||||
@@ -18,10 +18,10 @@ func backtrack(row, n int, state *[][]string, res *[][][]string, cols, diags1, d
|
||||
}
|
||||
// 遍历所有列
|
||||
for col := 0; col < n; col++ {
|
||||
// 计算该格子对应的主对角线和副对角线
|
||||
// 计算该格子对应的主对角线和次对角线
|
||||
diag1 := row - col + n - 1
|
||||
diag2 := row + col
|
||||
// 剪枝:不允许该格子所在列、主对角线、副对角线上存在皇后
|
||||
// 剪枝:不允许该格子所在列、主对角线、次对角线上存在皇后
|
||||
if !(*cols)[col] && !(*diags1)[diag1] && !(*diags2)[diag2] {
|
||||
// 尝试:将皇后放置在该格子
|
||||
(*state)[row][col] = "Q"
|
||||
|
||||
@@ -8,7 +8,7 @@ import (
|
||||
. "github.com/krahets/hello-algo/pkg"
|
||||
)
|
||||
|
||||
/* 广度优先遍历 BFS */
|
||||
/* 广度优先遍历 */
|
||||
// 使用邻接表来表示图,以便获取指定顶点的所有邻接顶点
|
||||
func graphBFS(g *graphAdjList, startVet Vertex) []Vertex {
|
||||
// 顶点遍历序列
|
||||
|
||||
@@ -22,7 +22,7 @@ func TestGraphBFS(t *testing.T) {
|
||||
fmt.Println("初始化后,图为:")
|
||||
graph.print()
|
||||
|
||||
/* 广度优先遍历 BFS */
|
||||
/* 广度优先遍历 */
|
||||
res := graphBFS(graph, vets[0])
|
||||
fmt.Println("广度优先遍历(BFS)顶点序列为:")
|
||||
PrintSlice(VetsToVals(res))
|
||||
|
||||
@@ -8,7 +8,7 @@ import (
|
||||
. "github.com/krahets/hello-algo/pkg"
|
||||
)
|
||||
|
||||
/* 深度优先遍历 DFS 辅助函数 */
|
||||
/* 深度优先遍历辅助函数 */
|
||||
func dfs(g *graphAdjList, visited map[Vertex]struct{}, res *[]Vertex, vet Vertex) {
|
||||
// append 操作会返回新的的引用,必须让原引用重新赋值为新slice的引用
|
||||
*res = append(*res, vet)
|
||||
@@ -23,7 +23,7 @@ func dfs(g *graphAdjList, visited map[Vertex]struct{}, res *[]Vertex, vet Vertex
|
||||
}
|
||||
}
|
||||
|
||||
/* 深度优先遍历 DFS */
|
||||
/* 深度优先遍历 */
|
||||
// 使用邻接表来表示图,以便获取指定顶点的所有邻接顶点
|
||||
func graphDFS(g *graphAdjList, startVet Vertex) []Vertex {
|
||||
// 顶点遍历序列
|
||||
|
||||
@@ -21,7 +21,7 @@ func TestGraphDFS(t *testing.T) {
|
||||
fmt.Println("初始化后,图为:")
|
||||
graph.print()
|
||||
|
||||
/* 深度优先遍历 DFS */
|
||||
/* 深度优先遍历 */
|
||||
res := graphDFS(graph, vets[0])
|
||||
fmt.Println("深度优先遍历(DFS)顶点序列为:")
|
||||
PrintSlice(VetsToVals(res))
|
||||
|
||||
@@ -8,7 +8,7 @@ import "math"
|
||||
|
||||
/* 最大容量:贪心 */
|
||||
func maxCapacity(ht []int) int {
|
||||
// 初始化 i, j 分列数组两端
|
||||
// 初始化 i, j,使其分列数组两端
|
||||
i, j := 0, len(ht)-1
|
||||
// 初始最大容量为 0
|
||||
res := 0
|
||||
|
||||
@@ -24,7 +24,7 @@ func TestArrayHashMap(t *testing.T) {
|
||||
hmap.print()
|
||||
|
||||
/* 查询操作 */
|
||||
// 向哈希表输入键 key ,得到值 value
|
||||
// 向哈希表中输入键 key ,得到值 value
|
||||
name := hmap.get(15937)
|
||||
fmt.Println("\n输入学号 15937 ,查询到姓名 " + name)
|
||||
|
||||
|
||||
@@ -24,7 +24,7 @@ func TestHashMapChaining(t *testing.T) {
|
||||
hmap.print()
|
||||
|
||||
/* 查询操作 */
|
||||
// 向哈希表输入键 key ,得到值 value
|
||||
// 向哈希表中输入键 key ,得到值 value
|
||||
name := hmap.get(15937)
|
||||
fmt.Println("\n输入学号 15937 ,查询到姓名 ", name)
|
||||
|
||||
@@ -50,7 +50,7 @@ func TestHashMapOpenAddressing(t *testing.T) {
|
||||
hmap.print()
|
||||
|
||||
/* 查询操作 */
|
||||
// 向哈希表输入键 key ,得到值 value
|
||||
// 向哈希表中输入键 key ,得到值 value
|
||||
name := hmap.get(13276)
|
||||
fmt.Println("\n输入学号 13276 ,查询到姓名 ", name)
|
||||
|
||||
|
||||
@@ -48,13 +48,13 @@ func (m *hashMapChaining) loadFactor() float64 {
|
||||
func (m *hashMapChaining) get(key int) string {
|
||||
idx := m.hashFunc(key)
|
||||
bucket := m.buckets[idx]
|
||||
// 遍历桶,若找到 key 则返回对应 val
|
||||
// 遍历桶,若找到 key ,则返回对应 val
|
||||
for _, p := range bucket {
|
||||
if p.key == key {
|
||||
return p.val
|
||||
}
|
||||
}
|
||||
// 若未找到 key 则返回空字符串
|
||||
// 若未找到 key ,则返回空字符串
|
||||
return ""
|
||||
}
|
||||
|
||||
|
||||
@@ -50,7 +50,7 @@ func (m *hashMapOpenAddressing) get(key int) string {
|
||||
idx := m.hashFunc(key)
|
||||
// 线性探测,从 index 开始向后遍历
|
||||
for i := 0; i < m.capacity; i++ {
|
||||
// 计算桶索引,越过尾部返回头部
|
||||
// 计算桶索引,越过尾部则返回头部
|
||||
j := (idx + i) % m.capacity
|
||||
// 若遇到空桶,说明无此 key ,则返回 null
|
||||
if m.buckets[j] == (pair{}) {
|
||||
@@ -61,7 +61,7 @@ func (m *hashMapOpenAddressing) get(key int) string {
|
||||
return m.buckets[j].val
|
||||
}
|
||||
}
|
||||
// 若未找到 key 则返回空字符串
|
||||
// 若未找到 key ,则返回空字符串
|
||||
return ""
|
||||
}
|
||||
|
||||
@@ -74,7 +74,7 @@ func (m *hashMapOpenAddressing) put(key int, val string) {
|
||||
idx := m.hashFunc(key)
|
||||
// 线性探测,从 index 开始向后遍历
|
||||
for i := 0; i < m.capacity; i++ {
|
||||
// 计算桶索引,越过尾部返回头部
|
||||
// 计算桶索引,越过尾部则返回头部
|
||||
j := (idx + i) % m.capacity
|
||||
// 若遇到空桶、或带有删除标记的桶,则将键值对放入该桶
|
||||
if m.buckets[j] == (pair{}) || m.buckets[j] == m.removed {
|
||||
@@ -99,7 +99,7 @@ func (m *hashMapOpenAddressing) remove(key int) {
|
||||
// 遍历桶,从中删除键值对
|
||||
// 线性探测,从 index 开始向后遍历
|
||||
for i := 0; i < m.capacity; i++ {
|
||||
// 计算桶索引,越过尾部返回头部
|
||||
// 计算桶索引,越过尾部则返回头部
|
||||
j := (idx + i) % m.capacity
|
||||
// 若遇到空桶,说明无此 key ,则直接返回
|
||||
if m.buckets[j] == (pair{}) {
|
||||
|
||||
@@ -27,7 +27,7 @@ func TestHashMap(t *testing.T) {
|
||||
PrintMap(hmap)
|
||||
|
||||
/* 查询操作 */
|
||||
// 向哈希表输入键 key ,得到值 value
|
||||
// 向哈希表中输入键 key ,得到值 value
|
||||
name := hmap[15937]
|
||||
fmt.Println("\n输入学号 15937 ,查询到姓名 ", name)
|
||||
|
||||
|
||||
@@ -33,17 +33,17 @@ func newMaxHeap(nums []any) *maxHeap {
|
||||
return h
|
||||
}
|
||||
|
||||
/* 获取左子节点索引 */
|
||||
/* 获取左子节点的索引 */
|
||||
func (h *maxHeap) left(i int) int {
|
||||
return 2*i + 1
|
||||
}
|
||||
|
||||
/* 获取右子节点索引 */
|
||||
/* 获取右子节点的索引 */
|
||||
func (h *maxHeap) right(i int) int {
|
||||
return 2*i + 2
|
||||
}
|
||||
|
||||
/* 获取父节点索引 */
|
||||
/* 获取父节点的索引 */
|
||||
func (h *maxHeap) parent(i int) int {
|
||||
// 向下整除
|
||||
return (i - 1) / 2
|
||||
|
||||
@@ -31,7 +31,7 @@ func bubbleSortWithFlag(nums []int) {
|
||||
flag = true // 记录交换元素
|
||||
}
|
||||
}
|
||||
if flag == false { // 此轮冒泡未交换任何元素,直接跳出
|
||||
if flag == false { // 此轮“冒泡”未交换任何元素,直接跳出
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,12 +6,12 @@ package chapter_sorting
|
||||
|
||||
/* 合并左子数组和右子数组 */
|
||||
func merge(nums []int, left, mid, right int) {
|
||||
// 左子数组区间 [left, mid], 右子数组区间 [mid+1, right]
|
||||
// 左子数组区间为 [left, mid], 右子数组区间为 [mid+1, right]
|
||||
// 创建一个临时数组 tmp ,用于存放合并后的结果
|
||||
tmp := make([]int, right-left+1)
|
||||
// 初始化左子数组和右子数组的起始索引
|
||||
i, j, k := left, mid+1, 0
|
||||
// 当左右子数组都还有元素时,比较并将较小的元素复制到临时数组中
|
||||
// 当左右子数组都还有元素时,进行比较并将较小的元素复制到临时数组中
|
||||
for i <= mid && j <= right {
|
||||
if nums[i] <= nums[j] {
|
||||
tmp[k] = nums[i]
|
||||
|
||||
@@ -45,7 +45,7 @@ func (q *quickSort) quickSort(nums []int, left, right int) {
|
||||
q.quickSort(nums, pivot+1, right)
|
||||
}
|
||||
|
||||
/* 选取三个元素的中位数 */
|
||||
/* 选取三个候选元素的中位数 */
|
||||
func (q *quickSortMedian) medianThree(nums []int, left, mid, right int) int {
|
||||
// 此处使用异或运算来简化代码(!= 在这里起到异或的作用)
|
||||
// 异或规则为 0 ^ 0 = 1 ^ 1 = 0, 0 ^ 1 = 1 ^ 0 = 1
|
||||
|
||||
@@ -49,7 +49,7 @@ func (q *arrayDeque) pushFirst(num int) {
|
||||
return
|
||||
}
|
||||
// 队首指针向左移动一位
|
||||
// 通过取余操作,实现 front 越过数组头部后回到尾部
|
||||
// 通过取余操作实现 front 越过数组头部后回到尾部
|
||||
q.front = q.index(q.front - 1)
|
||||
// 将 num 添加至队首
|
||||
q.nums[q.front] = num
|
||||
@@ -62,7 +62,7 @@ func (q *arrayDeque) pushLast(num int) {
|
||||
fmt.Println("双向队列已满")
|
||||
return
|
||||
}
|
||||
// 计算尾指针,指向队尾索引 + 1
|
||||
// 计算队尾指针,指向队尾索引 + 1
|
||||
rear := q.index(q.front + q.queSize)
|
||||
// 将 num 添加至队首
|
||||
q.nums[rear] = num
|
||||
|
||||
@@ -38,8 +38,8 @@ func (q *arrayQueue) push(num int) {
|
||||
if q.queSize == q.queCapacity {
|
||||
return
|
||||
}
|
||||
// 计算尾指针,指向队尾索引 + 1
|
||||
// 通过取余操作,实现 rear 越过数组尾部后回到头部
|
||||
// 计算队尾指针,指向队尾索引 + 1
|
||||
// 通过取余操作实现 rear 越过数组尾部后回到头部
|
||||
rear := (q.front + q.queSize) % q.queCapacity
|
||||
// 将 num 添加至队尾
|
||||
q.nums[rear] = num
|
||||
@@ -49,7 +49,7 @@ func (q *arrayQueue) push(num int) {
|
||||
/* 出队 */
|
||||
func (q *arrayQueue) pop() any {
|
||||
num := q.peek()
|
||||
// 队首指针向后移动一位,若越过尾部则返回到数组头部
|
||||
// 队首指针向后移动一位,若越过尾部,则返回到数组头部
|
||||
q.front = (q.front + 1) % q.queCapacity
|
||||
q.queSize--
|
||||
return num
|
||||
|
||||
@@ -116,7 +116,7 @@ func (t *aVLTree) insertHelper(node *TreeNode, val int) *TreeNode {
|
||||
if node == nil {
|
||||
return NewTreeNode(val)
|
||||
}
|
||||
/* 1. 查找插入位置,并插入节点 */
|
||||
/* 1. 查找插入位置并插入节点 */
|
||||
if val < node.Val.(int) {
|
||||
node.Left = t.insertHelper(node.Left, val)
|
||||
} else if val > node.Val.(int) {
|
||||
@@ -143,7 +143,7 @@ func (t *aVLTree) removeHelper(node *TreeNode, val int) *TreeNode {
|
||||
if node == nil {
|
||||
return nil
|
||||
}
|
||||
/* 1. 查找节点,并删除之 */
|
||||
/* 1. 查找节点并删除 */
|
||||
if val < node.Val.(int) {
|
||||
node.Left = t.removeHelper(node.Left, val)
|
||||
} else if val > node.Val.(int) {
|
||||
|
||||
@@ -32,7 +32,7 @@ class MyList {
|
||||
|
||||
/* 访问元素 */
|
||||
public int get(int index) {
|
||||
// 索引如果越界则抛出异常,下同
|
||||
// 索引如果越界,则抛出异常,下同
|
||||
if (index < 0 || index >= size)
|
||||
throw new IndexOutOfBoundsException("索引越界");
|
||||
return arr[index];
|
||||
@@ -82,13 +82,13 @@ class MyList {
|
||||
}
|
||||
// 更新元素数量
|
||||
size--;
|
||||
// 返回被删除元素
|
||||
// 返回被删除的元素
|
||||
return num;
|
||||
}
|
||||
|
||||
/* 列表扩容 */
|
||||
public void extendCapacity() {
|
||||
// 新建一个长度为原数组 extendRatio 倍的新数组,并将原数组拷贝到新数组
|
||||
// 新建一个长度为原数组 extendRatio 倍的新数组,并将原数组复制到新数组
|
||||
arr = Arrays.copyOf(arr, capacity() * extendRatio);
|
||||
// 更新列表容量
|
||||
capacity = arr.length;
|
||||
|
||||
@@ -23,10 +23,10 @@ public class n_queens {
|
||||
}
|
||||
// 遍历所有列
|
||||
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.get(row).set(col, "Q");
|
||||
@@ -53,7 +53,7 @@ public class n_queens {
|
||||
}
|
||||
boolean[] cols = new boolean[n]; // 记录列是否有皇后
|
||||
boolean[] diags1 = new boolean[2 * n - 1]; // 记录主对角线上是否有皇后
|
||||
boolean[] diags2 = new boolean[2 * n - 1]; // 记录副对角线上是否有皇后
|
||||
boolean[] diags2 = new boolean[2 * n - 1]; // 记录次对角线上是否有皇后
|
||||
List<List<List<String>>> res = new ArrayList<>();
|
||||
|
||||
backtrack(0, n, state, res, cols, diags1, diags2);
|
||||
|
||||
@@ -10,7 +10,7 @@ import java.util.*;
|
||||
import utils.*;
|
||||
|
||||
public class graph_bfs {
|
||||
/* 广度优先遍历 BFS */
|
||||
/* 广度优先遍历 */
|
||||
// 使用邻接表来表示图,以便获取指定顶点的所有邻接顶点
|
||||
static List<Vertex> graphBFS(GraphAdjList graph, Vertex startVet) {
|
||||
// 顶点遍历序列
|
||||
@@ -47,7 +47,7 @@ public class graph_bfs {
|
||||
System.out.println("\n初始化后,图为");
|
||||
graph.print();
|
||||
|
||||
/* 广度优先遍历 BFS */
|
||||
/* 广度优先遍历 */
|
||||
List<Vertex> res = graphBFS(graph, v[0]);
|
||||
System.out.println("\n广度优先遍历(BFS)顶点序列为");
|
||||
System.out.println(Vertex.vetsToVals(res));
|
||||
|
||||
@@ -10,7 +10,7 @@ import java.util.*;
|
||||
import utils.*;
|
||||
|
||||
public class graph_dfs {
|
||||
/* 深度优先遍历 DFS 辅助函数 */
|
||||
/* 深度优先遍历辅助函数 */
|
||||
static void dfs(GraphAdjList graph, Set<Vertex> visited, List<Vertex> res, Vertex vet) {
|
||||
res.add(vet); // 记录访问顶点
|
||||
visited.add(vet); // 标记该顶点已被访问
|
||||
@@ -23,7 +23,7 @@ public class graph_dfs {
|
||||
}
|
||||
}
|
||||
|
||||
/* 深度优先遍历 DFS */
|
||||
/* 深度优先遍历 */
|
||||
// 使用邻接表来表示图,以便获取指定顶点的所有邻接顶点
|
||||
static List<Vertex> graphDFS(GraphAdjList graph, Vertex startVet) {
|
||||
// 顶点遍历序列
|
||||
@@ -43,7 +43,7 @@ public class graph_dfs {
|
||||
System.out.println("\n初始化后,图为");
|
||||
graph.print();
|
||||
|
||||
/* 深度优先遍历 DFS */
|
||||
/* 深度优先遍历 */
|
||||
List<Vertex> res = graphDFS(graph, v[0]);
|
||||
System.out.println("\n深度优先遍历(DFS)顶点序列为");
|
||||
System.out.println(Vertex.vetsToVals(res));
|
||||
|
||||
@@ -9,7 +9,7 @@ package chapter_greedy;
|
||||
public class max_capacity {
|
||||
/* 最大容量:贪心 */
|
||||
static int maxCapacity(int[] ht) {
|
||||
// 初始化 i, j 分列数组两端
|
||||
// 初始化 i, j,使其分列数组两端
|
||||
int i = 0, j = ht.length - 1;
|
||||
// 初始最大容量为 0
|
||||
int res = 0;
|
||||
|
||||
@@ -114,7 +114,7 @@ public class array_hash_map {
|
||||
map.print();
|
||||
|
||||
/* 查询操作 */
|
||||
// 向哈希表输入键 key ,得到值 value
|
||||
// 向哈希表中输入键 key ,得到值 value
|
||||
String name = map.get(15937);
|
||||
System.out.println("\n输入学号 15937 ,查询到姓名 " + name);
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@ public class hash_map {
|
||||
PrintUtil.printHashMap(map);
|
||||
|
||||
/* 查询操作 */
|
||||
// 向哈希表输入键 key ,得到值 value
|
||||
// 向哈希表中输入键 key ,得到值 value
|
||||
String name = map.get(15937);
|
||||
System.out.println("\n输入学号 15937 ,查询到姓名 " + name);
|
||||
|
||||
|
||||
@@ -43,13 +43,13 @@ class HashMapChaining {
|
||||
String get(int key) {
|
||||
int index = hashFunc(key);
|
||||
List<Pair> bucket = buckets.get(index);
|
||||
// 遍历桶,若找到 key 则返回对应 val
|
||||
// 遍历桶,若找到 key ,则返回对应 val
|
||||
for (Pair pair : bucket) {
|
||||
if (pair.key == key) {
|
||||
return pair.val;
|
||||
}
|
||||
}
|
||||
// 若未找到 key 则返回 null
|
||||
// 若未找到 key ,则返回 null
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -135,7 +135,7 @@ public class hash_map_chaining {
|
||||
map.print();
|
||||
|
||||
/* 查询操作 */
|
||||
// 向哈希表输入键 key ,得到值 value
|
||||
// 向哈希表中输入键 key ,得到值 value
|
||||
String name = map.get(13276);
|
||||
System.out.println("\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 @@ public class hash_map_open_addressing {
|
||||
hashmap.print();
|
||||
|
||||
// 查询操作
|
||||
// 向哈希表输入键 key ,得到值 val
|
||||
// 向哈希表中输入键 key ,得到值 val
|
||||
String name = hashmap.get(13276);
|
||||
System.out.println("\n输入学号 13276 ,查询到姓名 " + name);
|
||||
|
||||
|
||||
@@ -24,17 +24,17 @@ class MaxHeap {
|
||||
}
|
||||
}
|
||||
|
||||
/* 获取左子节点索引 */
|
||||
/* 获取左子节点的索引 */
|
||||
private int left(int i) {
|
||||
return 2 * i + 1;
|
||||
}
|
||||
|
||||
/* 获取右子节点索引 */
|
||||
/* 获取右子节点的索引 */
|
||||
private int right(int i) {
|
||||
return 2 * i + 2;
|
||||
}
|
||||
|
||||
/* 获取父节点索引 */
|
||||
/* 获取父节点的索引 */
|
||||
private int parent(int i) {
|
||||
return (i - 1) / 2; // 向下整除
|
||||
}
|
||||
|
||||
@@ -41,7 +41,7 @@ public class bubble_sort {
|
||||
}
|
||||
}
|
||||
if (!flag)
|
||||
break; // 此轮冒泡未交换任何元素,直接跳出
|
||||
break; // 此轮“冒泡”未交换任何元素,直接跳出
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -11,12 +11,12 @@ import java.util.*;
|
||||
public class merge_sort {
|
||||
/* 合并左子数组和右子数组 */
|
||||
static void merge(int[] nums, int left, int mid, int right) {
|
||||
// 左子数组区间 [left, mid], 右子数组区间 [mid+1, right]
|
||||
// 左子数组区间为 [left, mid], 右子数组区间为 [mid+1, right]
|
||||
// 创建一个临时数组 tmp ,用于存放合并后的结果
|
||||
int[] tmp = new int[right - left + 1];
|
||||
// 初始化左子数组和右子数组的起始索引
|
||||
int i = left, j = mid + 1, k = 0;
|
||||
// 当左右子数组都还有元素时,比较并将较小的元素复制到临时数组中
|
||||
// 当左右子数组都还有元素时,进行比较并将较小的元素复制到临时数组中
|
||||
while (i <= mid && j <= right) {
|
||||
if (nums[i] <= nums[j])
|
||||
tmp[k++] = nums[i++];
|
||||
|
||||
@@ -54,7 +54,7 @@ class QuickSortMedian {
|
||||
nums[j] = tmp;
|
||||
}
|
||||
|
||||
/* 选取三个元素的中位数 */
|
||||
/* 选取三个候选元素的中位数 */
|
||||
static int medianThree(int[] nums, int left, int mid, int right) {
|
||||
// 此处使用异或运算来简化代码
|
||||
// 异或规则为 0 ^ 0 = 1 ^ 1 = 0, 0 ^ 1 = 1 ^ 0 = 1
|
||||
|
||||
@@ -50,7 +50,7 @@ class ArrayDeque {
|
||||
return;
|
||||
}
|
||||
// 队首指针向左移动一位
|
||||
// 通过取余操作,实现 front 越过数组头部后回到尾部
|
||||
// 通过取余操作实现 front 越过数组头部后回到尾部
|
||||
front = index(front - 1);
|
||||
// 将 num 添加至队首
|
||||
nums[front] = num;
|
||||
@@ -63,7 +63,7 @@ class ArrayDeque {
|
||||
System.out.println("双向队列已满");
|
||||
return;
|
||||
}
|
||||
// 计算尾指针,指向队尾索引 + 1
|
||||
// 计算队尾指针,指向队尾索引 + 1
|
||||
int rear = index(front + queSize);
|
||||
// 将 num 添加至队尾
|
||||
nums[rear] = num;
|
||||
|
||||
@@ -40,8 +40,8 @@ class ArrayQueue {
|
||||
System.out.println("队列已满");
|
||||
return;
|
||||
}
|
||||
// 计算尾指针,指向队尾索引 + 1
|
||||
// 通过取余操作,实现 rear 越过数组尾部后回到头部
|
||||
// 计算队尾指针,指向队尾索引 + 1
|
||||
// 通过取余操作实现 rear 越过数组尾部后回到头部
|
||||
int rear = (front + queSize) % capacity();
|
||||
// 将 num 添加至队尾
|
||||
nums[rear] = num;
|
||||
@@ -51,7 +51,7 @@ class ArrayQueue {
|
||||
/* 出队 */
|
||||
public int pop() {
|
||||
int num = peek();
|
||||
// 队首指针向后移动一位,若越过尾部则返回到数组头部
|
||||
// 队首指针向后移动一位,若越过尾部,则返回到数组头部
|
||||
front = (front + 1) % capacity();
|
||||
queSize--;
|
||||
return num;
|
||||
|
||||
@@ -30,7 +30,7 @@ class LinkedListQueue {
|
||||
|
||||
/* 入队 */
|
||||
public void push(int num) {
|
||||
// 尾节点后添加 num
|
||||
// 在尾节点后添加 num
|
||||
ListNode node = new ListNode(num);
|
||||
// 如果队列为空,则令头、尾节点都指向该节点
|
||||
if (front == null) {
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user