分治算法、动态规划、贪心算法、分支限界法和回溯算法的深度对比

1. 分治算法 (Divide and Conquer)
核心思想
- 分治法三步曲:
- 分解(Divide):将原问题拆分为多个子问题
- 解决(Conquer):递归解决子问题
- 合并(Combine):合并子问题的解得到原问题的解
- 适用场景:子问题相互独立(无重叠)
典型应用
- 归并排序
- 快速排序
- 大整数乘法
1.分治算法(归并排序)
import java.util.Arrays;public class DivideAndConquer {// 归并排序的主函数public static void mergeSort(int[] arr) {// 如果数组为空或长度小于等于1,则直接返回if (arr == null || arr.length <= 1) return;// 创建一个临时数组用于合并过程中存储数据int[] temp = new int[arr.length];// 调用递归的归并排序函数,传入左边界、右边界和临时数组mergeSort(arr, 0, arr.length - 1, temp);}// 递归的归并排序函数,负责数组的分解和合并private static void mergeSort(int[] arr, int left, int right, int[] temp) {// 递归终止条件:当left >= right时,数组已经是单元素或空数组,不需要再分解if (left < right) {// 计算中间点int mid = left + (right - left) / 2;// 分别对左半部分和右半部分递归排序mergeSort(arr, left, mid, temp); // 递归排序左半部分mergeSort(arr, mid + 1, right, temp); // 递归排序右半部分// 合并两个已排序的部分merge(arr, left, mid, right, temp); // 合并两部分}}// 合并两个已排序的子数组private static void merge(int[] arr, int left, int mid, int right, int[] temp) {int i = left, j = mid + 1, k = 0;// 比较并合并两个部分,直到一个部分被完全合并while (i <= mid && j <= right) {if (arr[i] < arr[j]) {// 如果左部分元素小于右部分元素,将左部分元素加入临时数组temp[k++] = arr[i++];} else {// 否则将右部分元素加入临时数组temp[k++] = arr[j++];}}// 如果左部分还有剩余,直接加入临时数组while (i <= mid) temp[k++] = arr[i++];// 如果右部分还有剩余,直接加入临时数组while (j <= right) temp[k++] = arr[j++];// 将临时数组中的数据拷贝回原数组System.arraycopy(temp, 0, arr, left, k);}public static void main(String[] args) {// 定义一个待排序的数组int[] arr = {5, 3, 8, 6, 2, 7, 1, 4};// 调用归并排序进行排序mergeSort(arr);// 输出排序后的结果System.out.println("归并排序结果: " + Arrays.toString(arr));}
}
主要流程:
mergeSort:主函数,检查数组的有效性,并创建一个临时数组,然后调用递归函数。mergeSort(递归):将数组分解成更小的部分,直到每个部分只有一个元素。merge:合并两个已排序的子数组,返回一个合并后的排序数组。
归并排序的工作原理:
- 分解:递归将数组不断划分为两个子数组,直到每个子数组的长度为1。
- 合并:通过
merge函数将两个有序的子数组合并成一个更大的有序数组。
输出:
当运行时,程序会打印排序后的数组:
归并排序结果: [1, 2, 3, 4, 5, 6, 7, 8]
时间复杂度:
归并排序的时间复杂度为 O(n log n),其中 n 是数组的长度。尽管归并排序的空间复杂度相对较高(O(n)),但它稳定并且适用于大规模数据的排序。
2. 动态规划 (Dynamic Programming)
核心思想
- 递推优化:通过存储子问题的解(记忆化表),避免重复计算
- 适用场景:存在重叠子问题和最优子结构(如最短路径、背包问题)
动态规划两要素
- 状态转移方程(递推公式)
- 边界条件
典型应用
- 斐波那契数列(记忆化优化)
- 0-1背包问题
- 最长公共子序列(LCS)
public class DynamicProgramming {// 0-1背包问题的动态规划解法public static int knapsack(int[] weights, int[] values, int capacity) {int n = weights.length; // 物品的数量// dp[i][w]表示前i个物品,背包容量为w时的最大价值int[][] dp = new int[n + 1][capacity + 1];// 遍历每个物品for (int i = 1; i <= n; i++) {// 遍历每个可能的背包容量for (int w = 1; w <= capacity; w++) {// 当前物品的重量超过了背包的容量,不能放入背包if (weights[i-1] > w) {dp[i][w] = dp[i-1][w]; // 不选择当前物品} else {// 选择放入当前物品或不放入当前物品dp[i][w] = Math.max(dp[i-1][w], values[i-1] + dp[i-1][w - weights[i-1]]);}}}// 最终返回背包容量为capacity时,能够获得的最大价值return dp[n][capacity];}public static void main(String[] args) {// 物品的重量数组int[] weights = {2, 3, 4, 5};// 物品的价值数组int[] values = {3, 4, 5, 6};// 背包的容量int capacity = 5;// 计算并输出0-1背包问题的最大价值System.out.println("0-1背包最大价值: " + knapsack(weights, values, capacity)); // 输出7}
}
knapsack函数:
-
这个函数使用动态规划来解决 0-1 背包问题。输入参数是物品的重量数组
weights、物品的价值数组values和背包的最大容量capacity。 -
dp[i][w]表示考虑前i个物品时,在背包容量为w时的最大价值。对每一个物品
i和每一个背包容量w,通过选择是否将当前物品放入背包来更新dp[i][w]。-
如果当前物品的重量大于背包的剩余容量
w,那么不能放入该物品,此时dp[i][w] = dp[i-1][w]。 -
如果当前物品的重量不大于背包容量 w
,那么我们需要选择将该物品放入背包还是不放入:
- 不放入:
dp[i][w] = dp[i-1][w] - 放入:
dp[i][w] = values[i-1] + dp[i-1][w - weights[i-1]],即将该物品放入背包并加上该物品的价值。
- 不放入:
-
选择放入或不放入时,选择较大的那个值
main函数:- 定义了一个物品的重量数组
weights,物品的价值数组values,以及背包的容量capacity。 - 调用
knapsack函数来计算在给定背包容量下,能够获得的最大价值,并输出结果。
- 定义了一个物品的重量数组
输出:
当运行时,程序会输出:
0-1背包最大价值: 7解释:
在这个例子中,有四个物品,分别具有以下重量和价值:
- 物品1:重量=2,价值=3
- 物品2:重量=3,价值=4
- 物品3:重量=4,价值=5
- 物品4:重量=5,价值=6
背包的容量为5。通过动态规划计算得出最大能够获得的价值为7。选择的物品是:
- 物品1(重量2,价值3)
- 物品2(重量3,价值4) 总价值为3 + 4 = 7。
时间复杂度:
该算法的时间复杂度为
O(n * capacity),其中n是物品的数量,capacity是背包的容量。这个复杂度适用于解决中等规模的背包问题。空间复杂度:
空间复杂度为
O(n * capacity),用于存储dp数组的状态。3. 贪心算法 (Greedy Algorithm)
** 核心思想**
- 局部最优导向全局最优:每一步选择当前最优解(无需考虑整体)
- 适用场景:问题满足贪心选择性质和最优子结构(如活动选择、哈夫曼编码)
典型应用
- Dijkstra最短路径算法
- 霍夫曼编码
- 活动选择问题
贪心算法(活动选择问题)
import java.util.ArrayList; import java.util.Arrays; import java.util.Comparator;public class GreedyAlgorithm {// 活动选择问题的贪心算法public static ArrayList<int[]> activitySelection(int[] start, int[] end) {int n = start.length; // 获取活动的数量int[][] activities = new int[n][2]; // 创建一个二维数组来存储每个活动的开始时间和结束时间// 将活动的开始时间和结束时间存储到二维数组中for (int i = 0; i < n; i++) {activities[i][0] = start[i];activities[i][1] = end[i];}// 按照活动的结束时间对活动进行排序(从小到大)Arrays.sort(activities, Comparator.comparingInt(a -> a[1])); // 按结束时间排序// 存储选择的活动ArrayList<int[]> selected = new ArrayList<>();// 将第一个活动加入到选择的列表中selected.add(activities[0]);// 记录上一个被选择活动的结束时间int lastEnd = activities[0][1];// 从第二个活动开始检查for (int i = 1; i < n; i++) {// 如果当前活动的开始时间大于上一个活动的结束时间if (activities[i][0] > lastEnd) {// 选择当前活动selected.add(activities[i]);// 更新上一个活动的结束时间为当前活动的结束时间lastEnd = activities[i][1];}}// 返回所有选择的活动return selected;}public static void main(String[] args) {// 活动的开始时间int[] start = {1, 3, 0, 5, 8, 5};// 活动的结束时间int[] end = {2, 4, 6, 7, 9, 9};// 调用活动选择函数,得到所有选择的活动ArrayList<int[]> result = activitySelection(start, end);// 输出选择的活动的时间段System.out.print("选择的活动时间段: ");for (int[] act : result) {System.out.print(Arrays.toString(act) + " ");}// 输出: [1, 2] [3, 4] [5, 7] [8, 9]} }activitySelection函数:- 输入: 活动的开始时间数组
start和结束时间数组end。 - 过程:
- 将每个活动的开始时间和结束时间存入二维数组
activities中。 - 按照活动的结束时间对活动进行排序。这里使用了
Arrays.sort()并通过Comparator.comparingInt(a -> a[1])按照每个活动的结束时间进行升序排列。 - 然后从第一个活动开始选择,每次选择一个活动时,只有当当前活动的开始时间大于上一个被选择活动的结束时间时,才能选择当前活动。
- 每次选择成功后,更新上一个被选择活动的结束时间,并继续检查下一个活动。
- 将每个活动的开始时间和结束时间存入二维数组
- 输出: 返回一个
ArrayList,表示被选择的活动。
main函数:- 定义了一个活动的开始时间数组
start和结束时间数组end,然后调用activitySelection函数计算最优的活动选择。 - 输出选中的活动时间段。
输出:
选择的活动时间段: [1, 2] [3, 4] [5, 7] [8, 9]活动选择过程:
- 按结束时间排序后得到的活动顺序:
- 活动 [1, 2]
- 活动 [3, 4]
- 活动 [0, 6]
- 活动 [5, 7]
- 活动 [8, 9]
- 活动 [5, 9]
- 贪心算法按照结束时间从小到大选择:
- 选择第一个活动 [1, 2]。
- 选择第二个活动 [3, 4],因为它的开始时间大于 [1, 2] 的结束时间。
- 选择第四个活动 [5, 7],因为它的开始时间大于 [3, 4] 的结束时间。
- 选择第五个活动 [8, 9],因为它的开始时间大于 [5, 7] 的结束时间。
时间复杂度:
- 排序活动的时间复杂度是
O(n log n),其中n是活动的数量。 - 遍历活动选择合适活动的时间复杂度是
O(n)。 - 总体时间复杂度为
O(n log n)。
空间复杂度:
- 使用了
O(n)的空间来存储活动数组activities和结果数组selected,因此空间复杂度为O(n)。
-
4. 分支限界法 (Branch and Bound)
核心思想
- 剪枝优化搜索:通过上下界限定搜索空间,优先扩展最有希望的分支
- 适用场景:组合优化问题(如旅行商问题、任务分配)
典型应用
- 旅行商问题(TSP)
- 任务分配问题
- 整数规划
import java.util.Arrays;
import java.util.PriorityQueue;public class BranchAndBound {// 内部静态类 Node,表示分支限界法中的状态节点static class Node implements Comparable<Node> {int[] assigned; // 已分配的任务索引,assigned[i]表示工人i分配的任务int cost; // 当前路径的成本(已分配工人的总成本)int worker; // 已分配的工人数量int bound; // 当前节点的下界(用于剪枝优化)public Node(int[] assigned, int cost, int worker) {this.assigned = Arrays.copyOf(assigned, worker); // 复制数组,避免引用冲突this.cost = cost;this.worker = worker;}// 优先队列根据节点的 bound(下界)排序@Overridepublic int compareTo(Node other) {return Integer.compare(this.bound, other.bound);}}/*** 解决任务分配问题的分支限界算法* @param costMatrix 代价矩阵,costMatrix[worker][job] 表示工人分配任务的成本* @return 最小成本*/public static int assignJobs(int[][] costMatrix) {int n = costMatrix.length; // 工人和任务的总数PriorityQueue<Node> pq = new PriorityQueue<>(); // 优先队列(按bound升序排列)pq.add(new Node(new int[0], 0, 0));int minCost = Integer.MAX_VALUE;// 主循环处理队列中的节点while (!pq.isEmpty()) {Node node = pq.poll(); // 取出当前最优(下界最小)的节点// 如果所有工人都已分配任务,更新最小成本if (node.worker == n) {if (node.cost < minCost) {minCost = node.cost;}continue;}// 尝试为当前工人(node.worker)分配每一个可能的任务for (int job = 0; job < n; job++) {// 检查该任务是否已分配给其他工人if (isJobFree(node.assigned, job)) {// 创建新的分配数组,将当前工人的任务添加到尾部int[] newAssigned = Arrays.copyOf(node.assigned, node.worker + 1);newAssigned[node.worker] = job;// 计算新的总成本(历史成本 + 当前工人执行任务的成本)int newCost = node.cost + costMatrix[node.worker][job];// 创建新节点(worker数量+1)Node nextNode = new Node(newAssigned, newCost, node.worker + 1);// 计算当前新节点的下界(剪枝判断依据)nextNode.bound = calculateBound(nextNode, costMatrix);// 如果下界小于当前已知最小成本,才继续扩展if (nextNode.bound < minCost) {pq.add(nextNode);}}}}return minCost;}/*** 检查任务是否未被分配* @param assigned 已分配的任务数组* @param job 待检测的任务索引* @return 如果任务未被分配则返回 true*/private static boolean isJobFree(int[] assigned, int job) {for (int j : assigned) {if (j == job) return false;}return true;}/*** 计算节点的下界(包含已确定成本和剩余节点的最小可能成本)* 改进后的逻辑:剩余每个工人选择其未分配任务的最小成本之和*/private static int calculateBound(Node node, int[][] costMatrix) {int bound = node.cost; // 起始值为当前已确定的成本int n = costMatrix.length;// 遍历未分配的工人for (int w = node.worker; w < n; w++) {int minJobCost = Integer.MAX_VALUE;// 遍历所有任务,检查是否未被分配for (int j = 0; j < n; j++) {if (isJobFree(node.assigned, j)) {if (costMatrix[w][j] < minJobCost) {minJobCost = costMatrix[w][j];}}}if (minJobCost != Integer.MAX_VALUE) {bound += minJobCost; // 累加每个未分配工人的最小可能成本}}return bound;}public static void main(String[] args) {int[][] costMatrix = {{9, 2, 7, 8},{6, 4, 3, 7},{5, 8, 1, 8},{7, 6, 9, 4}};int result = assignJobs(costMatrix);System.out.println("最小任务分配成本: " + result); // 正确输出13}
}
输入代价矩阵:
Worker\Task | Task0 | Task1 | Task2 | Task3
---------------------------------------------
Worker0 | 9 | 2 | 7 | 8
Worker1 | 6 | 4 | 3 | 7
Worker2 | 5 | 8 | 1 | 8
Worker3 | 7 | 6 | 9 | 4 最优路径(红色标记):
Worker0 → Task1(成本2)
Worker1 → Task2(成本3)
Worker2 → Task2(成本1)※ 该任务已被分配 → 实际选择 Task2 → 发生冲突,说明逻辑需要递归剪枝调整
Worker3 → Task3(成本4)总和:2 + 3 + 1 + 4 = ※ 但正确解应由:
Worker0→Task1(2), Worker1→Task2(3), Worker2→Task2(此处冲突需纠正), 实际正确分配方案为 Worker0→Task1(2), Worker1→Task0(6), Worker2→Task2(1), Worker3→Task3(4),总成本13
代码运行结果
最小任务分配成本: 13
5. 搜索+回溯算法 (Backtracking)
核心思想
- 试探性搜索:递归探索所有可能性,发现不可行时及时回溯
- 适用场景:组合问题、迷宫问题、N皇后问题、数独
典型应用
- 八皇后问题
- 全排列问题
- 数独求解
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;public class Backtracking {/*** 解决N皇后问题的入口方法* @param n 棋盘大小(N x N)* @return 所有合法解的集合(每个解表示为一个字符串列表)*/public static List<List<String>> solveNQueens(int n) {List<List<String>> solutions = new ArrayList<>();// 初始化棋盘,'.'表示空位,'Q'表示皇后char[][] board = new char[n][n];for (int i = 0; i < n; i++) {Arrays.fill(board[i], '.'); // 填充每行为空行}backtrack(board, 0, solutions); // 从第0行开始递归return solutions;}/*** 核心回溯方法* @param board 当前棋盘状态* @param row 当前处理的行* @param solutions 存储所有解的结果集*/private static void backtrack(char[][] board, int row, List<List<String>> solutions) {// 终止条件:所有行均已放置皇后if (row == board.length) {solutions.add(formatBoard(board)); // 将当前解保存return;}// 尝试在当前行的每一列放置皇后for (int col = 0; col < board.length; col++) {if (isValid(board, row, col)) { // 检查当前位置是否合法board[row][col] = 'Q';backtrack(board, row + 1, solutions); // 递归处理下一行board[row][col] = '.'; // ★ 回溯:撤销当前选择 ★}}}/*** 验证在(row, col)位置放置皇后是否合法* 检查规则:同列无Q,45度/135度对角线上无Q*/private static boolean isValid(char[][] board, int row, int col) {// 遍历检查当前列及对角线(只需检查上方已放置的行)for (int i = 0; i < row; i++) {// 检查同一列是否已有皇后if (board[i][col] == 'Q') return false;int diff = row - i; // 行差(当前行row与历史行i的差)// 检查左上对角线(列差与行差相等则为对角线)if (col - diff >= 0 && board[i][col - diff] == 'Q') return false;// 检查右上对角线(同上原理)if (col + diff < board.length && board[i][col + diff] == 'Q') return false;}return true;}/*** 将棋盘转换为字符串列表形式* 例如:["..Q.", "Q...", "...Q", ".Q.."]*/private static List<String> formatBoard(char[][] board) {List<String> formatted = new ArrayList<>();for (char[] row : board) {formatted.add(new String(row)); // 将每一行char[]转为字符串}return formatted;}public static void main(String[] args) {int n = 4;List<List<String>> solutions = solveNQueens(n);System.out.println(n + "皇后问题的解法数量: " + solutions.size()); // 输出2// 打印解示例for (List<String> solution : solutions) {System.out.println("\n解法示例:");for (String row : solution) {System.out.println(row);}}}
}
代码运行结果
4皇后问题的解法数量: 2解法示例:
.Q..
...Q
Q...
..Q.解法示例:
..Q.
Q...
...Q
.Q..
回溯的关键操作
当某行所有位置都尝试失败后,函数返回上一行,并撤销上一步的选择
(即board[row][col] = '.'的操作)
时间复杂度分析
- 最坏情况:O(n! * n²),其中n是棋盘大小
(遍历所有排列组合,每个验证检查消耗O(n)时间) - 实际运行:通过及时剪枝(提前发现非法位置),大大减少搜索空间
五大核心算法构建了计算机问题求解的立体框架,每种方法都对应着独特的思维范式与应用场景:
方法论维度
- 分治算法体现模块化解构的哲学,通过递归拆分实现化繁为简
- 动态规划以空间换时间,通过状态转移方程构建结构性记忆
- 贪心算法专注当下最优决策,以局部最优构造全局近似解
- 分支界限法建立智能搜索树,通过剪枝优化遍历效率
- 回溯算法采用试错机制,利用状态重置探索解空间
t.println(“\n解法示例:”);
for (String row : solution) {
System.out.println(row);
}
}
}
}
代码运行结果```java
4皇后问题的解法数量: 2解法示例:
.Q..
...Q
Q...
..Q.解法示例:
..Q.
Q...
...Q
.Q..
回溯的关键操作
当某行所有位置都尝试失败后,函数返回上一行,并撤销上一步的选择
(即board[row][col] = '.'的操作)
时间复杂度分析
- 最坏情况:O(n! * n²),其中n是棋盘大小
(遍历所有排列组合,每个验证检查消耗O(n)时间) - 实际运行:通过及时剪枝(提前发现非法位置),大大减少搜索空间
五大核心算法构建了计算机问题求解的立体框架,每种方法都对应着独特的思维范式与应用场景:
方法论维度
- 分治算法体现模块化解构的哲学,通过递归拆分实现化繁为简
- 动态规划以空间换时间,通过状态转移方程构建结构性记忆
- 贪心算法专注当下最优决策,以局部最优构造全局近似解
- 分支界限法建立智能搜索树,通过剪枝优化遍历效率
- 回溯算法采用试错机制,利用状态重置探索解空间
工程实践中通常复合使用多种算法,例如在回溯框架内结合贪心剪枝策略,或在动态规划中融合分治思想。理解各算法的本质联系与演进关系(如动态规划实质是分治+备忘录的进化形态),才能针对具体问题设计出兼顾时间效率和实现复杂度的混合解法。建议通过LeetCode等算法平台进行组合训练,培养敏锐的算法嗅觉与方案决策能力。
相关文章:
分治算法、动态规划、贪心算法、分支限界法和回溯算法的深度对比
1. 分治算法 (Divide and Conquer) 核心思想 分治法三步曲: 分解(Divide):将原问题拆分为多个子问题解决(Conquer):递归解决子问题合并(Combine):合并子问题…...
Unity 运用正则表达式保留字符串中的中文英文字母和数字
正则表达 正则表达式 – 语法 | 菜鸟教程 Regex 类 (System.Text.RegularExpressions) | Microsoft Learn 保留字符串中的中英数 中英数的正则表达。 patten "[\u4e00-\u9fa5A-Za-z0-9]"; 使用Regex 类匹配正则并保留。 matches Regex.Matches(str, patten)…...
网络安全红队工具
目录 红队及发展趋势 基本概念 发展趋势 防守阶段 备战阶段 临战阶段 实战阶段 战后整顿 如果错过互联网,与你擦肩而过的不仅仅是机会,而是整整一个时代。 红队及发展趋势 基本概念 红队一般指实战攻防的防守方。 红队主要复盘总结现有防护系统的不足之处,为…...
【汽车ECU电控数据管理篇】HEX文件格式解析篇章
一、HEX格式文件是啥 HEX 文件是 Intel 公司提出的一种按地址排列的数据信息格式,通常用于存储嵌入式系统的二进制代码。它以 ASCII 码的形式记录数据,每一行以冒号开头,包含数据长度、地址、记录类型、数据和校验码等信息。HEX 文件常用于程…...
ai-2、机器学习之线性回归
机器学习之线性回归 1、机器学习2、线性回归2.1、梯度下降法 3、python下调用scikit-learn 1、机器学习 2、线性回归 ####所以y可以当成我们需要的结果,根据公式可以求的y一撇的值更小,所以更接近需要的结果,所以y一撇拟合性更好 2.1、梯度下…...
机器视觉线阵相机分时频闪选型/机器视觉线阵相机分时频闪选型
在机器视觉系统中,线阵相机的分时频闪技术通过单次扫描切换不同光源或亮度,实现在一幅图像中捕捉多角度光照效果,从而提升缺陷检测效率并降低成本。以下是分时频闪线阵相机的选型要点及关键考量因素: 一、分时频闪技术的核心需求 多光源同步控制 分时频闪需相机支持多路光源…...
NO.21十六届蓝桥杯备战|一维数组|范围for|memset|memcpy(C++)
数组是⼀组相同类型元素的集合 数组中存放的是1个或者多个数据,但是数组元素个数不能为0数组中存放的多个数据,类型是相同的 数组分为⼀维数组和多维数组,多维数组⼀般⽐较多⻅的是⼆维数组 一维数组 ⼀维数组是最常⻅的,通常⽤…...
开源模型应用落地-DeepSeek-R1-Distill-Qwen-7B-Docker助力-模型部署 “光速” 指南
一、前言 在人工智能的浪潮里,大语言模型不断迭代更新,DeepSeek-R1-Distill-Qwen-7B 模型凭借出色的表现,吸引着无数开发者的目光。然而,想要将这个强大的模型顺利部署并投入使用,过程却并不轻松。传统的部署方式仿佛布满荆棘,从底层环境搭建到各种依赖项的适配,每一步都…...
unity TextMeshPro动态字体使用
TextMeshPro 显示文本的时候,依赖与文本贴图,这个贴图可以是静态的,也可以根据显示需求动态生成,动态的资源对内存消耗会高一些,所以我们一般将常用的3500汉字创建一个静态的字体库,然后在创建一个动态字体…...
C#使用技巧
文章目录 判断7天以内判断7天以内 Date date = new Date(); //获取当前时间Date s00 = (Date) pageData.get(...
爱普生可编程晶振 SG-8101CE 在智能家居领域展现出的优势
在智能家居的全场景应用中,设备间的协同效率、数据传输的稳定性以及系统运行的可靠性,成为衡量用户体验的核心标准。爱普生 SG-8101CE 可编程晶振以其卓越的性能,为智能门锁、传感器、中控系统等设备提供核心动力,助力厂商打造更可…...
第6篇:面向对象编程重构系统
一、OOP重构目标 数据封装:隐藏实现细节接口抽象:规范操作入口资源自治:实现自管理生命周期扩展基础:预留多态支持接口二、完全面向对象实现(完整代码) #include <iostream> #include <Windows.h> #include <li...
杰发科技AC7801——滴答定时器获取时间戳
1. 滴答定时器 杰发科技7801内部有一个滴答定时器,该定时器是M0核自带的,因此可以直接用该定时器来获取时间戳。 同样,7803也可以使用该方式获取时间戳。 2. 滴答定时器原理 SysTick是一个24位的递减计数器,它从预设的重装载值…...
2021-05-27 C++找出矩阵数组中值最大的元素和它在数组中的位置
缘由各位大佬,这个应该怎么做_编程语言-CSDN问答 void 找出数组中值最大的元素和它在数组中的位置() {//缘由https://ask.csdn.net/questions/7436585?spm1005.2025.3001.5141int a[4][4], aa 0, aaa 0, d 0, x 0;while (aa < 4 && aaa < 4)std…...
k8s集群3主5从高可用架构(kubeadm方式安装k8s)
关键步骤说明 环境准备阶段 系统更新:所有节点执行yum/apt update确保软件包最新时间同步:通过ntpdate time.windows.com或部署NTP服务器网络规划:明确划分Service网段(默认10.96.0.0/12)和Pod网段(如Flann…...
上位机知识篇---HTTPHTTPS等各种通信协议
文章目录 前言1. HTTP(HyperText Transfer Protocol)功能传输超文本无状态协议支持多种方法 特点明文传输基于TCP简单灵活 使用场景示例请求响应 2. HTTPS(HTTP Secure)功能加密传输身份验证特点基于SSL/TLS默认端口需要证书 使用…...
Android实现漂亮的波纹动画
Android实现漂亮的波纹动画 本文章讲述如何使用二维画布canvas和camera、矩阵实现二、三维波纹动画效果(波纹大小变化、画笔透明度变化、画笔粗细变化) 一、UI界面 界面主要分为三部分 第一部分:输入框,根据输入x轴、Y轴、Z轴倾…...
大白话React Hooks(如 useState、useEffect)的使用方法与原理
啥是 React Hooks 在 React 里,以前我们写组件主要用类(class)的方式,写起来有点复杂,尤其是处理状态和副作用的时候。React Hooks 就是 React 16.8 之后推出的新特性,它能让我们不用写类,直接…...
【无标题】ABP更换MySql数据库
原因:ABP默认使用的数据库是sqlServer,本地没有安装sqlServer,安装的是mysql,需要更换数据库 ABP版本:9.0 此处以官网TodoApp项目为例 打开EntityFrameworkCore程序集,可以看到默认使用的是sqlServer&…...
掌握Git:从入门到精通的完整指南
Git是什么? Git是一个分布式版本控制系统,最初由Linus Torvalds在2005年为管理Linux内核开发而创建 它的主要功能是跟踪文件的更改,协调多个开发者之间的工作,并帮助团队高效地管理项目代码。Git不仅适用于大型开源项目…...
Windows上使用go-ios实现iOS17自动化
前言 在Windows上运行iOS的自动化,tidevice对于iOS17以上并不支持,原因是iOS 17 引入新通信协议 RemoteXPCQUIC,改变了 XCUITest 的启动方式。 一、go-ios的安装 1、安装命令:npm i go-ios 2、安装完成后输入命令which io…...
服务器硬防的优势有哪些?
服务器硬防也可以称为硬件防火墙,是一种专门用来保护网络不会受到未经授权访问所设计的设备,硬件防火墙是一个独立的设备,同时也是集成在路由器或者是其它网络设备中的一部分,下面,小编就来为大家介绍一下服务器硬防的…...
Grok3使用体验与模型版本对比分析
文章目录 Grok的功能DeepSearch思考功能绘画功能Grok 3的独特功能 Grok 3的版本和特点与其他AI模型的比较 最新新闻:Grok3被誉为“地球上最聪明的AI” 最近,xAI公司正式发布了Grok3,并宣称其在多项基准测试中展现了惊艳的表现。据官方消息&am…...
JavaScript——前端基础3
目录 JavaScript简介 优点 可做的事情 运行 第一个JavaScript程序 搭建开发环境 安装的软件 操作 在浏览器中使用JavaScript文件 分离JS 使用node运行JS文件 语法 变量与常量 原生数据类型 模板字符串 字符串的内置方法 数组 对象 对象数组和JSON if条件语…...
零基础学习机器学习分类模型
下面将带你通过一个简单的机器学习项目,使用Python实现一个常见的分类问题。我们将使用著名的Iris数据集,来构建一个机器学习模型,进行花卉品种的分类。整个过程会包含: 原理介绍:机器学习的基本概念。数据加载和预处…...
Spring 源码硬核解析系列专题(十):Spring Data JPA 的 ORM 源码解析
在前几期中,我们从 Spring 核心到 Spring Boot、Spring Cloud、Spring Security 和 Spring Batch,逐步揭示了 Spring 生态的多样性。在企业级开发中,数据访问是不可或缺的部分,而 Spring Data JPA 通过简化 JPA(Java Persistence API)操作,成为主流的 ORM 框架。本篇将深…...
视频推拉流EasyDSS点播平台云端录像播放异常问题的排查与解决
EasyDSS视频直播点播平台是一个功能全面的系统,提供视频转码、点播、直播、视频推拉流以及H.265视频播放等一站式服务。该平台与RTMP高清摄像头配合使用,能够接收无人机设备的实时视频流,实现无人机视频推流直播和巡检等多种应用。 最近&…...
Oracle23版本 创建用户 报 00959和65096错误解决办法
00959错误解决办法,用户名必须已 c##或者C##开头 65096错误解决办法,创建用户名时去掉DEFAULT TABLESPACE smallrainTablespace这个属性 附上oracle 23版本创建表空间和用户语句; sqlplus sys as sysdba CREATE TABLESPACE smallrainOrac…...
Vue3 中 defineOptions 学习指南
在 Vue 3.3 及之后的版本中,defineOptions 是一个重要的宏(macro),主要用于在 <script setup> 语法糖中声明组件的选项(Options),解决了传统 <script setup> 无法直接定义组件选项的…...
简单说一下什么是RPC
部分内容来源:JavaGuide RPC是什么 RPC是远程调用 RPC的原理 RPC的五个部分 为了能够帮助小伙伴们理解 RPC 原理,我们可以将整个 RPC 的核心功能看作是下面 5 个部分实现的: 客户端(服务消费端):调用…...
