【动手学运动规划】 4.5 A*算法
我宁愿永远做我自己,也不愿成为别人,即使那个人比你更快乐。
—《成为简·奥斯汀》
🏰代码及环境配置:请参考 环境配置和代码运行!
4.5.1 概述
Dijkstra算法是基于广度优先搜索策略来遍历空间内的所有节点,最终计算出全局最优的路径,其计算量非常大。而基于启发式的贪婪最佳优先搜索(greedy best first search,GBFS)速度快,但结果可能不是最优的。那么,如何将二者的优势结合呢,即在Dijkstra算法基础上,引入启发式策略。这就是A*算法。
🌟**Note:**最佳优先搜索算法是在广度优先搜索的基础上,用启发估价函数对将要被遍历到的点进行估价,然后选择代价小的进行遍历,直到找到目标节点或者遍历完所有点,算法结束。
4.5.2 算法详解
A*算法结合了GBFS算法和Dijkstra算法的优点,通过评估函数 f ( n ) f(n) f(n)来指导搜索过程, f ( n ) f(n) f(n)定义为从起点到节点n
的实际代价 g ( n ) g(n) g(n)与从节点n
到目标节点的估计代价 h ( n ) h(n) h(n)之和,即 f ( n ) = g ( n ) + h ( n ) f(n)=g(n) + h(n) f(n)=g(n)+h(n)。
- g ( n ) g(n) g(n):从起点到节点
n
的实际代价(通常是距离或消耗)。 - h ( n ) h(n) h(n):从节点
n
到目标节点的估计代价(启发式函数)。
🌟**Note:**为了确保 g ( n ) g(n) g(n)和 h ( n ) h(n) h(n)的相加有意义,这两个值必须使用相同的衡量单位。
4.5.1.1 启发式函数
启发式函数可以控制A*的行为:
- 一种极端情况,如果 h ( n ) h(n) h(n)是0,则只有 g ( n ) g(n) g(n)起作用,此时A*演变成Dijkstra算法,计算量增大,但可以确保找到最优路径。
- 如果 h ( n ) h(n) h(n)经常都比从节点
n
移动到目标节点的实际代价小(或者相等),则A可以保证能找到一条最优路径。 h ( n ) h(n) h(n)越小,A扩展的节点越多,计算量越大,运行得越慢。 - 如果 h ( n ) h(n) h(n)精确地等于从节点
n
移动到目标节点的代价,则A*将会仅仅寻找最优路径而不扩展别的任何结点,这会运行得非常快。尽管这不可能在所有情况下发生,但仍可以在一些特殊情况下让它们精确地相等。 - 如果 h ( n ) h(n) h(n)有时比从节点
n
移动到目标节点的实际代价高,则A*不能保证找到一条最优路径,但它运行得更快。 - 另一种极端情况,如果 h ( n ) h(n) h(n)比 g ( n ) g(n) g(n)大很多,则只有 h ( n ) h(n) h(n)起作用,A*演变成GBFS算法。
下图可以清晰的看出不同的 h ( n ) h(n) h(n)对算法的影响(图中绿色的为起始点,红色的为目标点):
- a = 1 , b = 0 a=1, b=0 a=1,b=0:如图Fig.1,此时A*算法变成了Dijkstra算法,虽然可以得到最优解,但是扩展了非常多的节点,计算量很大。
- a = 0 , b = 1 a=0,b=1 a=0,b=1:如图Fig.2,此时A*算法变成了GBFS算法,计算量减少,但可能找不到最优解。
- a = 1 , b = 1 a=1,b=1 a=1,b=1:如图Fig.3,即为A*算法,平衡了计算量和最优解之间的关系。
🌟Note: 图中的算法展示来源于:https://qiao.github.io/PathFinding.js/visual/
经过分析,可以看到在A*算法中,启发式函数 h ( n ) h(n) h(n)扮演着及其重要的角色,以下是一些常见的启发式函数类型:
- 曼哈顿距离(Manhattan Distance):
- 曼哈顿距离是A*算法中常用的启发式函数之一。它计算的是两点在标准坐标系上的绝对轴距总和,即只能沿着坐标轴(或网格的边界)移动的距离。对于网格地图,曼哈顿距离非常适合,因为它反映了实际移动中的限制(如只能上下左右移动)。
- 公式: h ( n ) = ∣ x n − x g o a l ∣ + ∣ y n − y g o a l ∣ h(n)=\left | x_{n} - x_{goal} \right | + \left | y_{n} - y_{goal} \right | h(n)=∣xn−xgoal∣+∣yn−ygoal∣,其中 ( x n , y n ) (x_{n},y_{n}) (xn,yn)和 ( x g o a l , y g o a l ) (x_{goal},y_{goal}) (xgoal,ygoal)分别是当前点和目标点的坐标。
- 欧几里得距离(Euclidean Distance):
- 欧几里得距离是两点之间的直线距离,在平面直角坐标系中,它可以通过勾股定理计算得到。虽然欧几里得距离在物理上更准确,但在网格地图中,由于只能沿网格线移动,它可能不总是反映实际的最短路径。然而,在某些情况下,为了简化计算或适应特定需求,也可以使用欧几里得距离作为启发式函数。
- 公式: h ( n ) = ( x n − x g o a l ) 2 + ( y n − y g o a l 2 ) h(n)=\sqrt{(x_{n} - x_{goal})^{2} + (y_{n} - y_{goal}^{2} )} h(n)=(xn−xgoal)2+(yn−ygoal2)
- 切比雪夫距离(Chebyshev Distance):
- 切比雪夫距离是各坐标数值差的最大值,也称为棋盘距离或 L ∞ L\infty L∞ 度量。在网格地图中,它表示从一个点到另一个点所需改变的最大坐标值(即沿任一坐标轴移动的最大步数)。虽然不如曼哈顿距离常用,但在某些特定场景下,切比雪夫距离也能作为有效的启发式函数。
- 公式: h ( n ) = m a x ( ∣ x n − x g o a l ∣ , ∣ y n − y g o a l ∣ ) h(n)=max(\left | x_{n} - x_{goal} \right |, \left | y_{n} - y_{goal} \right |) h(n)=max(∣xn−xgoal∣,∣yn−ygoal∣)
- 自定义启发式函数:
- 除了上述常见的启发式函数外,还可以根据具体问题设计自定义的启发式函数。自定义启发式函数可以更加精确地反映问题的实际情况,从而提高搜索效率和准确性。然而,设计有效的自定义启发式函数需要深入了解问题的本质和特性。
4.5.1.2 算法步骤
其算法步骤如下:
- 初始化:
- 创建一个数组
g[]
,其中g[i]
表示从源节点start
到节点i
的最小cost,初始时,源节点的cost为0。 - 创建一个数组
f[]
,其中f[i]
表示从源节点start
到节点i
的最小cost + 节点i
到目标节点的启发式cost。 - 创建一个布尔数组
visited[]
来跟踪每个节点是否已被访问过,初始时,所有顶点都未访问 - 创建一个优先队列
open_list
,用于根据cost选择下一个要处理的节点。优先队列中的每个元素是一个包含顶点和cost的配对,初始时将源节点start
和其f cost加入优先队列。
- 创建一个数组
- 循环处理优先队列中的节点:
- 从优先队列中取出f cost最小的节点
v
,并将节点v
标记为已访问,若节点v
就是目标节点,则提前返回。 - 遍历节点
v
中所有未被访问过的邻接节点,对于每一个邻接节点next
:- 计算邻接节点
next
的g cost和h cost。 - 若邻接节点
next
不在优先队列中,则将邻接节点next
和其对应的f cost加入优先队列,并在数组g[]
和f[]
中设置分别设置邻接节点next
的g cost和f cost,最后将临接节点next
的父节点设为v
。 - 若邻接节点
next
在优先队列中,则在数组g[]
,f[]
和优先队列open_list
中更新节点next
的相关信息,最后将临接节点next
的父节点设为v
。
- 计算邻接节点
- 继续处理优先队列中的顶点,直到队列为空或所有顶点都被访问。
- 从优先队列中取出f cost最小的节点
- 从目标节点
goal
开始,通过父节点向回追溯,直到起始节点,最终得到一条路径。
其伪代码如下:
Algorithm A star(G, start, goal):let **open_list** be a priority_queueg[**start**] = 0f[**start**] = g[**start**] + h[**start**]**open_list.**push(**start,** f[**start**])while **open_list** is not empty dov = **open_list**.pop()mark v as vistedif v is the **goal**:return vfor **all unvisited neighbours** next of v in Graph G do next_g_cost = g[v] + cost(v, next)next_h_cost = h[next]if next is not in **open_list**:g[next] = next_g_costf[next] = next_g_cost + next_h_cost**open_list**.push(next, f[next])next.parent = velse:if g[next] > next_g_cost:g[next] = next_g_costf[next] = next_g_cost + next_h_cost**open_list**.**update_priority**(next, f[next])next.parent = v
4.5.1.3 算法图解
以从下面的无向图中寻找出节点A
到节点E
的最短路径为例,其中两个节点之间的权重表示他们之间的距离(或者cost),节点旁边的数字表示预定义的启发项,并初始话两个表:visited nodes info和unvisited nodes info。
所有节点的初始cost如下:
- 源节点到自身的g-cost为0,到目标节点的h-cost为6,因此源节点的f-cost为6。
- 源节点到其它节点的cost还没有确定,暂时先标记为无穷大。
- 从源节点
A
开始,将其加入到已访问列表中,并从未访问列表中删除。同时在未访问列表中更新源节点A
的邻近节点(节点B
和节点C
)的信息。- 节点
B
:节点B
最短路径为A —> B
,g-cost为1.5,h-cost为5,f-cost为6.5,父节点为A
- 节点
C
:节点C
最短路径为A —> C
,g-cost为2,h-cost为3,f-cost为5,父节点为A
- 节点
- 查看未访问列表,节点
C
的cost最小,因此将其加入到已访问列表中,并从未访问列表中删除。同时在未访问列表中更新节点C
的邻近节点(节点E
)的信息。- 节点
E
:节点E
最短路径为A —> C —> E
,g-cost为5,h-cost为0,f-cost为5,父节点为C
。
- 节点
- 查看未访问列表,节点
E
的cost最小,因此将其加入到已访问列表中,并从未访问列表中删除,此时节点E
为目标节点,因此搜索结束,经过回溯父节点,节点A
到节点E
最短路径为:A —> C —> E
。
4.5.3 优缺点
- 优点
- 高效性:A*算法结合了最佳优先搜索(Best-First Search)和Dijkstra算法的优点,通过启发式函数(heuristic function)来评估节点的优先级,从而能够快速找到从起点到终点的最短路径。
- 最优性:在启发式函数满足一定条件(如 h ( n ) h(n) h(n)始终小于等于节点 n n n到目标节点的实际代价)的情况下,A*算法能够保证找到从起点到终点的最短路径。
- 缺点
- 启发式函数的选择:虽然A*算法允许选择不同的启发式函数,但启发式函数的选择会直接影响算法的性能和结果。如果启发式函数选择不当,可能会导致算法无法找到最短路径或搜索效率降低。
4.5.c A*代码解析
本节提供了A*算法的代码测试:
python3 tests/search_based_planning/a_star_test.py
4.5.c.1 构图的代码实现
基于图搜的运动规划中最重要的一步是构图,构建的图比较简单,主要包含map border和obstacles,读者也可根据需求修改构图方式。
def construct_env_info():border_x = []border_y = []ox = []oy = []# map border.for i in range(-10, 60):border_x.append(i)border_y.append(-10.0)for i in range(-10, 60):border_x.append(60.0)border_y.append(i)for i in range(-10, 61):border_x.append(i)border_y.append(60.0)for i in range(-10, 61):border_x.append(-10.0)border_y.append(i)# Obstacle 1.for i in range(40, 55, 1):for j in range(5, 15, 1):ox.append(i)oy.append(j)# Obstacle 2.for i in range(40):for j in range(20, 25, 1):ox.append(j)oy.append(i)# Obstacle 3.for i in range(30):for j in range(40, 45, 1):ox.append(j)oy.append(58.0 - i)# Obstacle 4.for i in range(0, 20, 1):for j in range(35, 40, 1):ox.append(i)oy.append(j)return border_x, border_y, ox, oy
4.5.c.2 A*的代码实现
在A*算法中,首先我们定义了节点Node
,这是图的基础元素。其中(x, y)
表示节点的位置,cost
表示从源节点到当前节点的cost,parent
表示当前节点的父节点。
class Node:def __init__(self, x, y, cost, parent_index):self.x = x self.y = y self.cost = costself.parent_index = parent_indexdef __str__(self):return (str(self.x)+ ","+ str(self.y)+ ","+ str(self.cost)+ ","+ str(self.parent_index))
在A*中,启发式函数使用的是欧式距离,如下:
def calc_heuristic(n1, n2):w = 1.0 # weight of heuristicd = w * math.hypot(n1.x - n2.x, n1.y - n2.y)return d
下面是A*的核心算法,基于环境信息,起始点位置,目标点位置搜到最优路径,其中:
sx
:起始点的x坐标的值
sy
:起始点的y坐标的值
gx
:目标点的x坐标的值
gy
:目标点的y坐标的值
最终返回一条路径:rx, ry
def planning(self, sx, sy, gx, gy):start_node = self.Node(self.calc_xy_index(sx, self.min_x),self.calc_xy_index(sy, self.min_y),0.0,-1,)goal_node = self.Node(self.calc_xy_index(gx, self.min_x),self.calc_xy_index(gy, self.min_y),0.0,-1,)open_set, closed_set = dict(), dict()open_set[self.calc_grid_index(start_node)] = start_nodewhile True:if len(open_set) == 0:print("Open set is empty..")breakc_id = min(open_set,key=lambda o: open_set[o].cost+ self.calc_heuristic(goal_node, open_set[o]),)current = open_set[c_id]# show graphif show_animation:plt.plot(self.calc_grid_position(current.x, self.min_x),self.calc_grid_position(current.y, self.min_y),"xc",)# for stopping simulation with the esc key.plt.gcf().canvas.mpl_connect("key_release_event",lambda event: [exit(0) if event.key == "escape" else None],)if len(closed_set.keys()) % 10 == 0:plt.pause(0.001)plt.savefig(gif_creator.get_image_path())if current.x == goal_node.x and current.y == goal_node.y:print("Find goal")goal_node.parent_index = current.parent_indexgoal_node.cost = current.costbreak# Remove the item from the open setdel open_set[c_id]# Add it to the closed setclosed_set[c_id] = current# expand_grid search grid based on motion modelfor i, _ in enumerate(self.motion):node = self.Node(current.x + self.motion[i][0],current.y + self.motion[i][1],current.cost + self.motion[i][2],c_id,)n_id = self.calc_grid_index(node)# If the node is not safe, do nothingif not self.verify_node(node):continueif n_id in closed_set:continueif n_id not in open_set:open_set[n_id] = node # discovered a new nodeelse:if open_set[n_id].cost > node.cost:# This path is the best until now. record itopen_set[n_id] = noderx, ry = self.calc_final_path(goal_node, closed_set)return rx, ry
4.5.c.3 A*的代码测试
在main
函数中设置起始点,目标点,grid的分辨率和机器人的半径,在创建grid map之后,并运行A算法,即可找到最优路径。如下图所示,红色路径即为最终A搜出来的最优路径。
def main():# start and goal positionstart_x = 10.0 # [m]start_y = 10.0 # [m]goal_x = 50.0 # [m]goal_y = 0.0 # [m]grid_size = 2.0 # [m]robot_radius = 1.0 # [m]# construct environment info.border_x, border_y, ox, oy = construct_env_info()if show_animation: plt.plot(border_x, border_y, "s", color=(0.5, 0.5, 0.5), markersize=10)plt.plot(ox, oy, "s", color="k")plt.plot(start_x, start_y, "og", markersize=10)plt.plot(goal_x, goal_y, "ob", markersize=10)plt.grid(True)plt.axis("equal")ox.extend(border_x)oy.extend(border_y)a_star = AStarPlanner(ox, oy, grid_size, robot_radius)rx, ry = a_star.planning(start_x, start_y, goal_x, goal_y)if show_animation: plt.plot(rx, ry, "-r")plt.savefig(gif_creator.get_image_path())plt.pause(0.01)gif_creator.create_gif()plt.show()
4.5.4 A*算法的变种
A*算法有很多的变种,此处不在详细介绍,感兴趣者可参考以下链接。
- Anytime A*
- Block A*
- D*
- Field D*
- Fringe
- Fringe Saving A (FSA*)*
- Generalized Adaptive A (GAA*)*
- Incremental heuristic search
- Iterative deepening A (IDA*)*
- Jump point search
- Lifelong Planning A (LPA*)*
- Simplified Memory bounded A (SMA*)*
- Theta*
4.5.5 参考
https://en.wikipedia.org/wiki/A*_search_algorithm#Pseudocode
推荐阅读
- 端到端理论与实战
- 动手学轨迹预测
- 动手学运动规划
- 动手学行为决策
- 强化学习入门笔记
相关文章:
【动手学运动规划】 4.5 A*算法
我宁愿永远做我自己,也不愿成为别人,即使那个人比你更快乐。 —《成为简奥斯汀》 🏰代码及环境配置:请参考 环境配置和代码运行! 4.5.1 概述 Dijkstra算法是基于广度优先搜索策略来遍历空间内的所有节点,最终计算出…...
从零开始学习 sg200x 多核开发之小核 FreeRTOS 运行
sophpi 小核支持默认运行 FreeRTOS,并且已经启动,小核的运行固件被打包在 fip.bin文件中,由 fsbl 负责加载。 启动后,小核会运行 FreeRTOS,并输出日志到串口。串口日志输出在 UART0 上,波特率 115200&…...
生信软件开发1 - 设计一个简单的Windwos风格的GUI报告软件
1. 安装基础库 使用Windows 11标题样式和主题自定义UI窗口库pywinstyles(github: https://github.com/Akascape/py-window-styles),结合python自带tkinter库设计一个报告GUI软件。 pip install pywinstyles2. 设计一个简单的Windwos风格的G…...
openEuler 22.03 使用cephadm安装部署ceph集群
目录 目的步骤规格步骤ceph部署前准备工作安装部署ceph集群ceph集群添加node与osdceph集群一些操作组件服务操作集群进程操作 目的 使用ceph官网的cephadm无法正常安装,会报错ERROR: Distro openeuler version 22.03 not supported 在openEuler上实现以cephadm安装部…...
爬虫项目练手
python抓取优美图库小姐姐图片 整体功能概述 这段 Python 代码定义了一个名为 ImageDownloader 的类,其主要目的是从指定网站(https://www.umei.cc)上按照不同的图片分类,爬取图片并保存到本地相应的文件夹中。不过需要注意&…...
关于使用注册表修改键盘的键位映射
修改注册表实现键盘的键位映射 前言一、scancode是什么?二、步骤1.打开注册表2.scancode表 总结 前言 弄了个蓝牙的欧洲键盘,但左上角居然是WWW home键,还找不到Esc键,崩溃了,VI都用不了。 赶紧考虑键位映射ÿ…...
[HCTF 2018]WarmUp-滑稽
启动场景打开链接,出现一下图片 F12查看代码出现一个注释,应该在这个文件中, 进入到该页面,出现一段代码 <?phphighlight_file(__FILE__);class emmm{public static function checkFile(&$page){$whitelist ["sourc…...
WPF+LibVLC开发播放器-进度条显示和拖动控制
进度条显示和拖动控制 视频教程界面上代码实现进度条显示进度进度条拖动视频进度 效果 视频教程 WPFLibVLC开发播放器-进度条控制 界面上 界面上线增加一个Slider控件,当做播放进度条 <SliderName"PlaySlider"Grid.Row"1"Width"800&qu…...
linux下Qt程序部署教程
文章目录 [toc]1、概述2、静态编译安装Qt1.1 安装依赖1.2 静态编译1.3 报错1.4 添加环境变量1.5 下载安装QtCreator 3、配置linuxdeployqt环境1.1 在线安装依赖1.2 使用linuxdeployqt提供的程序1.3 编译安装linuxdeployqt 4、使用linuxdeployqt打包依赖1.1 linuxdeployqt使用选…...
Python3:pytest+request+yaml+allure接口自动化测试
pytest+request+yaml+allure接口自动化测试 一、Pytest的parametrize结合yaml实现数据驱动 1、读取yaml文件数据 ids:- [请求方式,请求地址,请求头,请求参数,预期结果]#测试用例测试数据 testcases:test_login:- ["POST","http://10.1.1.xx:8081/xx/xx"…...
【Docker】针对开发环境、测试环境、生产环境如何编排?
目录 一、引言 二、Docker Compose 文件基础 三、针对不同环境的 Docker 编排 开发环境 测试环境 生产环境 四、配置文件全局变量的编写 五、总结 一、引言 在软件开发和部署的过程中,不同的环境有着不同的需求和配置。Docker 作为一种强大的容器化技术&…...
数据采集卡的各参数介绍
数据采集卡(DAQ 卡)是用于测量物理信号(如电压、电流、温度等)并将其转化为数字信号的设备。 1. 通道数(Channels) 含义:数据采集卡可以同时采集多少路信号。比喻:通道数就像一个人…...
MySQL备份恢复
华子目录 MySQL日志管理为什么需要日志日志作用日志文件查看方法错误日志通用查询日志慢查询日志示例 撤销日志重做日志二进制日志---重要中继日志 MySQL备份备份类型逻辑备份优缺点备份内容备份工具导入sql文件 MySQL日志管理 为什么需要日志 用于排错用来做数据分析了解程序…...
flask内存马的真谛!!!
flask内存马 1.概念 常用的Python框架有Django、Flask, 这两者都可能存在SSTI漏洞. Python 内存马利用Flask框架中SSTI注入来实现, Flask框架中在web应用模板渲染的过程中用到render_template_string进行渲染, 但未对用户传输的代码进行过滤导致用户可以通过注入恶意代码来实…...
【机器学习02--模型评估】
机器学习 --- 模型评估 你需要得到更好的模型,怎么判断模型更好呢?你需要先得到训练集和测试集,怎么划分它们呢?训练完模型之后,在验证集上测试的时候,用什么指标衡量好坏呢?云里雾里࿰…...
【人工智能】深入解析Python中的聚类算法:从K-Means到DBSCAN
解锁Python编程的无限可能:《奇妙的Python》带你漫游代码世界 聚类是一种无监督学习的核心技术,用于将数据点分组到不同的簇中,使得同一簇内的点相似度最大化,不同簇间的点差异性最大化。K-Means和DBSCAN是两种最常见的聚类算法,分别适用于密度驱动和形状复杂的数据分组需…...
【STM32 Modbus编程】-作为主设备读取线圈和输入
作为主设备读取线圈和输入 文章目录 作为主设备读取线圈和输入1、硬件准备与连接1.1 RS452模块介绍1.2 硬件配置与接线1.3 软件准备2、读取线圈2.1 主设备发送请求2.2 从设备响应请求2.3 主机接收数据3、读取输入4、结果本文将在前面文章的基础上,实现主设备通过ModBus协议对从…...
数据结构(栈Stack)
1.前言: 在计算机科学中,栈(Stack)是一种基础而存在的数据结构,它的核心特性是后进先出(LIFO,Last In, First Out)。想象一下,在现实生活中我们如何处理一堆托盘——我们…...
Maven 中scope 的provided、compile、runtime、test、system 含义
在 Maven 中,<scope> 定义了依赖的可见性和生命周期。不同的 scope 值指示 Maven 在编译、测试和运行时如何处理这些依赖。以下是 Maven 中的几种常用依赖范围及其详细说明: 1. <scope>provided</scope> 含义:provided 范…...
Nginx 负载均衡和反向代理
Nginx 是一个高性能的 HTTP 服务器和反向代理服务器,广泛应用于负载均衡中。它的负载均衡功能支持多种策略,可以有效分配流量到后端服务器,提升系统的可靠性和可用性。 负载均衡 首先,Nginx 负载均衡配置是通过在 Nginx 配置文件…...
【网络安全】数据集合集!
本文将为您介绍经典、热门的数据集,希望对您在选择适合的数据集时有所帮助。 1 SecGPT 更新时间:2024-05-08 访问地址: GitHub 描述: SecGPT的愿景是将人工智能技术引入网络安全领域,以提高网络防御的效率和效果。其使命是推动…...
大数据(一)MaxCompute
一、引言 作者后面会使用MaxCompute,所以在进行学习研究,总会有一些疑问产生,这里讲讲作者的疑问和思路 二、介绍 MaxCompute(原名 ODPS - Open Data Processing Service)是阿里云提供的大数据处理平台,专…...
数据科学与大数据之间的区别
什么是数据科学? 数据科学是一个跨学科领域,它将统计学和计算方法相结合,旨在从数据中提取见解和知识。它涉及收集、处理、分析以及解读数据,以揭示可用于为决策过程提供依据并推动创新的模式、趋势和关系。 数据科学涵盖了广泛…...
IP 地理位置定位技术原理概述
本文深入探讨 IP 地理位置定位技术的原理。介绍了 IP 地址的基本概念及其在网络中的作用,随后阐述了基于数据库查询、基于网络拓扑分析以及基于机器学习算法的三种主要 IP 地理位置定位技术原理中的基于IP数据库查询。 IP 地址基础 IP 地址是互联网协议࿰…...
多进程multiprocessing通信multiprocessing.Queue
multiprocessing.Queue 通常只能在主模块(即 if __name__ "__main__": 块)中创建和使用。这是因为 multiprocessing 模块在 Windows 系统上需要通过 if __name__ "__main__": 块来避免递归导入问题。 from multiprocessing import…...
工业—使用Flink处理Kafka中的数据_ChangeRecord2
使用 Flink 消费 Kafka 中 ChangeRecord 主题的数据,每隔 1 分钟输出最近 3 分钟的预警次数最多的 设备,将结果存入Redis 中, key 值为...
微信小程序4-内容溢出滚动条
感谢阅读,初学小白,有错指正。 一、功能描述 在前一篇文章的隐藏框页面的功能里(《微信小程序3-显标记信息和弹框》),我想添加一个内容溢出的时候,可通过滑动滚动条,实现查看溢出部分的内容&a…...
python源码实例游戏开发小程序办公自动化网络爬虫项目开发源码(250+个项目、26.6GB)
文章目录 源代码下载地址项目介绍预览 项目备注源代码下载地址 源代码下载地址 点击这里下载源码 项目介绍 python源码实例游戏开发小程序办公自动化网络爬虫项目开发源码(250个项目、26.6GB) 预览 项目备注 1、该资源内项目代码都经过测试运行成功,功能ok的情…...
ProjectSend 身份认证绕过漏洞复现(CVE-2024-11680)
0x01 产品描述: ProjectSend 是一个开源文件共享网络应用程序,旨在促进服务器管理员和客户端之间的安全、私密文件传输。它是一款相当流行的应用程序,被更喜欢自托管解决方案而不是 Google Drive 和 Dropbox 等第三方服务的组织使用。0x02 漏洞描述: ProjectSend r1720 之前…...
算法训练-搜索
搜索 leetcode102. 二叉树的层序遍历 法一:广度优先遍历 leetcode103. 二叉树的锯齿形层序遍历 法一:双端队列 法二:倒序 法三:奇偶逻辑分离 leetcode236. 二叉树的最近公共祖先 法一:递归 leetcode230. 二叉…...
【C++】map和set
个人主页 : zxctscl 如有转载请先通知 文章目录 1. 关联式容器2. 键值对3. set3.1 set的模板参数列表3.2 set的构造3.3 set的迭代器3.4 set的容量3.5 set修改操作3.6 multiset 4. map4.1 map的模板参数说明4.2 map的构造4.3 map的迭代器4.4 map的容量与元素访问4.5 …...
MongoDB安装|注意事项
《疯狂Spring Boot讲义》是2021年电子工业出版社出版的图书,作者是李刚 《疯狂Spring Boot终极讲义》不是一本介绍类似于PathVariable、MatrixVariable、RequestBody、ResponseBody这些基础注解的图书,它是真正讲解Spring Boot的图书。Spring Boot的核心…...
使用playwright自动化测试时,npx playwright test --ui打开图形化界面时报错
使用playwright自动化测试时,npx playwright test --ui打开图形化界面时报错 1、错误描述:2、解决办法3、注意符号的转义 1、错误描述: 在运行playwright的自动化测试项目时,使用npm run test无头模式运行正常,但使用…...
Linux ufw 命令详解
简介 UFW(Uncomplicated Firewall) 简单防火墙是一款基于 iptables 构建的、用于管理防火墙规则的用户友好型工具。它简化了在 Linux 系统上配置防火墙的过程。 安装 在 Ubuntu/Debian 上安装 sudo apt update sudo apt install ufw在 CentOS/Red Hat 上安装 sudo yum ins…...
3248. 矩阵中的蛇
3248. 矩阵中的蛇 题目链接:3248. 矩阵中的蛇 代码如下: class Solution { public:int finalPositionOfSnake(int n, vector<string>& commands){int i 0, j 0;for (string& command : commands){if (command "LEFT") { j…...
图片的懒加载
目录 懒加载的来源 事件监听 IntersectionObserver 懒加载的来源 图片的来加载其实就是延迟加载,我们知道浏览器的可视范围是有限的,现在网页的内容越来越丰富,一般网页的内容都是需要滚动才能完成浏览 如果网页有很多图片,然…...
网络脚本生成器
网络官网地址 网络配置生成工具 终端-接入-汇聚-核心-防火墙-互联网路由器 一 开局配置 华为设备配置命令 system-viewsysname SW-JR-Switchvlan 10 vlan 20 vlan 30 vlan 40 quitinterface Vlan-interface 40 ip address 192.168.40.1 255.255.255.0 quitip route-static 1…...
Kibana server is not ready yet
遇到“Kibana server is not ready yet”错误通常表示Kibana无法连接到Elasticsearch。以下是一些常见原因及其解决方案: 1.常见原因 1.1.Elasticsearch未运行: 确保Elasticsearch服务已启动并正常运行。您可以通过访问 http://localhost:9200 来检查…...
Git 高频命令及其功能、作用与使用场景
在软件开发的世界里,Git 已经成为了版本控制的代名词。无论你是开发小型项目还是参与大型团队协作,Git 都是你不可或缺的得力助手。今天我们来聊聊 Git 中的一些高频命令,了解它们的功能、作用以及常见的使用场景,帮助你在日常开发…...
将word里自带公式编辑器编辑的公式转换成用mathtype编辑的格式
文章目录 将word里自带公式编辑器编辑的公式转换成用mathtype编辑的格式MathType安装问题MathType30天试用延期MathPage.wll文件找不到问题 将word里自带公式编辑器编辑的公式转换成用mathtype编辑的格式 word自带公式编辑器编辑的公式格式: MathType编辑的格式&a…...
【HarmonyOS】Component组件引入报错 does not meet UI component syntax.
【HarmonyOS】Component组件引入报错 一、问题背景 有时会碰到引入组件时,无法import引入组件,导致引入的组件报错。 或者提示does not meet UI component syntax. (不符合UI组件语法。) 如下图所示,在引入组件时&a…...
力扣-图论-1【算法学习day.51】
前言 ###我做这类文章一个重要的目的还是给正在学习的大家提供方向和记录学习过程(例如想要掌握基础用法,该刷哪些题?)我的解析也不会做的非常详细,只会提供思路和一些关键点,力扣上的大佬们的题解质量是非…...
使用lumerical脚本语言创建定向耦合器并进行数据分析(纯代码实现)
本文使用lumerical脚本语言创建定向耦合器波导、计算定向耦合器的偶数和奇数模式、分析定向耦合器的波长依赖性、分析定向耦合器的间隙依赖性(代码均有注释详解)。 一、绘制定向耦合器波导 1.1 代码实现 # 这段代码主要实现了绘制定向耦合器波导几何结构的功能。通过定义各种…...
Java面试要点50 - List的线程安全实现:CopyOnWriteArrayList
文章目录 一、引入二、实现原理解析2.1 写时复制机制2.2 读写分离策略 三、性能测试分析四、应用场景分析4.1 事件监听器管理4.2 缓存实现 五、最佳实践建议5.1 性能优化技巧5.2 常见陷阱规避 总结 一、引入 在并发编程中,线程安全的集合类扮演着重要角色。CopyOnWriteArrayLi…...
python脚本实现csv中百度经纬度转84经纬度
数据准备 csv文件,带百度经纬度字段:bd09_x,bd09_y 目的 将百度经纬度转换为84经纬度,并在csv文件中添加两个字段:84_x,84_y python脚本 from ChangeCoordinate import ChangeCoordimport pandas as pd import numpy as npcoord = ChangeCoord()def bd09_to_wgs84...
Vue2和Vue3的区别
响应式系统 Vue 2 技术基础:使用 Object.defineProperty 实现响应式。局限性: 无法监听新增属性:如果在创建实例后添加新属性,这些属性不会自动成为响应式的。数组变更检测问题:直接通过索引设置值或长度不会触发更新…...
JavaEE-经典多线程样例
文章目录 单例模式设计模式初步引入为何存在单例模式饿汉式单例模式饿汉式缺陷以及是否线程安全懒汉式单例模式基础懒汉式缺陷以及是否线程安全懒汉式单例模式的改进完整代码(变量volatile) 阻塞队列生产者消费者模型生产者消费者模型的案例以及优点请求与响应案例解耦合削峰填…...
Android显示系统(04)- OpenGL ES - Shader绘制三角形
一、前言: OpenGL 1.0采用固定管线,OpenGL 2.0以上版本重要的改变就是采用了可编程管线,Shader 编程是指使用着色器(Shader)编写代码来控制图形渲染管线中特定阶段的处理过程。在图形渲染中,着色器是在 GP…...
PMP–一、二、三模、冲刺–分类–10.沟通管理
文章目录 技巧十、沟通管理 一模10.沟通管理--1.规划沟通管理--文化意识--军事背景和非军事背景人员有文化差异5、 [单选] 项目团队由前军事和非军事小组成员组成。没有军事背景的团队成员认为前军事团队成员在他们的项目方法中过于结构化和僵化。前军事成员认为其他团队成员更…...
flutter windows 使用c++、dll等实践记录
在flutter的windows平台引入dll文件 https://juejin.cn/post/7223676609794015287 google官方说法(感觉不太实用) https://groups.google.com/a/dartlang.org/g/misc/c/fyh2W38AEVo Using a C DLL in Flutter Windows desktop app(未尝试&…...