算法学习笔记:回溯法

        回溯法有“通用的解题法”之称。用它可以系统地搜索一个问题的所有解或任一解。回溯法是一个既带有系统性又带有跳跃性的搜索算法。它在包含问题的所有解的解空间树中,按照深度优先的策略,从根节点出发搜索解空间树。算法搜索至解空间树的任一节点时,总是先判断该节点是否肯定不包含问题的解。如果肯定不包含,则跳过对已节点为根后续搜索,逐层向其祖先节点回溯。否则,进入该子树,继续按深度优先的策略进行搜索。回溯法在用来求问题的所有解时,要回溯到根,且根节点的所有子树都已被搜索遍结束。而回溯法在用来求问题的任一解时,只要搜索到问题的一个解就可结束。这种以深度优先的方式系统地搜索问题的解的算法称为回溯法,它适用于解一些组合数较大的问题。

        许多复杂的,规模较大的问题都可以使用回溯法,它是早期的人工智能里使用的算法,借助计算机强大的计算能力帮助我们找到问题的解。

        回溯算法在树和图中有较多的应用,对树形或者图形结构执行一次深度优先遍历,实际上类似枚举的搜索尝试过程,在遍历的过程中寻找问题的解。

        用回溯法解决的问题的所有选项可以形象地用树状结构表示。在某一步有n个可能的选项,那么该步骤可以看成是树状结构中的一个节点,每个选项看成树中节点连接线,经过这些连接线到达该节点的n个子节点。树的叶节点对应着终结状态。如果在叶节点的状态满足题目的约束条件,那么我们找到了一个可行的解决方案。

        如果在叶子节点的状态不满足约束条件,那么只好回溯到它的上一个节点再尝试其他的选项。如果上一个节点所有可能的选项都已经试过,并且不能到达满足约束条件的终结状态,则再次回溯到上一个节点。如果所有节点的所有选项都已经尝试过仍然不能到达满足约束条件的终结状态,则该问题无解。

力扣46、全排列(中等)

        给定一个不含重复数字的数组nums,输出其所有可能的全排列。你可以按任意顺序输出答案。

void Show(int* arr, int len)
{for (int i = 0; i < len; i++)printf("%d ", arr[i]);printf("\n");
}void Swap(int* p1, int* p2)
{int tmp = *p1;*p1 = *p2;*p2 = tmp;
}
//这个函数用于交换两个整数的值,通过交换两个整数指针所指向的值来实现。
//这意味着它可以直接在原始数组上操作,而不需要返回任何值或修改数组的大小。
//函数接收两个指向整数的指针p1和p2,然后通过一个临时变量tmp来交换这两个指针所指向的值。void Permutations(int* arr, int k, int n)
{if (k == n - 1){Show(arr, n);}else{for (int i = k; i < n; i++){Swap(&arr[k], &arr[i]);Permutations(arr, k + 1, n);Swap(&arr[k], &arr[i]);//回溯,撤销之前的交换}}
}
//此函数是生成排列的核心。它接收一个整数数组arr、一个索引k表示当前正在处理的元素位置,以及数组的总长度n。
//基准情况:如果k等于n-1,即已经处理完数组中的所有元素,此时arr表示一个有效的排列,
//因此调用Show函数来显示这个排列。
//递归情况:如果k不等于n-1,则对于从k开始的每个元素,都尝试将其与后面的元素交换,然后递归地调用Permutations来处理剩下的元素(即k+1到n-1)。
//在递归调用之后,需要撤销之前的交换,以便尝试下一个可能的排列。这是通过再次调用Swap来实现的,以确保在回溯时数组状态被正确恢复。int main()
{int arr[] = { 0,1 };Permutations(arr, 0, sizeof(arr) / sizeof(arr[0]));return 0;
}

C++实现如下:

class Solution {
public:vector<vector<string>> solveNQueens(int n) {vector<vector<string>>ans;vector<int>col(n),on_path(n),diag1(n*2-1),diag2(n*2-1);function<void(int)>dfs=[&](int r){if(r==n){vector<string>board(n);for(int i=0;i<n;i++){board[i]=string(col[i],'.')+'Q'+string(n-1-col[i],'.');}ans.emplace_back(board);return;}for(int c=0;c<n;c++){int rc=r-c+n-1;if(!on_path[c] && !diag1[r+c] && !diag2[rc]){col[r]=c;on_path[c]=diag1[r+c]=diag2[rc]=true;dfs(r+1);on_path[c]=diag1[r+c]=diag2[rc]=false;//恢复现场}}};dfs(0);return ans;}
};//1、数据结构定义:
//vector<vector<sting>>ans;用于存储所有有效的N皇后解决方案。
//vector<int>col(n),on_path(n),diag1(n*2-1),diag2(n*2-1);
//分别用于记录每一列、当前路径(即当前行)、主对角线和副对角线上是否有皇后。
//col数组用于记录每一行皇后的列位置。
//on_path数组用于标记当前列是否有皇后。
//diag1和diag2数组分别用于标记两个方向的对角线(主对角线和副对角线)上是否有皇后。
//这里使用n*2-1是因为对角线可能跨越的范围最大为从左上角到右下角(或相反),长度为n+n-1。
//2、DFS函数:
//定义一个名为dfs的lambda函数,它接受一个整数r作为参数,表示当前正在尝试放置皇后的行号。
//如果r等于n,说明已经成功地在每一行都放置了一个皇后,没有冲突,因此可以将当前的棋盘状态添加到答案中。
//否则,遍历当前行的每一列c,检查该位置是否可以放置皇后(即不在同一列、不在同一路径上、不在同一主对角线和副对角线上)。
//如果可以放置,就标记这个位置为已占用,并递归地调用dfs(r+1)来尝试放置下一行的皇后。
//递归返回后,需要恢复现场,即将之前标记为已占用的位置重新标记为未占用,以便尝试其他可能的放置方式。
//3、棋盘表示:
//在找到一个有效的N皇后布局时,会构建一个表示该布局的二维字符串向量board。每个字符串表示棋盘的一行,其中'Q'表示皇后,'.'表示空位。
//4、调用DFS:
//从第0行开始调用dfs(0),启动深度优先搜索过程。
//5、返回结果:
//最终,ans中包含了所有有效的N皇后布局,函数返回这个向量。

力扣51、N皇后(困难)

        按照国际象棋的规则,皇后可以攻击与之处在同一行或同一列或同一斜线上的棋子。

        n皇后问题研究的是如何将n个皇后放置在n*n的棋盘上,并且使皇后彼此之间不能相互攻击。

        给你一个整数n,输出所有不同的n皇后问题的解决方案。

//N皇后
#define N 8 //皇后数量(数组长度)
void Show(int* arr, int len)//输出
{for (int i = 0; i < len; i++){printf("%d ", arr[i]);}printf("\n");
}//检测当前皇后是否和前面的皇后有冲突,true有冲突,false没有冲突
//cur:当前皇后
bool CheckPos(int* arr, int cur)
{for (int i = cur - 1; i >= 0; i--)//前面所有的皇后{if (arr[cur] == arr[i] || abs(arr[cur] - arr[i]) == cur - i)return true;}return false;
}//arr:存放每个皇后的位置
//cur:当前处理第几个皇后,从0开始
void Queen(int* arr, int cur)
{for (int i = 0; i < N; i++)//当前皇后能存放的所有位置{arr[cur] = i;//当前皇后存放在i位置if (!CheckPos(arr, cur))//检测当前皇后和前面皇后是否冲突{if (cur == N - 1)//最后一个皇后都没有冲突,则可以Show(arr, N);elseQueen(arr, cur + 1);//处理下一个皇后}}
}int main()
{int arr[N];//保存N皇后的位置Queen(arr, 0);//从0下标开始return 0;
}
class Solution {
public:vector<vector<string>> solveNQueens(int n) {vector<vector<string>>ans;vector<int>col(n),on_path(n),diag1(n*2-1),diag2(n*2-1);function<void(int)>dfs=[&](int r){if(r==n){vector<string>board(n);for(int i=0;i<n;i++){board[i]=string(col[i],'.')+'Q'+string(n-1-col[i],'.');}ans.emplace_back(board);return;}for(int c=0;c<n;c++){int rc=r-c+n-1;if(!on_path[c] && !diag1[r+c] && !diag2[rc]){col[r]=c;on_path[c]=diag1[r+c]=diag2[rc]=true;dfs(r+1);on_path[c]=diag1[r+c]=diag2[rc]=false;//恢复现场}}};dfs(0);return ans;}
};//1、数据结构定义:
//vector<vector<sting>>ans;用于存储所有有效的N皇后解决方案。
//vector<int>col(n),on_path(n),diag1(n*2-1),diag2(n*2-1);
//分别用于记录每一列、当前路径(即当前行)、主对角线和副对角线上是否有皇后。
//col数组用于记录每一行皇后的列位置。
//on_path数组用于标记当前列是否有皇后。
//diag1和diag2数组分别用于标记两个方向的对角线(主对角线和副对角线)上是否有皇后。
//这里使用n*2-1是因为对角线可能跨越的范围最大为从左上角到右下角(或相反),长度为n+n-1。
//2、DFS函数:
//定义一个名为dfs的lambda函数,它接受一个整数r作为参数,表示当前正在尝试放置皇后的行号。
//如果r等于n,说明已经成功地在每一行都放置了一个皇后,没有冲突,因此可以将当前的棋盘状态添加到答案中。
//否则,遍历当前行的每一列c,检查该位置是否可以放置皇后(即不在同一列、不在同一路径上、不在同一主对角线和副对角线上)。
//如果可以放置,就标记这个位置为已占用,并递归地调用dfs(r+1)来尝试放置下一行的皇后。
//递归返回后,需要恢复现场,即将之前标记为已占用的位置重新标记为未占用,以便尝试其他可能的放置方式。
//3、棋盘表示:
//在找到一个有效的N皇后布局时,会构建一个表示该布局的二维字符串向量board。每个字符串表示棋盘的一行,其中'Q'表示皇后,'.'表示空位。
//4、调用DFS:
//从第0行开始调用dfs(0),启动深度优先搜索过程。
//5、返回结果:
//最终,ans中包含了所有有效的N皇后布局,函数返回这个向量。

力扣78、子集(中等)

        给你一个整数数组nums,数组中的元素互不相同。返回该数组所有可能的子集。

        不能包含重复的子集。你可能按任意顺序输出解集。

//子集
//arr:数组名,n:数组长度
void SubSet(int* arr, int n)
{int maxnum = 1 << n;for (int i = 0; i < maxnum; i++)//处理0到2^n  -1之间的数字{for (int j = 0; j < n; j++)//j表示二进制右数第几位,同时也表示arr中第j号数据{if ((i & (1 << j)) != 0)//表示当前位不为0,则需要打印相应的字母{printf("%d ", arr[j]);}}printf("\n");}
}int main()
{int arr[] = { 1,2,3 };SubSet(arr, sizeof(arr) / sizeof(arr[0]));return 0;
}

C++实现如下:

class Solution {
public:vector<vector<int>> subsets(vector<int>& nums) {vector<vector<int>> v;int n=nums.size();      //长度for(int i=0;i<(1<<n);i++)//从0~(1000(二进制)-1){vector<int>tmp;for(int j=0;j<n;j++) //j表示二进制右数第几位,同时也表示arr中第j号数据{if((i & (1<<j))!=0)//表示当前位不为0,则输出当前数据tmp.push_back(nums[j]);}v.push_back(tmp);}return v;}
};//1、初始化:
//首先,创建一个vector<vector<int>>类型的变量v,用于存储所有可能的子集。同时,获取输入数组nums的长度n。
//2、遍历所有可能的子集:
//使用一个从0到(1<<n)的循环来遍历所有可能的子集。
//这里的(1<<n)实际上是2^n的位运算表示,因为n位二进制数可以表示从0到2^n-1的所有整数,
//每个整数都对应数组nums的一个特定子集(通过选择或不选择nums中的每个元素)。
//3、构建子集
//对于每个整数i(从0到2^n-1),通过检查其二进制表示的每一位来确定是否选择nums数组中的对应元素。
//这是通过位运算(i&(i<<j))来实现的,其中j表示当前正在检查的位(从右往左,即数组nums的索引)。
//如果(i&(i<<j))的结果不为0,则表示i的二进制表示中第j位是1,因此应该将nums[j]添加到当前子集tmp中。
//4、存储子集
//完成一个子集tmp的构建后,将其添加到结果集v中。
//5、返回结果:最后,返回包含所有可能子集的v。

        再介绍一个腾讯的面试题

        有一个集合由A~Z这26个字母组成,打印这个集合的所有子集,每个子集一行,写C代码实现,不能使用递归。

//str为A~Z的字母集合,n为需要处理的前n个字符集合,本题n为26,n是为了方便测试
void SubSet(int n)
{const char* str = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";int maxnum = 1 << n;   //2^nfor (int i = 0; i < maxnum; i++)//处理0到2^n   -1之间的数字{for (int j = 0; j < n; j++)//j表示二进制右数第几位{if ((i & (1 << j)) != 0)//表示当前位不为0,则需要打印数组相应的字母{printf("%c ", str[j]);}}printf("\n");}
}int main()
{SubSet(3);printf("----------------------\n");//SubSet(26);//数据太大不好统计测试结果return 0;
}

力扣79、单词搜索(中等)

同剑指offer12.矩阵中的路径

//矩阵中的路径
//matrix:字符矩阵,rows:矩阵的行数,cols:矩阵的列数
//row:当前处理行号,col:当前处理的列号
//str:字符串路径,pathLength:当前处理的字符串的第几个字符
//visited:字符是否被访问过标记数组
bool hasPathCore(char* matrix, int rows, int cols, int row, int col,const char* str, int* pathLength, bool* visited)
{if (str[*pathLength] == '\0')//字符串路径处理完成return true;bool haspa = false;//从当前开始是否有路径if (row >= 0 && row<rows && col >= 0 && col<cols &&matrix[row * cols + col] == str[*pathLength] && !visited[row * cols + col]){//矩阵当前字符和字符串路径当前字符相同++(*pathLength);visited[row * cols + col] = true;//判断下一个点,是否有路径haspa = hasPathCore(matrix, rows, cols, row, col - 1, str, pathLength, visited) ||//左hasPathCore(matrix, rows, cols, row - 1, col, str, pathLength, visited) ||//上hasPathCore(matrix, rows, cols, row, col + 1, str, pathLength, visited) || //右hasPathCore(matrix, rows, cols, row + 1, col, str, pathLength, visited);//下if (!haspa)//下一个点没有路径,回溯{--(*pathLength);visited[row * cols + col] = false;}}return haspa;
}
//矩阵中的路径
//判断给定的字符串在矩阵中是否有路径
//matrix:字符矩阵
//rows:字符矩阵的行
//cols:字符矩阵的列
//str:需要找的字符串路径
bool hasPath(char* matrix, int rows, int cols, const char* str)
{if (matrix == NULL || rows < 1 || cols < 1 || str == NULL)//参数非法return false;//true:表示当前这个格子已经被访问过,false还没有被访问bool* visited = (bool*)calloc(rows * cols, sizeof(bool));//calloc创建的内存默认为0int pathLength = 0;//str的下标for (int i = 0; i < rows; ++i)//遍历矩阵的所有开始点(每一个点都可能是开始点){for(int j=0;j<cols;j++)if (hasPathCore(matrix, rows, cols, i, j, str, &pathLength, visited))//判断从当前结点{free(visited);return true;}}free(visited);return false;
}int main()
{char matrix[3][4] = { {'a','b','t','g'},{'c','f','c','s'},{'j','d','e','h'} };const char* str = "bfce";if (hasPath((char*)matrix,3,4,str))printf("%s有路\n", str);elseprintf("%s没有路\n", str);return 0;
}

C++实现如下:

class Solution {bool visited[6][6]={false};//题目说明数据范围
public:bool hasPath(vector<vector<char>>& board,int i,int j,string word,int&cur){if(cur==word.size())//全部比较完成return true;int m = board.size();//行int n = board[0].size();//列bool flg = false;//有没有路if(0<=i && i<m && 0<=j && j<n && board[i][j]==word[cur] && !visited[i][j]){visited[i][j]=true;++cur;flg = hasPath(board,i,j-1,word,cur)//左|| hasPath(board,i,j+1,word,cur)//右|| hasPath(board,i-1,j,word,cur)//上|| hasPath(board,i+1,j,word,cur);//下if(!flg){--cur;visited[i][j]=false;}}return flg;}bool exist(vector<vector<char>>& board, string word) {int m = board.size();int n = board[0].size();int cur = 0;for(int i=0;i<m;i++){for(int j=0;j<n;j++){if(hasPath(board,i,j,word,cur))return true;}}return false;}
};//1、全局变量:
//visited数组用于记录棋盘上的ifu是否已经被访问过,避免重复访问和无限循环。
//2、hasPath方法:
//这是一个递归函数,用于在棋盘上搜索给定单词的剩余部分。它接收棋盘board、当前位置(i,j)、
//要搜索的单词word和当前已经匹配的单词长度cur作为参数。
//如果cur等于word.size(),说明单词已经完整匹配,返回true。
//检查当前位置(i,j)是否在棋盘范围内、是否未被访问过、且当前位置的字符与单词的下一个字符匹配。
//如果满足条件,标记当前位置为已访问,并尝试四个方向(左、右、上、下)递归搜索。
//如果在任何方向找到了匹配路径,flg被设置为true并返回。
//如果在所有方向都没有找到匹配路径,则回溯,即将cur减1并将当前位置标记为未访问。
//3、exist方法:
//这是公开的接口函数,用于启动搜索过程。它遍历棋盘上的每个位置,从每个位置开始尝试搜索给定的单词。
//如果hasPath方法返回true,则立即返回true,表示找了匹配路径。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/48252.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【Android Studio】整合okhttp发送get和post请求(提供Gitee源码)

前言&#xff1a;本篇博客教学大家如何使用okhttp发送同步/异步get请求和同步/异步post请求&#xff0c;这边博主把代码全部亲自测试过了一遍&#xff0c;需要源码的可以在文章最后自行拉取。 目录 一、导入依赖 二、开启外网访问权限 三、发送请求 3.1、发送同步get请求…

关于pycharm上push项目到gitee失败原因

版权声明&#xff1a;本文为博主原创文章&#xff0c;如需转载请贴上原博文链接&#xff1a;https://blog.csdn.net/u011628215/article/details/140577821?spm1001.2014.3001.5502 前言&#xff1a;最近新建项目push上gitee都没有问题&#xff0c;但是当在gitee网站进行了一个…

2024在线PHP加密网站源码

源码介绍 2024在线PHP加密网站源码 更新内容: 1.加强算法强度 2.优化模版UI 加密后的代码示例截图 源码下载 https://download.csdn.net/download/huayula/89568335

kafka集群搭建-使用zookeeper

1.环境准备&#xff1a; 使用如下3台主机搭建zookeeper集群&#xff0c;由于默认的9092客户端连接端口不在本次使用的云服务器开放端口范围内&#xff0c;故端口改为了8093。 172.2.1.69:8093 172.2.1.70:8093 172.2.1.71:8093 2.下载地址 去官网下载&#xff0c;或者使用如…

Mysql的主从复制(重要)和读写分离(理论重要实验不重要)

一、主从复制&#xff1a;架构一般是一主两从。 1.主从复制的模式&#xff1a; mysql默认模式为异步模式&#xff1a;主库在更新完事务之后会立即把结果返回给从服务器&#xff0c;并不关心从库是否接收到以及从库是否处理成功。缺点&#xff1a;网络问题没有同步、防火墙的等…

vue3-video-play 导入 以及解决报错

npm install vue3-video-play --save # 或者 yarn add vue3-video-play import Vue3VideoPlay from vue3-video-play; import vue3-video-play/dist/style.css; app.use(Vue3VideoPlay) <template><div id"main-container-part"><div class"al…

Meta发布最强AI模型,扎克伯格公开信解释为何支持开源?

凤凰网科技讯 北京时间7月24日&#xff0c;脸书母公司Meta周二发布了最新大语言模型Llama 3.1&#xff0c;这是该公司目前为止推出的最强大开源模型&#xff0c;号称能够比肩OpenAI等公司的私有大模型。与此同时&#xff0c;Meta CEO马克扎克伯格(Mark Zuckerberg)发表公开信&a…

opencv grabCut前景后景分割去除背景

参考&#xff1a; https://zhuanlan.zhihu.com/p/523954762 https://docs.opencv.org/3.4/d8/d83/tutorial_py_grabcut.html 环境本次&#xff1a; python 3.10 提取前景&#xff1a; 1、需要先把前景物体框出来 需要坐标信息&#xff0c;可以用windows自带的画图简单提取像素…

Concat() Function-SQL-字符串拼接函数

Concat() Function-SQL 在SQL中&#xff0c;CONCAT() 函数用于将两个或多个字符串连接在一起。 不同数据库管理系统可能有些许差异&#xff0c;但基本用法和语法通常是相似的。 语法 CONCAT(string1, string2, ...)string1, string2, …: 这些是需要连接的字符串参数。可以…

【时序约束】读懂用好Timing_report

一、静态时序分析&#xff1a; 静态时序分析&#xff08;Static Timing Analysis&#xff09;简称 STA&#xff0c;采用穷尽的分析方法来提取出整个电路存在的所有时序路径&#xff0c;计算信号在这些路径上的传播延时&#xff0c;检查信号的建立和保持时间是否满足时序要求&a…

定时器+外部中断实现NEC红外线协议解码

一、前言 1.1 功能介绍 随着科技的进步和人们生活水平的提高&#xff0c;红外遥控器已经成为了日常生活中不可或缺的电子设备之一&#xff0c;广泛应用于电视、空调、音响等多种家电产品中。 传统的红外遥控器通常只能实现预设的有限功能&#xff0c;无法满足用户对设备更加智…

TCP客户端connect断线重连

文章目录 TCP客户端connect断线重连1、为什么要断线重连2、实现代码 TCP客户端connect断线重连 1、为什么要断线重连 客户端会面临服务器崩溃的情况&#xff0c;我们可以试着写一个客户端重连的代码&#xff0c;模拟并理解一些客户端行为&#xff0c;比如游戏客户端等. 考虑到…

实战篇(十二):如何使用 Processing 创建一个多功能的简易吃豆人游戏

如何使用 Processing 创建一个多功能的简易吃豆人游戏 文章目录 如何使用 Processing 创建一个多功能的==简易==吃豆人游戏引言准备工作第一步:设置基本框架第二步:创建 Pacman 类第三步:创建 Obstacle 类第四步:添加分数系统第五步:运行游戏完整代码结论参考资料引言 吃…

STL常用算法——常用查找算法

自定义类型都要用仿函数判断 1.find() class Person { public:Person(string name,int age){this->m_Name name;this->m_Age age;}bool operator(const Person &p)//重载operator{if (this->m_Name p.m_Name && this->m_Age p.m_Age){return true;…

NVIDIA 全面转向开源 GPU 内核模块

NVIDIA 全面转向开源 GPU 内核模块 文章目录 NVIDIA 全面转向开源 GPU 内核模块支持的 GPU安装程序更改使用带有 CUDA 元包的包管理器 使用运行文件使用安装帮助脚本包管理器详细信息dnf&#xff1a;Red Hat Enterprise Linux、Fedora、Kylin、Amazon Linux 或 Rocky Linuxzypp…

网络安全等级保护:什么是网络安全等级保护?(非常详细)零基础入门到精通,收藏这一篇就够了

关键词&#xff1a; 网络安全等级保护 等级保护 网络 信息系统 旧话重提&#xff0c;一直以来&#xff0c;我们不断强调“等级保护”制度是我国的网络安全领域的基本制度、基本策略和基本方法&#xff0c;是促进信息化健康发展&#xff0c;维护国家安全、社会秩序和公共利益的…

数字图像处理中的常用特殊矩阵及MATLAB应用

一、前言 Matlab的名称来源于“矩阵实验室&#xff08;Matrix Laboratory&#xff09;”&#xff0c;其对矩阵的操作具有先天性的优势&#xff08;特别是相对于C语言的数组来说&#xff09;。在数字图像处理中&#xff0c;为了提高编程效率&#xff0c;我们可以使用多种方式来创…

Mysql数据库和Sql语句

数据库管理&#xff1a; sql语句&#xff1a;数据库用来增删改查的语句&#xff08;重要&#xff09; 备份&#xff1a;数据库的数据进行备份 主从复制、读写分离、高可用&#xff08;重要&#xff09; Mysql数据库和Sql语句 一、Mysql数据库 1、数据库&#xff1a;组织、…

Java基础(四) 内部类详解

Java 内部类详解 一. 内部类概述 内部类是嵌套在类内部进行定义的类&#xff0c;其外部的类则被称为外部类&#xff1b;按照内部类的定义位置&#xff0c;内部类可进一步划分为成员内部类、静态内部类、局部内部类和匿名内部类四种类型。内部类的出现实际上是进一步丰富了类的…

Modbus转BACnet/IP网关的技术实现与应用

引言 随着智能建筑和工业自动化的快速发展&#xff0c;不同通信协议之间的数据交换也变得日益重要。Modbus和BACnet/IP是两种广泛应用于自动化领域的通信协议&#xff0c;Modbus以其简单性和灵活性被广泛用于工业自动化&#xff0c;而BACnet/IP则在楼宇自动化系统中占据主导地…