图搜索算法A*、Dijkstra在路径规划中的应用

news/2024/7/20 17:34:31/文章来源:https://blog.csdn.net/qq_36372352/article/details/139280818

当我们讨论基础路径规划算法时,尤其是在图搜索算法的范畴内,通常会重点关注如A*和Dijkstra算法这样的经典方法。这些算法在多种场景中,如机器人导航、网络路由以及游戏设计中发挥着至关重要的作用。下面为您提供一个学习大纲,帮助您系统地理解和掌握这些算法。

1. 基本概念
图的定义:了解顶点、边、权重的基本概念。

图是由顶点(节点)和连接这些顶点的边(或弧)组成的集合。每个边可以有一个权重(或成本),表示从一个顶点到另一个顶点的代价。在许多应用中,如网络设计、路径规划等,边的权重扮演着关键角色。

  • 顶点:通常表示一个实体或位置,如城市、网络节点等。
  • :连接两个顶点,表示两者之间存在某种关系或路径。边可以是单向的(在有向图中)或双向的(在无向图中)。
  • 权重:边的权重表示从一个顶点到另一个顶点的代价或距离。权重可以是任意的标量值,例如距离、时间、成本或其他度量标准。
图的类型:无向图与有向图的区别,权重图。
  • 无向图:图中的每条边都是无方向的,即边不区分起点和终点。无向图常用于表示双向等价的关系,例如双向通行的道路。
  • 有向图:图中的每条边都有一个明确的方向,从一个顶点指向另一个顶点。有向图用于表示如单行道、风向、数据流向等方向性关系。
  • 权重图:图中的边具有权重,表示顶点间关系的强度或成本。权重图适用于需要考虑成本、距离或其他量化指标的场景。
存储方法:邻接矩阵和邻接表的应用与比较。

在计算机中,图的存储方式对算法的效率有直接影响。主要有两种存储图的方法:邻接矩阵和邻接表。

  • 邻接矩阵:一个二维数组,其中的元素[i] [j]表示顶点i到顶点j的边的存在及其权重。如果i到j没有直接的边,则该位置通常标记为无穷大(表示不可达)或特定的空值标记。
    • 优点:直观,易于实现;适合表示密集图,即图中大部分顶点之间都有边连接;方便检查任意一对顶点间是否存在边。
    • 缺点:空间复杂度高,为O(n^2);不适合稀疏图,因为会造成空间浪费。
  • 邻接表:一个顶点数组,每个顶点存储一个链表,链表中包含所有与该顶点相连接的其他顶点的信息和权重。
    • 优点:空间效率高,特别是对于稀疏图;动态添加和删除边更为方便。
    • 缺点:检查两个特定顶点间是否存在边比邻接矩阵慢;实现复杂度较高。

选择合适的图存储方法取决于图的类型(密集或稀疏)以及应用场景中操作的类型(如频繁检查边的存在或频繁添加和删除边)。这些基本概念是理解更复杂的图算法,如路径搜索和网络流分析,的基础。

优先级队列

优先级队列是一种抽象数据类型,支持常规队列操作,如插入元素和删除元素,但在这种队列中,每个元素都有一个与之关联的“优先级”。元素的添加和移除是基于优先级进行的:优先级最高的元素最先被移除。在不同的实现中,优先级的高低可以有不同的定义,通常可以是最大值优先(即值最大的元素被视为优先级最高)或最小值优先。

优先级队列的作用

优先级队列在计算机科学的许多领域都有广泛应用,如任务调度、数据压缩、网络流量管理,以及特别在图算法中,比如Dijkstra算法和A*搜索算法。在这些算法中,优先级队列的主要作用是管理待处理的节点,确保每次都能快速访问到当前最“紧急”或“最优”的元素。

在Dijkstra算法中的作用

在Dijkstra算法中,优先级队列用于维持所有未处理顶点的集合,并能够快速检索出当前已知最短路径的最小值顶点。这样做的好处包括:

  1. 高效性:优先级队列,尤其是实现为二叉堆的情况下,可以在对数时间内进行插入和删除最小元素操作,这使得算法能够高效地更新和访问顶点。
  2. 动态更新:当算法发现到某个顶点存在一条更短的路径时,需要更新这个顶点在队列中的优先级。优先级队列允许这种操作相对高效地进行,尽管具体的效率也取决于具体实现。
  3. 简化操作:使用优先级队列后,算法的主体部分可以不断从队列中提取最小元素进行处理,简化了管理和检索未处理顶点的逻辑。

具体实现

优先级队列可以通过多种数据结构实现,包括二叉堆、斐波那契堆、配对堆等。这些实现有各自的优缺点,如二叉堆实现简单但更新优先级(减少操作)可能较慢,而斐波那契堆虽然在理论上支持更快的优先级更新,但实现更为复杂。

总之,优先级队列是解决许多算法问题的关键工具,能够有效地支持那些需要频繁、快速地处理最优或最紧急任务的场景。在图算法中,特别是在路径搜索和最短路径计算中,它们提供了一个既高效又灵活的方式来跟踪待处理的任务。

2. Dijkstra算法
算法原理:解释算法的工作机制,包括如何使用优先级队列处理顶点。

Dijkstra算法是一种用于找到图中单个源点到其他所有点的最短路径的算法。它使用了贪心的策略,逐步扩展最短路径的边界,确保每一步都是局部最优的选择。该算法通常利用优先级队列(或称为最小堆)来高效地选择下一个需要处理的顶点,即当前已知达到的最短距离最小的顶点。

步骤详解:从源点出发,逐步扩展至图中所有可达顶点的过程。
  1. 初始化:将所有顶点的最短路径估计值设置为无穷大,源点设置为0。所有顶点标记为未处理。
  2. 优先级队列:将所有顶点放入优先级队列中,基于最短路径估计值排序。
  3. 处理顶点:从优先级队列中取出最小估计值的顶点(初始为源点)。对于这个顶点的每个邻接点,尝试通过这个顶点更新路径长度。
  4. 更新路径:对于当前顶点v的每一个邻接点u,如果通过vu的路径比已知的路径短,更新u的最短路径值,并更新优先级队列。
  5. 重复处理:重复步骤3和4,直到优先级队列为空,即所有可达顶点都已处理。
  6. 完成:算法结束后,每个顶点的最短路径值即从源点到该顶点的最短路径。
算法实现:伪代码或具体编程语言的示例。
def Dijkstra(Graph, source):dist[source] ← 0                                # 将起点的距离初始化为0create priority queue Q                         # 创建优先级队列Qfor each vertex v in Graph:                     # 遍历图中的每一个顶点vif v ≠ source:                              dist[v] ← INFINITY                      # 将非起点的距离初始化为无穷大predecessor[v] ← UNDEFINED              # 初始化v的前驱节点为未定义Q.add_with_priority(v, dist[v])             # 将每个顶点v加入优先级队列,并以其距离作为优先级while Q is not empty:                           # 当优先级队列非空时,执行循环u ← Q.extract_min()                         # 从Q中取出距离最小的顶点ufor each neighbor v of u:                   # 遍历u的每个邻接点valt ← dist[u] + length(u, v)            # 计算从源点到v的替代路径长度if alt < dist[v]:                       # 如果替代路径更短dist[v] ← alt                       # 更新到v的距离predecessor[v] ← u                  # 更新v的前驱节点为uQ.decrease_priority(v, alt)         # 更新优先级队列中v的优先级

我们来通过一个具体的例子来说明Dijkstra算法的过程。假设有一个加权图,图中的顶点表示城市,边的权重代表城市间的距离。我们的目标是找出从源城市到所有其他城市的最短路径。我们的图和权重如下:

  • 图的顶点:A, B, C, D, E
  • 图的边和权重:
    • A - B: 6
    • A - D: 1
    • B - D: 2
    • B - E: 2
    • B - C: 5
    • C - E: 5
    • D - B: 2
    • D - E: 1
    • E - C: 5

假定A是源点。我们使用Dijkstra算法来找出从A到图中每个其他顶点的最短路径。

初始设置:

  • dist[A] = 0,其他所有顶点(B, C, D, E)的距离初始化为无穷大。
  • 所有顶点加入优先级队列,以它们的距离作为优先级。

算法执行过程:

  1. 开始时的队列状态(A, 0), (B, ∞), (C, ∞), (D, ∞), (E, ∞)
  2. 提取A(最小距离顶点),检查A的邻居:
    • 更新D:dist[D] = dist[A] + length(A, D) = 0 + 1 = 1
    • 更新B:dist[B] = dist[A] + length(A, B) = 0 + 6 = 6
    • 队列更新(D, 1), (B, 6), (C, ∞), (E, ∞)
  3. 提取D(最小距离顶点),检查D的邻居:
    • 更新B(通过D):dist[B] = min(dist[B], dist[D] + length(D, B)) = min(6, 1 + 2) = 3
    • 更新E:dist[E] = dist[D] + length(D, E) = 1 + 1 = 2
    • 队列更新(E, 2), (B, 3), (C, ∞)
  4. 提取E(最小距离顶点),检查E的邻居:
    • 更新C:dist[C] = dist[E] + length(E, C) = 2 + 5 = 7
    • 队列更新(B, 3), (C, 7)
  5. 提取B(最小距离顶点),检查B的邻居:
    • 尝试更新E和C,但发现不需要更新因为现有的距离较短。
    • 队列更新(C, 7)
  6. 提取C(最小距离顶点),此时C的所有邻居都已处理过,无需进一步更新。
    • 队列为空

结果:

  • 最短路径到B:3(通过D)
  • 最短路径到C:7(通过E)
  • 最短路径到D:1(直接从A)
  • 最短路径到E:2(通过D)
应用场景:讨论Dijkstra算法在实际中的应用,如道路网络的最短路径规划。
  • 道路网络:Dijkstra算法常用于交通网络中寻找最短路线,如导航软件计算从一个地点到另一个地点的最快路径。
  • 网络路由:在网络技术中,路由器使用类似于Dijkstra算法的协议来决定数据包的最佳路径。
  • 城市规划:可以用于规划公共交通系统,确定站点之间的最短路径以优化路线。
局限性:不能处理有负权边的图。
  • 负权边:Dijkstra算法不能处理有负权边的图。如果图中包含负权边,算法可能无法正确计算最短路径。
  • 效率问题:对于非常大或非常密集的图,即使使用优先级队列,Dijkstra算法的性能也可能受到影响,尤其是在需要频繁操作优先级队列的情况下。
3. A*搜索算法
算法原理:A*算法的核心,包括启发式函数(Heuristic)的概念和作用。

A搜索算法是一种用于找到从起点到目标点的最短路径的高效路径搜索算法。其核心在于使用一个启发式函数(Heuristic function),这个函数估计从当前节点到目标节点的最小成本。A算法的特点是它结合了Dijkstra算法(强调路径的最小成本)和贪心最佳优先搜索(优先访问距离目标近的节点)的优点。

启发式函数的选择:如何选择合适的启发式函数,包括常见的启发式函数例如欧几里得距离、曼哈顿距离。

启发式函数对A*算法的性能至关重要。合适的启发式函数能保证算法效率和准确性。常见的启发式函数包括:

  • 欧几里得距离:适用于可以直线移动的场景,计算两点间的直线距离。
  • 曼哈顿距离:适用于只能沿着格线移动(如街区)的场景,计算两点间的网格移动总距离。

选择启发式函数时应确保它是可采纳的(即不会高估实际的最小成本)和一致的(从任意节点到目标的估计成本不大于其任一邻居的估计成本加上从该邻居到该节点的实际成本)。

步骤详解:从源点到目标点的搜索过程,如何利用启发式函数优化搜索路径。
  1. 初始化:将起点的f值(g+h,其中g是起点到当前点的成本,h是启发式估计成本)设置为h(启发式估计成本),其他所有点设置为无穷大。
  2. 优先级队列:将起点加入优先级队列。
  3. 处理节点:从优先级队列中取出具有最低f值的节点。如果这个节点是目标节点,算法结束。
  4. 邻居更新:更新所有邻居的g值,计算新的f值,并重新放入优先级队列。
  5. 重复:重复步骤3和4,直到找到目标或队列为空。
算法实现:提供伪代码或编程语言的示例。
function A*(start, goal)openSet = PriorityQueue(initialize with start)            # 初始化包含起点的优先队列cameFrom = an empty map                                   # 创建一个空的来路图gScore = map with default value of Infinity               # 为每个节点设置默认距离无穷大的gScore映射gScore[start] = 0                                         # 起点的gScore设置为0fScore = map with default value of Infinity               # 为每个节点设置默认距离无穷大的fScore映射fScore[start] = heuristic(start, goal)                    # 起点的fScore设置为启发式函数的结果while openSet is not empty                                # 当开放集不为空时,循环执行current = openSet.remove_min()                        # 从开放集中移除具有最小fScore的节点if current == goal                                    # 如果当前节点是目标节点return reconstruct_path(cameFrom, current)        # 返回从起点到目标节点的路径for each neighbor of current                          # 遍历当前节点的每个邻居tentative_gScore = gScore[current] + dist_between(current, neighbor)  # 计算从起点到邻居的临时gScoreif tentative_gScore < gScore[neighbor]            # 如果临时gScore小于已记录的gScorecameFrom[neighbor] = current                  # 更新邻居的来路gScore[neighbor] = tentative_gScore           # 更新邻居的gScorefScore[neighbor] = gScore[neighbor] + heuristic(neighbor, goal)  # 更新邻居的fScoreif neighbor not in openSet                    # 如果邻居不在开放集中openSet.add(neighbor, fScore[neighbor])   # 将邻居加入开放集return failure                                            # 如果找不到路径,则返回失败

假设我们有一个简单的方格地图,目标是找到从起点到终点的最短路径。这里的启发式函数将使用曼哈顿距离,即从当前格子到目标格子在水平和垂直方向上的格子数之和。

地图如下:

S . . .
. # # .
. . . G
  • S 代表起点
  • G 代表目标终点
  • . 表示可以通行的路径
  • # 表示障碍物,不能通行

初始设置

  • 起点(S):坐标 (0, 0)
  • 终点(G):坐标 (2, 3)
  • 启发式函数(曼哈顿距离): ( h(x, y) = |x_2 - x_1| + |y_2 - y_1| )
  • gScore 初始为无穷大,除了起点为0
  • fScore 初始为无穷大,起点的 fScore 为启发式函数值 ( h(0, 0) = 5 )

算法执行步骤

  1. 初始化:将起点 S 放入开放集中。

  2. 第一步

    • 从开放集中取出 fScore 最小的节点,即起点 S。
    • 检查 S 的邻居:(1,0) 和 (0,1)。
    • 对于节点 (1,0):
      • gScore = 1 (从 S 到 (1,0) 的距离)
      • fScore = gScore + h(1,0) = 1 + 4 = 5
    • 对于节点 (0,1):
      • gScore = 1 (从 S 到 (0,1) 的距离)
      • fScore = gScore + h(0,1) = 1 + 4 = 5
    • 将这两个节点加入开放集。
  3. 后续步骤

    • 类似地,继续从开放集中取出 fScore 最小的节点。
    • 检查各节点的邻居,更新其 gScore 和 fScore。
    • 例如,从 (0,1) 走到 (0,2),然后走到 (0,3),最后走到 (1,3),每步 gScore 增加 1,更新 fScore。
  4. 到达终点

    • 当从开放集中取出的节点是终点 G 时,根据 cameFrom 映射重构路径。

路径重构

通过 cameFrom 映射可以找到从起点到终点的最短路径:S -> (0,1) -> (0,2) -> (0,3) -> (1,3) -> G。

这个例子说明了 A* 算法如何结合实际距离和启发式估计来找到有效的路径。通过每一步的选择,A* 算法能有效地规避障碍,同时朝向目标前进。

应用场景:在复杂的路径规划中的应用,特别是在有明确目标的场景中,如游戏中的角色路径规划。

A*算法广泛应用于各种路径规划场景,包括游戏中的角色路径规划、机器人导航、地图应用中的路线规划等。

比较与Dijkstra算法:讨论二者在不同场景下的效率和适用性。
  • 效率:在大多数情况下,A*算法比Dijkstra算法更快,因为它使用启发式减少了需要探索的节点数量。
  • 适用性:Dijkstra算法适合找到单个源到所有其他顶点的最短路径,而A*算法适合在有明确目标的情况下找到最短路径。

A*算法通过启发式函数的使用,在特定场景下提供了比Dijkstra算法更高效的路径查找解决方案。

4. 算法比较与实际应用
效率与复杂度:对比两种算法在不同类型图中的时间和空间复杂度。
  • Dijkstra算法:该算法的时间复杂度依赖于所使用的数据结构。使用优先级队列(通常是二叉堆)实现时,复杂度为 𝑂((𝑉+𝐸)log⁡𝑉)O((V+E)logV),其中 𝑉V 是顶点数,𝐸E 是边数。空间复杂度为 𝑂(𝑉)O(V),因为需要存储每个顶点的最短路径估计和优先级队列。
  • A*算法:理论上,A的时间复杂度在最坏情况下与Dijkstra算法相似,因为它也使用了优先级队列,并且可能遍历所有的 𝑉V* 个顶点和 𝐸E 条边。然而,由于启发式函数的指导,它通常会访问较少的顶点和边。其空间复杂度也为 𝑂(𝑉)O(V),主要是因为它需要存储已经访问和未访问的顶点信息。
选择适当的算法:根据实际需求决定使用哪种算法,例如根据图的大小、是否有负权边、是否需要最优路径等因素。
  • 图的大小和稠密度:对于较小或较稠密的图,Dijkstra算法或不带启发式函数的A算法(本质上等同于Dijkstra算法)可能表现良好。对于较大的图,尤其是当有明确目标点时,A算法通常更优,因为其启发式函数可以大大减少需要探索的顶点数量。
  • 是否有负权边:如果图中包含负权边,Dijkstra算法不适用。在这种情况下,需要考虑其他算法,如贝尔曼-福特算法。A*算法通常也不支持负权重,除非对启发式函数进行调整。
  • 是否需要最优路径:Dijkstra算法保证找到从单一源点到所有其他顶点的最短路径。而A*算法专注于从源点到一个特定目标的最短路径,其效率和准确性依赖于启发式函数的选择。
现代变体和改进:介绍这些经典算法的现代变体,如改进的A*算法。
  • 双向Dijkstra算法:这种变体从源点和目标点同时运行Dijkstra算法,直到两个搜索相遇。这可以在某些情况下减少需要探索的顶点和边的数量。
  • 双向A*算法:与双向Dijkstra类似,双向A*从两个方向搜索,并利用启发式函数来加速搜索过程。这通常可以进一步减少搜索空间和时间。
  • 时间依赖的路径规划:这些算法变体考虑了动态变化的边权重(如交通条件)。它们使用更复杂的数据结构来适应时间依赖性,以提供实时的最短路径决策。
  • 改进的启发式函数:为A*算法开发更有效的启发式函数,如动态调整的启发式,可以根据过去的搜索性能调整未来的启发式评估。
5. 实践与练习
案例研究:通过实际例子说明算法的应用,可能包括代码实现。
  1. A*算法在游戏中的路径规划

场景描述:在一款策略游戏中,A*算法被用来确定单位从一个位置移动到另一个位置的最短路径。地图被划分为网格,每个网格单元可能是可通行或不可通行的。

实现示例: 假设地图是一个二维网格,启发式函数使用曼哈顿距离(因为单位只能沿四个基本方向移动)。下面是Python的简化代码实现:

def heuristic(a, b):(x1, y1) = a(x2, y2) = breturn abs(x1 - x2) + abs(y1 - y2)def a_star_search(grid, start, goal):open_set = PriorityQueue()open_set.put(start, 0)came_from = {}g_score = {start: 0}f_score = {start: heuristic(start, goal)}while not open_set.empty():current = open_set.get()if current == goal:return reconstruct_path(came_from, current)for neighbor in neighbors(grid, current):tentative_g_score = g_score[current] + 1  # assuming each move has a cost of 1if neighbor not in g_score or tentative_g_score < g_score[neighbor]:came_from[neighbor] = currentg_score[neighbor] = tentative_g_scoref_score[neighbor] = tentative_g_score + heuristic(neighbor, goal)open_set.put(neighbor, f_score[neighbor])return failure# Helpers to reconstruct path and find neighbors would be needed

应用分析: 在这个例子中,A*算法能够有效地找到目标,即使在含有许多障碍物的复杂地图上。其效率得益于合适的启发式函数,这减少了不必要的探索。

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

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

相关文章

python mp3转mp4工具

成品UI 安装moviepy库 pip install moviepy 转换demo from moviepy.editor import *# 创建一个颜色剪辑&#xff0c;时长与音频相同 audioclip AudioFileClip(r"C:\Users\Administrator\PycharmProjects\pythonProject44\test4\赵照 - 灯塔守望人.mp3") videoclip…

联邦和反射器实验

拓扑图 一.实验要求 1.AS1存在两个环回&#xff0c;一个地址为192.168.1.0/24&#xff0c;该地址不能在任何协议中宣告 AS3存在两个环回&#xff0c;一个地址为192.168.2.0/24&#xff0c;该地址不能在任何协议中宣告 AS1还有一个环回地址为10.1.1.0/24&#xff…

区块链系统开发测试----链码部署开发、系统开发验证

一.检查配置环境 检查虚拟机环境&#xff0c;确保有正在运行的Hyperledger Fabric区块链&#xff0c;并且其中chaincode_basic、credit_chaincode链码可以正常调用 查看chaincode_basic、credit_chaincode链码调用 二.开发征信链码代码 基于现有征信链码&#xff0c;开发征信…

2024提升数字思维能力加快企业数字化转型(74页PPT)

方案介绍&#xff1a; 本报告的价值在于为企业提供了一套系统的提升数字思维能力、加快数字化转型的理论框架和实践指南。通过本报告的学习和应用&#xff0c;企业可以更加清晰地认识到数字化转型的重要性和紧迫性&#xff0c;明确自身在数字化转型中的优势和不足&#xff0c;并…

ROS2 Topics和Services

本文主要介绍ROS的Topics概念&#xff0c;如何创建Publisher和Subscriber&#xff0c;通过Topic在ROS程序间通信&#xff1b;介绍ROS的Services概念&#xff0c;如何创建Client和Server并建立通信。 更多内容&#xff0c;访问专栏目录获取实时更新。 ROS Topics Topics可以被视…

SpringJDBC

1.前言 Spring JDBC可以帮助开发者节省大量开发工作 自动去处理一些低级细节 比如&#xff1a;异常处理、打开和关闭资源(Connection、PreparedStatement、Statement、ResultSet) 需要下载的jar包&#xff1a; spring-jdbc(普通jar包、源码jar包)由于没有依赖其他的jar包 所以只…

vite+js配置

vite js 配置路径 npm install types/node --save-dev vite.config.js import { defineConfig } from vite import vue from vitejs/plugin-vue //需要引入 import path from path// https://vitejs.dev/config/ export default defineConfig({plugins: [vue()],resolve: {a…

WORD、PPT技巧

WORD技巧 编辑设置 word标题导航窗口怎么调出word2016&#xff0c;缩小了页面&#xff0c;可是怎么是竖着的一页一页排列啊&#xff1f;以前不是好几页横排着的么&#xff1f;怎么设置&#xff0c;求救&#xff1a;在Word标题栏那一行找到“视图”&#xff0c;点击“显示比例…

【算法】位运算算法——两整数之和

题解&#xff1a;两整数之和(位运算算法) 目录 1.题目2.位运算算法3.参考代码4.总结 1.题目 题目链接&#xff1a;LINK 2.位运算算法 这个题目难点就在于不能用、- 那什么能够代替加号呢&#xff1f; 既然数的层面不能用号&#xff0c;那二进制的角度去用号即可。 恰好&a…

FPGA——eMMC验证

一.FPGA基础 1.FPGA烧录流程 (1) 加载流文件 —— bitfile (2) 烧录文件 —— cmm 二.MMC 1.基础知识 (1)jz4740、mmc、emmc、sd之间的关系&#xff1f; jz4740——处理器 mmc——存储卡标准 emmc——mmc基础上发展的高效存储解决方案 sd—— 三.eMMC和SD case验证 1.ca…

MySQL数据表的“增删查改“

我们学习数据库, 最重要的就是要学会对数据表表进行"增删查改"(CRUD).(C -- create, R -- retrieve, U -- update, D -- delete) 目录 一. "增"(create) 1. 普通新增 2. 指定列新增 3. 一次插入多行 4. 用insert插入时间 5. 小结 二. "查"…

LuatOS学习

开发顺序 Lua是脚本语言中运行速度最快的语言 资源占用极低 脚本语言运行方式 脚本语言是从上往下一行一行运行的 变量 coun 123456 a,b,c 1,2,3交换 a,b b,a在测试环境中&#xff0c;用print(a,b)打印 nil类型 未声明的变量就是nil&#xff0c;nil用来表示此变量为空…

使用uniapp编写的微信小程序进行分包

简介&#xff1a; 由于小程序发布的时候每个包最多只能放置2MB的东西&#xff0c;所以把所有的代码资源都放置在一个主包当中不显示&#xff0c;所以就需要进行合理分包&#xff0c;&#xff0c;但是分包后整个小程序最终不能超过20MB。 一般情况下&#xff0c;我习惯将tabba…

ubuntu使用oh my zsh美化终端

ubuntu使用oh my zsh美化终端 文章目录 ubuntu使用oh my zsh美化终端1. 安装zsh和oh my zsh2. 修改zsh主题3. 安装zsh插件4. 将.bashrc移植到.zshrcReference 1. 安装zsh和oh my zsh 首先安装zsh sudo apt install zsh然后查看本地有哪些shell可以使用 cat /etc/shells 将默…

通过el-tree自定义渲染网页版工作目录,实现鼠标悬浮显示完整名称、用icon区分文件和文件夹等需求

目录 一、通过el-tree自定义渲染网页版工作目录 1.1、需求介绍 1.2、使用el-tree生成文档目录 1.2.1、官方基础用法 ①效果 ②代码&#xff1a; 1.2.2、自定义文档目录&#xff08;实现鼠标悬浮显示完整名称、用icon区分文件和文件夹&#xff09; ①效果&#xff08;直接效…

在winnas中使用docker desktop遇到的问题及解决方法记录

最近在尝试从群晖转向winnas&#xff0c;一些简单的服务依然计划使用docker来部署。群晖的docker简单易用且稳定&#xff0c;在win上使用docker desktop过程中遇到了不少问题&#xff0c;在此记录一下以供后来人参考。 一、安装docker desktop后启动时遇到无法启动docker引擎 …

5G专网驻网失败分析(suci无效)

suci 5G终端第一次驻网时&#xff0c;注册消息Registartion request中携带的5GS mobile identity要携带suci类型的mobile identity。 注册消息协议规范见5G NAS 协议3gpp TS24.501 8.2.6 Registration request。 suci协议规范参见3gpp TS24.501 9.11.3.4 5GS mobile identity …

常用批处理命令及批处理文件编写技巧

一常用批处理命令 1.查看命令用法&#xff1a;命令 /? //如&#xff1a;cd /? 2.切换盘符目录&#xff1a;cd /d D:\test 或直接输入 d: //进入上次d盘所在的目录 3.切换目录&#xff1a;cd test 4.清屏:cls 5.“arp -a” //它会列出当前设备缓存中的所有…

进程互斥经典问题(读写者问题、理发店问题)

目录 读写者问题 问题描述 问题分析 进程互斥问题三部曲 读者写者算法实现 一、找进程——确定进程关系 二、找主营业务 三、找同步约束 a.互斥 b.资源 c.配额 理发店问题 问题描述 问题分析 进程互斥问题三部曲 理发店问题算法实现 一、找进程——确定进程…

弘君资本股市行情:股指预计保持震荡上扬格局 关注汽车、银行等板块

弘君资本指出&#xff0c;近期商场体现全体分化&#xff0c;指数层面上看&#xff0c;沪指一路震动上行&#xff0c;创出年内新高&#xff0c;创业板指和科创50指数体现相对较弱&#xff0c;依然是底部震动走势。从盘面体现上看&#xff0c;轮动依然是当时商场的主基调&#xf…