当前位置: 首页 > news >正文

算法之回溯法

回溯法

  • 回溯法
    • 定义与概念
    • 核心思想
    • 回溯法的一般框架
      • 伪代码表示
      • C语言实现框架
    • 回溯法的优化技巧
      • 剪枝策略
      • 实现剪枝的C语言示例
      • 记忆化搜索
    • 案例分析
      • N皇后问题
      • 子集和问题
      • 全排列问题
      • 寻路问题
    • 回溯法的可视化理解
      • 决策树
      • 状态空间树
      • 回溯过程
    • 回溯法与其他算法的比较
      • 回溯法与动态规划的区别
      • 回溯法与贪心算法的区别
    • 总结
      • 应用场景总结
      • 优化技巧总结

回溯法

定义与概念

回溯法是一种通过探索所有可能的候选解来找出所有解的算法。它采用试错的思想,尝试分步解决一个问题,在分步解决问题的过程中,当发现现有的分步答案不能得到有效的正确的解答时,它将取消上一步甚至是上几步的计算,再通过其它的可能的分步解答再次尝试寻找问题的答案。

回溯法通常用最简单的递归方法来实现,在反复重复上述的步骤后可能出现两种情况:

  • 找到一个可能存在的正确答案
  • 在尝试了所有可能的分步方法后宣告该问题无解

核心思想

典型的回溯算法通常包括以下步骤:

选择:在解空间中,进行一次选择,生成一个可能的解。

约束条件:检查当前的选择是否满足问题的限制条件。

判断:判断当前的选择是否是问题的解决方案。

回溯:如果当前选择不符合约束条件或者不是最终解,就撤销这次选择,回到之前的状态,并尝试其他的选择。

重复:重复上述步骤,直到找到问题的解决方案或者穷尽所有可能性。

典型的应用场景包括:

  • 组合求和问题:寻找集合中符合特定条件的子集合或组合。
  • 排列问题:如全排列、字符串排列等。
  • 棋盘游戏:例如数独、八皇后等问题。
  • 图搜索:在图中寻找路径、回路等问题。

回溯算法在解决组合优化问题时通常具有高效的灵活性,但随着问题规模的增加,其时间复杂度可能会指数级增长。因此,在实际应用中,通常会对算法进行优化,比如剪枝、启发式搜索等方法,以提高效率。

回溯法的一般框架

伪代码表示

回溯法的一般框架可以用以下伪代码表示:

void backtrack(Candidate* candidate) {// 检查是否找到解决方案if (find_solution(candidate)) {output_solution(candidate);return;}// 获取候选列表Candidate next_candidates[MAX_CANDIDATES];int candidate_count = 0;generate_candidates(candidate, next_candidates, &candidate_count);// 尝试每个候选解for (int i = 0; i < candidate_count; i++) {if (is_valid(&next_candidates[i])) {// 放置候选解place_candidate(candidate, &next_candidates[i]);// 递归搜索backtrack(candidate);// 移除候选解(回溯)remove_candidate(candidate, &next_candidates[i]);}}
}

其中:

  • find_solution():检查当前候选解是否是一个完整的解
  • output_solution():输出找到的解决方案
  • generate_candidates():生成当前可以选择的候选解列表
  • is_valid():检查当前候选解是否满足约束条件
  • place_candidate():将当前候选解放入解集合中
  • remove_candidate():将当前候选解从解集合中移除(回溯)
  • MAX_CANDIDATES:候选解数组的最大容量
  • Candidate:表示候选解的数据结构

C语言实现框架

以下是回溯法的C语言通用框架实现:

#include <stdio.h>
#include <stdbool.h>// 问题的状态结构
typedef struct {// 问题特定的状态变量int n;              // 问题规模int* solution;      // 当前解int depth;          // 当前搜索深度// 其他需要的状态变量
} State;// 初始化状态
void initState(State* state, int n) {state->n = n;state->depth = 0;state->solution = (int*)malloc(n * sizeof(int));// 初始化其他状态变量
}// 检查是否找到解
bool isSolution(State* state) {// 实现检查当前状态是否是一个完整的解的逻辑return state->depth == state->n; // 示例:当深度等于问题规模时找到解
}// 处理找到的解
void processSolution(State* state) {printf("找到一个解: ");for (int i = 0; i < state->n; i++) {printf("%d ", state->solution[i]);}printf("\n");
}// 生成候选
void generateCandidates(State* state, int candidates[], int* count) {// 实现生成候选的逻辑*count = 0;// 填充candidates数组并更新count
}// 检查候选是否有效
bool isValid(State* state, int candidate) {// 实现检查候选是否有效的逻辑return true; // 示例:所有候选都有效
}// 做出选择
void makeMove(State* state, int candidate) {// 实现做出选择的逻辑state->solution[state->depth] = candidate;state->depth++;
}// 撤销选择(回溯)
void unmakeMove(State* state) {// 实现撤销选择的逻辑state->depth--;
}// 回溯算法主体
void backtrack(State* state) {if (isSolution(state)) {processSolution(state);return;}int candidates[100]; // 假设最多100个候选int candidateCount;generateCandidates(state, candidates, &candidateCount);for (int i = 0; i < candidateCount; i++) {if (isValid(state, candidates[i])) {makeMove(state, candidates[i]);backtrack(state);unmakeMove(state);}}
}// 主函数
int main() {int n = 4; // 问题规模State state;initState(&state, n);backtrack(&state);free(state.solution);return 0;
}

回溯法的优化技巧

剪枝策略

剪枝是回溯法中最重要的优化技巧,它可以显著减少搜索空间,提高算法效率。常见的剪枝策略包括:

  1. 可行性剪枝:在搜索过程中,如果当前状态已经不可能产生有效解,则立即回溯。

  2. 最优性剪枝:在求解最优化问题时,如果当前状态的解不可能优于已知的最优解,则立即回溯。

  3. 对称性剪枝:利用问题的对称性,避免搜索等价的状态。

  4. 启发式剪枝:使用启发式函数估计当前状态的潜力,优先搜索更有希望的状态。

实现剪枝的C语言示例

以下是在子集和问题中实现剪枝的示例:

// 子集和问题的结构定义
typedef struct {int* set;           // 原始集合int set_size;       // 集合大小int target_sum;     // 目标和int current_sum;    // 当前和int* current;       // 当前选择状态
} SubsetSum;// 打印子集
void printSubset(SubsetSum* problem) {printf("{ ");for (int i = 0; i < problem->set_size; i++) {if (problem->current[i]) {printf("%d ", problem->set[i]);}}printf("}\n");
}// 带剪枝的子集和问题回溯函数
void subsetSumBacktrackWithPruning(SubsetSum* problem, int index, int* solutions_count) {// 剪枝1:如果当前和已经等于目标和,直接输出解if (problem->current_sum == problem->target_sum) {(*solutions_count)++;printf("解决方案 %d: ", *solutions_count);printSubset(problem);return;}// 剪枝2:如果当前和已经超过目标和,直接回溯if (problem->current_sum > problem->target_sum) {return;}// 剪枝3:如果即使将剩余所有元素都选上也无法达到目标和,直接回溯int remaining_sum = 0;for (int i = index; i < problem->set_size; i++) {remaining_sum += problem->set[i];}if (problem->current_sum + remaining_sum < problem->target_sum) {return;}// 基本情况:已经处理完所有元素if (index == problem->set_size) {return;}// 选择当前元素problem->current[index] = 1;problem->current_sum += problem->set[index];subsetSumBacktrackWithPruning(problem, index + 1, solutions_count);// 回溯,不选当前元素problem->current_sum -= problem->set[index];problem->current[index] = 0;subsetSumBacktrackWithPruning(problem, index + 1, solutions_count);
}

记忆化搜索

记忆化搜索是一种结合了动态规划思想的回溯优化技术,它通过存储已经计算过的状态结果,避免重复计算。

// 记忆化搜索示例(斐波那契数列)
int memo[100] = {0}; // 记忆数组,初始化为0int fibonacci(int n) {// 基本情况if (n <= 1) return n;// 如果已经计算过,直接返回结果if (memo[n] != 0) return memo[n];// 计算结果并存储memo[n] = fibonacci(n-1) + fibonacci(n-2);return memo[n];
}

案例分析

N皇后问题

N皇后问题是一个经典的问题:在N×N格的棋盘上放置N个皇后,使得它们不能互相攻击。按照国际象棋的规则,皇后可以攻击同一行、同一列或同一斜线上的棋子。

以下是N皇后问题的C语言实现:

#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>#define N 8  // 棋盘大小和皇后数量// 打印棋盘
void printSolution(int board[N][N]) {for (int i = 0; i < N; i++) {for (int j = 0; j < N; j++) {printf("%c ", board[i][j] ? 'Q' : '.');}printf("\n");}printf("\n");
}// 检查在board[row][col]位置放置皇后是否安全
bool isSafe(int board[N][N], int row, int col) {int i, j;// 检查这一行的左侧for (i = 0; i < col; i++) {if (board[row][i]) {return false;}}// 检查左上对角线for (i = row, j = col; i >= 0 && j >= 0; i--, j--) {if (board[i][j]) {return false;}}// 检查左下对角线for (i = row, j = col; j >= 0 && i < N; i++, j--) {if (board[i][j]) {return false;}}return true;
}// 使用回溯法解决N皇后问题
bool solveNQUtil(int board[N][N], int col, int* solutionCount) {// 基本情况:如果所有皇后都被放置if (col >= N) {(*solutionCount)++;printf("解决方案 %d:\n", *solutionCount);printSolution(board);return true; // 找到一个解决方案}bool res = false;// 考虑这一列并尝试将皇后放在这一列的所有行中for (int i = 0; i < N; i++) {// 检查皇后是否可以放在board[i][col]if (isSafe(board, i, col)) {// 放置皇后在board[i][col]board[i][col] = 1;// 递归放置其余的皇后// 修改这里以找到所有解决方案,而不是只找到一个就返回solveNQUtil(board, col + 1, solutionCount);res = true; // 标记找到了至少一个解决方案// 回溯,移除皇后,继续尝试其他位置board[i][col] = 0; // 回溯}}// 如果皇后不能放在这一列的任何行,则返回falsereturn res;
}// 解决N皇后问题的包装函数
void solveNQ() {int board[N][N] = {0}; // 初始化棋盘int solutionCount = 0;if (!solveNQUtil(board, 0, &solutionCount)) {printf("没有解决方案\n");} else {printf("总共找到 %d 个解决方案\n", solutionCount);}
}int main() {solveNQ();return 0;
}

子集和问题

子集和问题是指:给定一个整数集合和一个目标和,找出集合中所有和为目标值的子集。

/*** 回溯法解决子集和问题* @param problem 子集和问题结构* @param index 当前处理的元素索引* @param solutions_count 找到的解决方案计数*/
void subsetSumBacktrack(SubsetSum* problem, int index, int* solutions_count) {// 基本情况:已经处理完所有元素if (index == problem->set_size) {// 检查是否找到一个解if (problem->current_sum == problem->target_sum) {(*solutions_count)++;printf("解决方案 %d: ", *solutions_count);printSubset(problem);}return;}// 不选当前元素problem->current[index] = 0;subsetSumBacktrack(problem, index + 1, solutions_count);// 选择当前元素(只有当不超过目标和时才选择)if (problem->current_sum + problem->set[index] <= problem->target_sum) {problem->current[index] = 1;problem->current_sum += problem->set[index];subsetSumBacktrack(problem, index + 1, solutions_count);// 回溯problem->current_sum -= problem->set[index];problem->current[index] = 0;}
}

全排列问题

全排列问题是指:给定一个不含重复数字的序列,返回其所有可能的全排列。

// 全排列问题的结构定义
typedef struct {int* nums;          // 原始数字序列int size;           // 序列大小int* result;        // 当前排列结果bool* used;         // 标记数字是否已使用int depth;          // 当前深度
} Permutation;// 打印排列
void printPermutation(Permutation* problem) {printf("{ ");for (int i = 0; i < problem->size; i++) {printf("%d ", problem->result[i]);}printf("}\n");
}/*** 回溯法解决全排列问题* @param problem 全排列问题结构* @param solutions_count 找到的解决方案计数*/
void permutationBacktrack(Permutation* problem, int* solutions_count) {// 基本情况:已经生成完整的排列if (problem->depth == problem->size) {(*solutions_count)++;printf("排列 %d: ", *solutions_count);printPermutation(problem);return;}// 尝试在当前位置放置每个未使用的数字for (int i = 0; i < problem->size; i++) {// 如果数字未被使用if (!problem->used[i]) {// 选择当前数字problem->result[problem->depth] = problem->nums[i];problem->used[i] = true;problem->depth++;// 递归生成下一个位置的数字permutationBacktrack(problem, solutions_count);// 回溯problem->depth--;problem->used[i] = false;}}
}

寻路问题

寻路问题是指在一个迷宫中找出从起点到终点的路径。以下是一个简单的迷宫寻路问题的C语言实现:

#include <stdio.h>
#include <stdbool.h>#define N 5 // 迷宫大小// 迷宫:0表示可以通过的路径,1表示墙
int maze[N][N] = {{0, 1, 0, 0, 0},{0, 1, 0, 1, 0},{0, 0, 0, 0, 0},{0, 1, 1, 1, 0},{0, 0, 0, 1, 0}
};// 解决方案:记录路径,1表示路径的一部分
int solution[N][N] = {0};// 检查(x,y)是否是迷宫中的有效位置
bool isValidPosition(int x, int y) {return (x >= 0 && x < N && y >= 0 && y < N && maze[x][y] == 0);
}// 使用回溯法解决迷宫问题
bool solveMazeUtil(int x, int y) {// 如果(x,y)是目标位置,返回trueif (x == N-1 && y == N-1) {solution[x][y] = 1;return true;}// 检查(x,y)是否是有效位置if (isValidPosition(x, y)) {// 标记(x,y)为路径的一部分solution[x][y] = 1;// 向右移动if (solveMazeUtil(x+1, y)) {return true;}// 向下移动if (solveMazeUtil(x, y+1)) {return true;}// 向左移动if (solveMazeUtil(x-1, y)) {return true;}// 向上移动if (solveMazeUtil(x, y-1)) {return true;}// 如果没有方向可以到达目标,回溯solution[x][y] = 0;return false;}return false;
}// 解决迷宫问题的包装函数
bool solveMaze() {if (!solveMazeUtil(0, 0)) {printf("没有解决方案\n");return false;}// 打印解决方案printf("解决方案:\n");for (int i = 0; i < N; i++) {for (int j = 0; j < N; j++) {printf("%d ", solution[i][j]);}printf("\n");}return true;
}int main() {solveMaze();return 0;
}

回溯法的可视化理解

回溯法本质上是一种深度优先搜索(DFS)的过程,通过可视化工具可以更直观地理解其工作原理。

决策树

回溯法可以通过决策树来可视化理解。每个节点代表一个状态,每条边代表一个选择。回溯法就是在这棵树上进行深度优先搜索,寻找满足条件的路径。

                    [Root]/  |  \/   |   \[A]   [B]   [C]  <- 第一层选择/ \    / \    / \/   \  /   \  /   \[D]  [E][F]  [G][H]  [I]  <- 第二层选择

在这个决策树中:

  • 从根节点开始,我们有三个可能的选择:A、B或C
  • 选择A后,我们可以进一步选择D或E
  • 选择B后,我们可以进一步选择F或G
  • 选择C后,我们可以进一步选择H或I

回溯法会先尝试一条路径(如Root→A→D),如果发现这条路径不满足条件,就回溯到上一个节点(A),然后尝试另一条路径(Root→A→E),依此类推。

状态空间树

状态空间树是回溯法中另一种重要的可视化工具,它展示了问题的所有可能状态及其转换关系。

对于N皇后问题,状态空间树的每一层代表在棋盘的一列中放置皇后,每个节点的子节点代表在下一列的不同行中放置皇后的选择。

                    [空棋盘]/   |   \/    |    \[第1行]  [第2行]  [第3行] ... [第N行]  <- 第1列的选择/  |  \    /  |  \    /  |  \/   |   \  /   |   \  /   |   \[第1行] [第2行] [第3行]...  <- 第2列的选择(根据约束条件筛选)

在这个状态空间树中:

  • 第一层表示在第1列的N个可能位置放置皇后
  • 第二层表示在第2列的可能位置放置皇后,但这些位置必须满足不与第1列的皇后相互攻击
  • 依此类推,每一层的选择都受到之前所有选择的约束

回溯过程

以3皇后问题为例,回溯过程可以表示为:

  1. 在第1列放置皇后(尝试第1行)
  2. 在第2列放置皇后(由于第1行已被攻击,尝试第2行)
  3. 在第3列放置皇后(由于第1行和第2行已被攻击,尝试第3行)
  4. 发现无法放置所有皇后,回溯到第2步
  5. 在第2列移除皇后,尝试第3行
  6. 在第3列放置皇后(由于第1行和第3行已被攻击,尝试第2行)
  7. 找到一个解决方案

这个过程可以用以下棋盘序列来可视化:

步骤1: 在第1列第1行放置皇后
Q . .
. . .
. . .步骤2: 在第2列第2行放置皇后
Q . .
. Q .
. . .步骤3: 尝试在第3列放置皇后,但没有有效位置
(回溯到步骤2)步骤4: 移除第2列的皇后
Q . .
. . .
. . .步骤5: 在第2列第3行放置皇后
Q . .
. . .
. Q .步骤6: 在第3列第2行放置皇后
Q . .
. . Q
. Q .找到解决方案!

通过这种可视化方式,我们可以清晰地看到回溯法如何系统地探索解空间,并在遇到死胡同时如何回溯并尝试其他路径。

回溯法与其他算法的比较

算法特点适用场景典型问题时间复杂度空间复杂度
回溯法尝试所有可能的解,遇到不满足条件的解则回溯需要找到所有可能的解八皇后问题、数独、全排列指数级 O(b^d)O(d)
贪心算法每一步选择当前最优解问题具有贪心选择性质最小生成树、哈夫曼编码多项式级O(n)
动态规划将问题分解为子问题,存储子问题的解问题具有重叠子问题和最优子结构背包问题、最长公共子序列多项式级O(n^2)
分治法将问题分解为独立的子问题,合并子问题的解问题可以分解为独立的子问题归并排序、快速排序O(n log n)O(log n)
分支限界法类似回溯但使用队列而非栈,可以找到最优解求解最优化问题旅行商问题、作业调度指数级指数级

回溯法与动态规划的区别

  1. 问题类型

    • 回溯法:适用于找出所有可能解或所有满足条件的解。
    • 动态规划:适用于找出最优解。
  2. 重叠子问题

    • 回溯法:通常不处理重叠子问题,可能会重复计算。
    • 动态规划:通过记忆化存储子问题的解,避免重复计算。
  3. 搜索方式

    • 回溯法:深度优先搜索。
    • 动态规划:通常是自底向上或自顶向下的方式构建解。

回溯法与贪心算法的区别

  1. 决策方式

    • 回溯法:考虑所有可能的选择,并在需要时回溯。
    • 贪心算法:每一步都选择当前看起来最好的选择,不会回溯。
  2. 最优性

    • 回溯法:可以找到全局最优解。
    • 贪心算法:只能保证局部最优,不一定能找到全局最优解。
  3. 效率

    • 回溯法:时间复杂度通常较高,可能是指数级的。
    • 贪心算法:时间复杂度通常较低,多为多项式级别。

总结

回溯法是一种强大的算法设计技术,适用于需要探索所有可能解的问题。它通过系统地尝试所有可能的解,并在发现当前路径不可行时回溯到上一步,继续探索其他可能的路径。虽然回溯法的时间复杂度可能很高,但通过合理的剪枝策略,可以显著提高算法的效率。

回溯法的核心思想是"试探+回溯",它是解决组合优化问题、约束满足问题等的有效方法。在实际应用中,回溯法常常与其他算法技术(如动态规划、贪心算法等)结合使用,以解决更复杂的问题。

应用场景总结

  1. 组合问题:如子集和问题、组合总和问题等。
  2. 排列问题:如全排列、字符串排列等。
  3. 棋盘问题:如N皇后问题、数独问题等。
  4. 图搜索问题:如迷宫寻路、图的着色问题等。
  5. 约束满足问题:如数独、填字游戏等。

优化技巧总结

  1. 剪枝:通过各种策略减少搜索空间。
  2. 启发式搜索:优先搜索更有希望的状态。
  3. 记忆化:存储已计算过的状态结果,避免重复计算。
  4. 位运算优化:使用位运算加速状态表示和操作。
  5. 并行化:在多核环境下并行搜索不同的状态空间。

相关文章:

算法之回溯法

回溯法 回溯法定义与概念核心思想回溯法的一般框架伪代码表示C语言实现框架 回溯法的优化技巧剪枝策略实现剪枝的C语言示例记忆化搜索 案例分析N皇后问题子集和问题全排列问题寻路问题 回溯法的可视化理解决策树状态空间树回溯过程 回溯法与其他算法的比较回溯法与动态规划的区…...

Linux 内核中 cgroup(控制组) 作用是什么?

cgroup&#xff08;Control Groups&#xff09; 是 Linux 内核提供的一种机制&#xff0c;用于对 进程&#xff08;或线程&#xff09;组 进行资源限制、优先级分配、统计监控和任务控制。通过将进程分组管理&#xff0c;可以实现对 CPU、内存、磁盘 I/O、网络等系统资源的精细…...

Relay IR的核心数据结构

在 Apache TVM 的 Relay IR 中&#xff0c;基础节点&#xff08;Var、Const、Call、Function 和 Expr&#xff09;是构建计算图的核心数据结构。以下是对它们的详细解析&#xff0c;包括定义、作用、内部组成及相互关系&#xff1a; 1. Expr&#xff08;表达式基类&#xff09;…...

【MCP Node.js SDK 全栈进阶指南】初级篇(4):MCP工具开发基础

在MCP(模型上下文协议)的生态系统中,工具(Tools)是一种强大的扩展机制,允许AI模型执行各种操作并获取结果。本文将深入探讨MCP TypeScript-SDK中的工具开发基础,包括工具定义与参数验证、Zod模式详解与高级用法、异步工具处理与错误管理以及工具调用与结果格式化。通过学…...

3Blue1Brown/videos - 数学视频生成代码库

本文翻译整理自&#xff1a;https://github.com/3b1b/videos 文章目录 一、关于本项目相关链接资源关键功能特性 二、注意事项三、工作流1、核心原理2、Sublime 专用配置 四、快捷键功能说明 一、关于本项目 本项目包含用于生成 3Blue1Brown 数学解说视频的代码。 相关链接资源…...

vue3 + element-plus中el-drawer抽屉滚动条回到顶部

el-drawer抽屉滚动条回到顶部 <script setup lang"ts" name"PerformanceLogQuery"> import { ref, nextTick } from "vue"; ...... // 详情 import { performanceLogQueryByIdService } from "/api/performanceLog"; const onD…...

【inlining failed in call to always_inline ‘_mm_aesenclast_si128’】

gcc编译错误&#xff1a;inlining failed in call to always_inline ‘_mm_aesenclast_si128’: target specific option mismatch 消除方法&#xff1a; 假如是GCC&#xff0c;则CFLAGS添加如下编译选项&#xff1a;-maes 假如是cmake&#xff0c;参加如下脚本&#xff1a; …...

DB-GPT支持mcp协议配置说明

简介 在 DB-GPT 中使用 MCP&#xff08;Model Context Protocol&#xff09;协议&#xff0c;主要通过配置 MCP 服务器和智能体协作实现外部工具集成与数据交互。 开启mcp服务&#xff0c;这里以网页抓取为例 npx -y supergateway --stdio "uvx mcp-server-fetch" …...

前端之勇闯DOM关

一、DOM简介 1.1什么是DOM 文档对象类型&#xff08;Document Object Model&#xff0c;简称DOM&#xff09;&#xff0c;是W3C组织推荐的处理课扩展标记语言&#xff08;HTML或者XML&#xff09;的标准编程接口 W3C已经定义了一系列的DOM接口&#xff0c;通过这些DOM接口可…...

实现鼠标拖拽图片效果

我们需要一个图片 可以是你的女朋友 可以是男朋友 &#xff0c;我就拿窝的偶像 一个大佬——>甘为例吧&#xff01; 哈哈哈哈哈 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport&q…...

nodejs模块暴露数据的方式,和引入(导入方式)方式

在 Node.js 中&#xff0c;模块之间通过 模块导出&#xff08;exports&#xff09; 和 模块导入&#xff08;require 或 ESModule 的 import&#xff09; 来进行数据和功能的共享。下面我详细总结一下两种主要的模块系统&#xff1a; 一、CommonJS 模块&#xff08;Node.js 默认…...

AXOP33552: 400MHz 高速双通道运算放大器

AXOP33552是一款通用型高速双通道运算放大器&#xff0c;产品的工作电压为2V至5.5V&#xff0c;具有400MHz的带宽&#xff0c;f0.1dB的带宽为 120MHz&#xff0c;单通道静态电流为10mA。产品特别对噪声和THD做了优化&#xff0c;其噪声为5nV/√Hz 1MHz&#xff0c;2次谐波为-85…...

Spring Boot日志配置

目录 logback 使用logback 获取日志对象 日志级别 控制日志输出级别 日志输出格式控制 配置方式 日志转存 示例 日志是应用程序不可或缺的一部分&#xff0c;记录着程序运行的信息。主要作用有&#xff1a; 记录日常运营的重要信息记录应用报错信息记录过程数据等…...

不可变数据:基于持久化数据结构的状态管理

不可变数据:基于持久化数据结构的状态管理 一、 什么是不可变数据&#xff1f; 不可变数据是指一旦创建就无法更改的数据。在计算机科学中&#xff0c;不可变数据结构是指其内容或状态不能被修改的数据结构。在不可变数据中&#xff0c;所有修改操作都会生成新的数据副本&#…...

PyTorch卷积层填充(Padding)与步幅(Stride)详解及代码示例

本文通过具体代码示例讲解PyTorch中卷积操作的填充&#xff08;Padding&#xff09;和步幅&#xff08;Stride&#xff09;对输出形状的影响&#xff0c;帮助读者掌握卷积层的参数配置技巧。 一、填充与步幅基础 填充&#xff08;Padding&#xff09;&#xff1a;在输入数据边缘…...

C++手撕STL-其叁

Deque 今天我们进入新的容器&#xff1a;deque&#xff0c;一般叫做双端队列。 比起传统的先入先出的队列queue&#xff0c;deque的出场率显然要低得多&#xff0c;事实上deque比起queue来说最大的特点就是多了一个push_front()和pop_front()&#xff0c;其他并没有太多不同。…...

AI大模型-window系统CPU版安装anaconda以及paddle详细步骤-亲测有效

window系统CPU版安装anaconda以及paddle详细步骤-亲测有效 一 安装anaconda 下载地址:anaconda下载 下载成功后,选择非C盘安装,按提示安装即可修改镜像文件 安装成功后,运行anaconda软件,若提示更新则点击更新,更新完后,修改镜像文件 找到用户目录下的.condarc文件,覆…...

UML概览

&#x1f970;名片&#xff1a; &#x1f433;作者简介&#xff1a;乐于分享知识的大二在校生 &#x1f333;本系列专栏: (点击直达)统一建模语言UML &#x1fae3;致读者&#xff1a;欢迎评论与私信,对于博客内容的疑问都会尽量回复哒!!! 本文序&#xff1a; ⛰️本文介绍&…...

影刀填写输入框(web) 时出错: Can not convert Array to String

环境&#xff1a; 影刀5.26.24 Win10专业版 问题描述&#xff1a; [错误来源]行12: 填写输入框(web) 执行 填写输入框(web) 时出错: Can not convert Array to String. 解决方案&#xff1a; 1. 检查变量内容 在填写输入框之前&#xff0c;打印BT和NR变量的值&#xff…...

LLMs可在2位精度下保持高准确率

每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗&#xff1f;订阅我们的简报&#xff0c;深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同&#xff0c;从行业内部的深度分析和实用指南中受益。不要错过这个机会&#xff0c;成为AI领…...

C语言高频面试题——结构体和联合体区别

在 C 语言中&#xff0c;结构体&#xff08;struct&#xff09; 和 联合体&#xff08;union&#xff09; 是两种重要的复合数据类型&#xff0c;用于组织和管理多个相关的变量。尽管它们在语法上有些相似&#xff0c;但在内存布局、用途和行为上有显著的区别。以下是详细的对比…...

App爬虫工具篇-mitmproxy

mitmproxy 是一个支持 HTTP 和 HTTPS 的抓包程序,类似 Fiddler、Charles 的功能,它通过控制台的形式和ui界面的方式 此外,mitmproxy 还有两个关联组件,一个是 mitmdump,它是 mitmproxy 的命令行接口,利用它可以对接 Python 脚本,实现监听后的处理;另一个是 mitmweb,它…...

配置openjdk调试环境

先决条件 首先在Ubuntu 18.04上编译SlowDebug版本的openjdk。注意&#xff0c;这里我选择的是x86处理器的电脑。苹果M系列属于ARM芯片&#xff0c;指令集不一样。由于我在苹果上进行垃圾回收调试的时候会报SIGILL错误。为了了解JVM的内部工作原理&#xff0c;不要在这种问题上…...

加油站小程序实战教程13充值规则配置

目录 1 创建数据源2 搭建管理功能最终效果 我们目前已经实现了会员的注册以及登录功能&#xff0c;有了基础的认证之后就进入到了业务部分的开发。会员的话首先是可以进行充值&#xff0c;在充值的时候通常会有一定的赠送&#xff0c;本篇我们来开发一下充值规则的配置功能。 1…...

jQuery — 总结

介绍 jQuery是一款高效、轻量级的JavaScript库&#xff0c;旨在简化网页开发中的常见任务。自2006年发布以来&#xff0c;它凭借直观的语法和强大的功能迅速成为前端开发的标配工具。其核心设计理念是“写更少&#xff0c;做更多”&#xff0c;通过封装复杂的原生JavaScript操作…...

【信息安全工程师备考笔记】第二章 网络信息安全概述

第二章 网络攻击原理与常用方法 2.1 网络攻击概述 概念&#xff1a;损害网络 系统安全属性 的危害行为 危害行为基本类型 信息泄露攻击&#xff08;机密性&#xff09;完整性破坏攻击&#xff08;完整性&#xff09;拒绝服务攻击&#xff08;可用性&#xff09;非法使用攻击…...

国家自然科学基金答辩ppt制作案例模板下载

国家自然科学基金 National Natural Science Foundation of China 支持基础研究&#xff0c;坚持自由探索&#xff0c;发挥导向作用&#xff0c;发现和培养科学技术人才&#xff0c;促进科学技术进步和经济社会协调发展&#xff0c;逐渐形成和发展了由研究项目、人才项目和环境…...

代码随想录第三十七天|华为秋季笔试真题230823

刷题小记&#xff1a; 主要偏向扎实编码基础的考察&#xff0c;但貌似近些年题目难度有所提高&#xff0c;仅供参考。 卡码网136.获取连通的相邻节点列表&#xff08;卡码网136.获取连通的相邻节点列表&#xff09; 题目分析&#xff1a; 题目描述&#xff1a; 存在N个转发…...

KUKA机器人KR 3 D1200 HM介绍

KUKA KR 3 D1200 HM是一款小型机器人&#xff0c;型号中HM代表“Hygienic Machine&#xff08;卫生机械&#xff09;用于主副食品行业”&#xff0c;也是一款并联机器人。用于执行高速、高精度的抓取任务。这款机器人采用食品级不锈钢设计&#xff0c;额定负载为3公斤&#xff…...

从零开始创建MCP Server实战指南

一、MCP协议核心概念 1.1 什么是MCP&#xff1f; MCP&#xff08;Model Context Protocol&#xff09; 是一个标准化的“沟通规则”&#xff0c;由公司Anthropic提出&#xff0c;专门用于让大语言模型&#xff08;LLM&#xff0c;比如通义千问、ChatGPT等&#xff09;与外部工…...

C语言教程(十二):C 语言数组详解

一、引言数组的基本概念 数组是一组具有相同数据类型的元素的集合&#xff0c;这些元素在内存中连续存储。通过一个统一的数组名和下标来访问数组中的每个元素。使用数组可以方便地处理大量相同类型的数据&#xff0c;避免为每个数据单独定义变量。 二、一维数组 2.1 数组的…...

Linux[基础指令][2]

Linux[基础指令][2] cp(复制) 格式:cp [-rf] 源文件 {普通文件,目录} 拷贝 cp -r 递归拷贝目录 蓝色为目录,白色为具体文件 拷贝后面加一个不存在的文件会新建文件再拷贝 cp -ir -i是覆盖的时候询问 如果目标文件存在就会覆盖原有文件 mv(重命名/剪切) 格式:mv 源文件…...

MySQL_MCP_Server_pro接入cherry_studio实现大模型操作数据库

大模型直接与数据库交互&#xff0c;实现基本增删改查操作。首先贴下代码地址&#xff1a; https://github.com/wenb1n-dev/mysql_mcp_server_pro 安装环境&#xff1a;win10 1、下载代码 git clone https://github.com/wenb1n-dev/mysql_mcp_server_pro 2、使用conda创建…...

linux命令集

命令 grep -r --includeAndroid.bp libcfs ./ ​参数说明 选项/参数作用-r递归搜索子目录。--includeAndroid.bp仅搜索名为 Android.bp 的文件&#xff08;精确匹配文件名&#xff09;。libcfs要搜索的关键字&#xff08;单引号包裹特殊字符如 以避免被 Shell 解析&#xff…...

数据结构:链表

链表的概念及结构&#xff1a; 链表的概念&#xff1a; 链表是一种物理储存结构上非连续的储存结构&#xff0c;数据元素的逻辑顺序是通过引用链接次序实现的 那物理存储结构连续是什么意思&#xff1f; 之前我们讲过顺序表&#xff0c;顺序表的底层是数组&#xff0c;如下…...

【高并发内存池】从零到一的项目之高并发内存池整体框架设计及thread cache设计

个人主页 &#xff1a; zxctscl 专栏 【C】、 【C语言】、 【Linux】、 【数据结构】、 【算法】 如有转载请先通知 文章目录 前言1. 高并发内存池整体框架设计2. 高并发内存池--thread cache2.1 定长内存池的问题2.2 整体框架2.3 自由链表2.4 thread cache哈希桶的对齐规则2.5…...

电气动调节单座V型球阀带阀杆节流套沟槽孔板的作用-耀圣

电气动调节单座V球阀杆节流套是阀门中的一个重要组件&#xff0c;主要用于调节和控制流体介质的流量、压力或流速&#xff0c;同时兼具导向、密封和稳定阀杆运动降低流速减少冲刷的作用。以下是其具体功能和应用场景的详细说明&#xff1a; 1. 节流与流量控制** 作用原理**&am…...

vscode使用笔记

文章目录 安装快捷键 vscode是前端开发的一款利器。 安装 快捷键 ctrlp # 查找文件(和idea的双击shift不一样) ctrlshiftf # 搜索内容...

基于 SpringAI 整合 DeepSeek 模型实现 AI 聊天对话

目录 1、Ollama 的下载配置 与 DeepSeek 的本地部署流程 1.1 下载安装 Ollama 1.2 搜索模型并进行本地部署 2、基于 SpringAI 调用 Ollama 模型 2.1 基于OpenAI 的接口规范&#xff08;其他模型基本遵循&#xff09; 2.2 在 IDEA 中进行创建 SpringAI 项目并调用 DS 模型 3、基…...

Idea创建项目的搭建方式

目录 一、普通Java项目 二、普通JavaWeb项目 三、maven的JavaWeb项目 四、maven的Java项目 一、普通Java项目 1. 点击 Create New Project 2. 选择Java项目&#xff0c;选择JDK&#xff0c;点击Next 3. 输入项目名称&#xff08;驼峰式命名法&#xff09;&#xff0c;可选…...

【MATLAB第115期】基于MATLAB的多元时间序列的ARIMAX的预测模型

【MATLAB第115期】基于MATLAB的多元时间序列的ARIMAX的预测模型 ‌一、简介 ARIMAX‌&#xff08;Autoregressive Integrated Moving Average with eXogenous inputs&#xff09;模型是一种结合自回归&#xff08;AR&#xff09;、差分&#xff08;I&#xff09;、移动平均&a…...

【以太网安全】——防护高级特性配置总结

目前网络中以太网技术的应用非常广泛、然后、各种网络攻击的纯在&#xff08;例如针对ARP DHCP 等攻击&#xff09;不仅造成了网络合法用户无法正常访问网络资源、而且对网络信息安全构成严重威胁、以下配置是对局域网安全配置命令做详解 主要的安全威胁 MAC攻击:泛洪、欺骗 …...

微信小程序 van-dropdown-menu

点击其他按钮&#xff0c;关闭van-dropdown-menu下拉框 DropdownMenu 引入页面使用index.wxmlindex.scssindex.ts(重点)index.ts(全部) DropdownMenu 引入 在app.json或index.json中引入组件 "usingComponents": {"van-dropdown-menu": "vant/weapp…...

再见 Smartdaili,你好 Decodo!

我们将翻开新的篇章&#xff0c;推出新的名称以及更好的代理和刮擦解决方案。了解我们如何帮助全球用户构建、测试和扩展他们的公共网络数据项目。 Smartproxy&#xff0c;即后来的Smartdaili&#xff0c;由一个行业专业人士和企业家团队于2018年创立&#xff0c;其使命是创建一…...

海量文本中的词语距离:在 O(n) 时间内找到最近的词对

想象一个巨大的日志文件、一部鸿篇巨著或者网络爬虫抓取的数据——它们可能达到 TB 级别。现在&#xff0c;假设你需要找出两个特定的词&#xff08;比如 词语1​ 和 词语2​&#xff09;在这段庞大文本中出现时&#xff0c;彼此“靠得最近”的距离是多少。 挑战&#xff1a; …...

TextCNN 模型文本分类实战:深度学习在自然语言处理中的应用

在自然语言处理&#xff08;NLP&#xff09;领域&#xff0c;文本分类是研究最多且应用最广泛的任务之一。从情感分析到主题识别&#xff0c;文本分类技术在众多场景中都发挥着重要作用。最近&#xff0c;我参与了一次基于 TextCNN 模型的文本分类实验&#xff0c;从数据准备到…...

前台调用接口的方式及速率对比

一、引言 在现代 Web 开发中&#xff0c;前台与后台的数据交互至关重要&#xff0c;而调用接口是实现这一交互的关键手段。不同的接口调用方式在速率上可能存在差异&#xff0c;这会影响用户体验和应用性能。本文将详细介绍几种常见的前台调用接口方式&#xff0c;并对它们的速…...

高级java每日一道面试题-2025年4月21日-基础篇[反射篇]-如何使用反射获取一个类的所有方法?

如果有遗漏,评论区告诉我进行补充 面试官: 如何使用反射获取一个类的所有方法&#xff1f; 我回答: 在Java中&#xff0c;反射是一种强大的机制&#xff0c;允许程序在运行时检查或“反射”自身&#xff0c;从而动态地操作类、字段、方法和构造函数等。这在需要动态调用方法…...

tomcat集成redis实现共享session

中间件&#xff1a;Tomcat、Redis、Nginx jar包要和tomcat相匹配 jar包&#xff1a;commons-pool2-2.2.jar、jedis-2.5.2.jar、tomcat-redis-session-manage-tomcat7.jar 配置Tomcat /conf/context.xml <?xml version1.0 encodingutf-8?> <!--Licensed to the A…...

2.6 递归

递归 特性&#xff1a; >.一递一归 >.终止条件 一般为&#xff1a;0 1 -1 #测试函数的返回值为函数 def test_recursion():return test_recursion() print(test_recursion()) RecursionError: maximum recursion depth exceeded #案例&#xff1a;计算 …...