路径规划——D*算法

news2024/9/22 23:24:49

路径规划——D*算法

D Star算法是一种用于动态环境下的算法,它可以在环境变化时快速更新路径。

算法原理

D Star算法是一种反向增量式搜索算法,反向即算法从目标点开始向起点逐步搜索;增量式搜索,即算法在搜索过程中会计算每一个节点的距离度量信息H(x),在动态环境中若出现障碍物无法继续沿预先路径搜索,算法会根据原先已经得到的每个点的距离度量信息在当前状态点进行路径再规划,无需从目标点进行重新规划。

算法流程:

1.起初,起点和终点的位置是已知的,环境中的障碍物未知或部分未知。初始化一个开放列表openlist(优先队列),将终点添加到该列表中,并将起点作为搜索目标。
2.在路径搜索过程中,D Star算法不使用启发信息,更像Dijkstra算法,由于是反向搜索,D Star算法计算每个节点到终点的成本代价,然后通过扩展节点来寻找从起点到终点的最优路径。在初次运行时,它使用Dijkstra算法生成一条从起点到终点的最短路径。
3.然而,当环境发生变化时,例如,检测到新的障碍物或路径变得不可通行时,要求算法可以动态更新路径。它通过回溯先前的路径,从遇到障碍物的节点开始重新计算新的路径。
4.在发生变化的区域重新执行D Star算法,从变化点开始,重新计算新的路径。D Star算法的一个关键特性是局部修复,即它只需要重新计算受到变化影响的部分路径,而不是整个路径。这使得算法在动态环境中能够高效地适应环境变化。
5.一旦路径更新完成,算法继续按照新的最短路径前进。每当环境再次变化时,重复上述步骤,直到达到终点。

D*算法有三个重要的函数:
1.process_state():该函数是用来降低openlist表中的某个节点x(state)的h(x)值或者传播节点x的h(x)值变更信息给邻居节点,让邻居节点进行相应变更的同时进行路径搜索查找的;
2.insert(x,val):该函数是用来修改节点x的状态以及h(x)值和k(x)值的;
3.modify_cost(x,y,val):该函数是用来修改节点x和y之间的移动代价cost(x,y),而且根据节点y的状态t(y)的情况,可能对节点y的h(y)值和状态t(y)进行修改的

函数process_state()是D*算法的核心,具体代码如下:

def process_state(self):
    node =self.min_state() # Find the node whose value of node.k is the smallest.
    self.searched.append(node.position)

    if node is None:
        return -1

    k_old = self.get_kmin() # Find the minimum node.k as k_old
    self.delete(node) # Delete the node from openlist, and modify node.t from 'OPEN' to 'CLOSE'

    neighbors, distances = self.get_neighbors(node)
    # RASIE State, its path cost may not be optimal
    if k_old < node.h:                                                                              
        for neighbor,distance in zip(neighbors,distances):                                          #
            if neighbor.h <= k_old and node.h > neighbor.h + distance:                              #
                node.parent = neighbor.position # Added obstacles, replanning, find better neighbor #
                node.h = neighbor.h + distance                                                      # 检查node的最优相邻状态,如果存在则降低 h 值

 	# LOWER State, its path cost is optimal since h ( X ) is equal to the old k_min .
    if k_old == node.h:
        for neighbor,distance in zip(neighbors,distances):
            if neighbor.t == 'NEW' or (neighbor.parent == node.position and neighbor.h != node.h+distance) \
            or (neighbor.parent != node.position and neighbor.h > node.h+distance):
                neighbor.parent = node.position # Searching commonly
                self.insert(neighbor,node.h+distance)
    else:
        for neighbor,distance in zip(neighbors,distances):
            if neighbor.t == 'NEW' or (neighbor.parent == node.position and neighbor.h != node.h+distance):
                neighbor.parent = node.position
                self.insert(neighbor,node.h+distance)
            else:
                if neighbor.parent != node.position and neighbor.h > node.h + distance:
                    self.insert(node,node.h)
                else:
                      if neighbor.parent != node.position and node.h > neighbor.h+distance \
                      and neighbor.t == 'CLOSED' and neighbor.h > k_old:
                          self.insert(neighbor,neighbor.h)

	return self.get_kmin()

下面解析此函数:

# RASIE State, its path cost may not be optimal
if k_old < node.h:                                                                              #
    for neighbor,distance in zip(neighbors,distances):                                          #
        if neighbor.h <= k_old and node.h > neighbor.h + distance:                              #
            node.parent = neighbor.position # Added obstacles, replanning, find better neighbor #
            node.h = neighbor.h + distance   

“RASIE”状态,其路径代价可能不是最优的,可以通过重新计算邻居节点来寻找最优路径;主要是在障碍物更新之后发挥作用。
当前访问的节点受到了新增障碍物的影响(比如,当前节点的父节点是新增障碍物),向h值越小的方向扩展,即从当前节点向靠近目标节点的方向扩展,并更新当前节点的父节点以更新路径.

# LOWER State, its path cost is optimal since h ( X ) is equal to the old k_min .
if k_old == node.h:
    for neighbor,distance in zip(neighbors,distances):
        if neighbor.t == 'NEW' or (neighbor.parent == node.position and neighbor.h != node.h+distance) \
        or (neighbor.parent != node.position and neighbor.h > node.h+distance):
            neighbor.parent = node.position # Searching commonly
            self.insert(neighbor,node.h+distance)

“LOWER”状态,其路径代价是最优的,正常搜索即可。
当前访问的节点还没有受新增障碍物的影响, 如果邻居节点neighbor的状态是"NEW"即未访问过, 或者邻居节点neighbor的父节点是当前节点node并且邻居节点的h值 不等于 当前节点的h值加上两节点间的距离,或者邻居节点neighbor的父节点不是当前节点node并且邻居节点的h值 大于 当前节点的h值加上两节点间的距离;那么!设邻居节点的父节点为当前节点,将neighbor节点放入openlist中进行访问搜索,并将其h值更新为当前节点的h值加上两节点间的距离.

else:
    for neighbor,distance in zip(neighbors,distances):
        if neighbor.t == 'NEW' or (neighbor.parent == node.position and neighbor.h != node.h+distance):
            neighbor.parent = node.position
            self.insert(neighbor,node.h+distance)
			// 如果邻居节点neighbor的状态是"NEW"即未访问过,
            // 或者邻居节点neighbor的父节点是当前节点node并且邻居节点的h值 大于 当前节点的h值加上两节点间的距离
            // 那么!设邻居节点的父节点为当前节点,并且将邻居节点的h值更新为当前节点的h值加上两节点间的距离,
            // 将neighbor节点放入openlist中进行访问搜索,也就是将采用从当前节点node经过neighbor节点的路径(此路径不一定是最终选择的路径)
        else:
			if neighbor.parent != node.position and neighbor.h > node.h + distance:
               	// 如果邻居节点neighbor的父节点不是当前访问节点node,
			    // 并且邻居节点的h值 大于 当前节点node的h值加上两节点间的距离,那么邻居节点不是“好点”,
			    // 为了更小的代价,便不应该从node经过neighbor,将node加入到openlist中重新访问搜索
				self.insert(node,node.h)
			else:
			     if neighbor.parent != node.position and node.h > neighbor.h+distance \
			     and neighbor.t == 'CLOSED' and neighbor.h > k_old:
			         self.insert(neighbor,neighbor.h)
	                 // 如果邻居节点neighbor的父节点不是当前访问节点node,并且邻居节点是个“好点”,
				     // 并且邻居节点的状态是“已访问”,同时邻居节点的h值 大于 k_old,这时node应该是新增的障碍物,
				     // 这时应该添加neighbor到openlist中,对其进行访问搜索

其他的情况,如果邻居是新的或其父节点是当前节点但代价不匹配,则更新父节点并插入开放列表。如果邻居的父节点不是当前节点且代价不匹配,则可能需要插入当前节点或邻居节点进行进一步处理。

函数**process_state()**理解起来是有一定难度的,逻辑思路有一定的复杂性,大家可以结合具体案例慢慢理解。

D*论文链接:https://ieeexplore.ieee.org/stamp/stamp.jsp?tp=&arnumber=351061

算法实现

"""
    Filename: dStar.py
    Description: Plan path using Dynamic A* Algorithm
    Author: Benxiaogu:https://github.com/Benxiaogu
    Date: 2024-08-29
"""

import math
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation
import time


class Node:
    """
    Class for D* nodes.

    Parameters:
        position (tuple): current coordinate
        parent (tuple): coordinate of parent node
        t (str): state of node, including `NEW` `OPEN` and `CLOSED`
                    'NEW': the node was never put into openlist;
                    'OPEN': the node is in openlist
                    'CLOSED': the node is no longer in openlist
        h (float): cost from goal to current node
        k (float): minimum cost from goal to current node in history
    """
    def __init__(self, position, parent, t, h, k) -> None:
        self.position = position
        self.parent = parent
        self.t = t
        self.h = h
        self.k = k

    def __add__(self, node):
        return Node((self.x + node.x, self.y + node.y), 
                     self.parent, self.t, self.h + node.h, self.k)
    
    def __eq__(self, other) -> bool:
        return self.position == other.position
        
    def __lt__(self,other):
        return self.k+self.h < other.k+other.h or (self.k+self.h==other.k+other.h and self.h<other.h)


class DStar:
    def __init__(self,grid,start,goal,board_size) -> None:
        self.grid = grid
        self.start = Node(start,None,'NEW',float('inf'),float('inf'))
        self.goal = Node(goal,None,'NEW',0,float('inf'))
        self.board_size = board_size
        self.path = []
        self.open = []
        self.searched = [] # Used to record nodes that are searched

        grid_map = []
        for i in range(len(self.grid)):
            for j in range(len(self.grid[0])):
                grid_map.append((i,j))

        self.map = {n: Node(n, None, 'NEW', float('inf'), float('inf')) for n in grid_map}
        self.map[self.goal.position] = self.goal
        self.map[self.start.position] = self.start
        self.insert(self.goal,0)

        self.fig, self.ax = plt.subplots()

    def run(self):
        cost = self.plan()
        self.fig.canvas.mpl_connect('button_press_event', self.update)
        self.visualize_grid(cost)

    def plan(self):
        while True:
            self.process_state()
            if self.start.t == 'CLOSED':
                break
        self.searched.clear()
        # Find the goal
        pathnode = self.start
        cost = 0
        self.path.append(pathnode.position)
        while pathnode != self.goal:
            nodeparent = self.map[pathnode.parent]
            cost += self.cost(pathnode, nodeparent)
            pathnode = nodeparent
            self.path.append(pathnode.position)
            
        return cost

    class Neighbor:
        def __init__(self,direction,cost):
            self.direction = direction
            self.cost = cost
    
    def get_neighbors(self, current_node):
        neighbors = []
        distances = []
        node = current_node.position
        nexts = [self.Neighbor((-1, 0),1), self.Neighbor((0, 1),1), self.Neighbor((0, -1),1), self.Neighbor((1,0),1),
                self.Neighbor((-1,1),math.sqrt(2)), self.Neighbor((1,1),math.sqrt(2)),self.Neighbor((1, -1),math.sqrt(2)), self.Neighbor((-1,-1),math.sqrt(2))]
        for next in nexts:
            neighbor = (node[0] + next.direction[0], node[1] + next.direction[1])
            neighborNode = self.map[neighbor]
            if not self.isCollision(node,neighbor):
                neighbors.append(neighborNode)
                distances.append(next.cost)

        return neighbors,distances
    
    def isCollision(self,node1,node2):
        """
            Check if there will be a collision from node1 to node2
        """
        if self.board_size <= node1[0] < len(self.grid)-self.board_size and self.board_size <= node1[1] < len(self.grid[0])-self.board_size \
                and self.board_size <= node2[0] < len(self.grid)-self.board_size and self.board_size <= node2[1] < len(self.grid[0])-self.board_size:
            if self.grid[node1[0]][node1[1]] == 0 and self.grid[node2[0]][node2[1]] == 0:
                direction1 = node1[0]-node2[0]
                direction2 = node1[1]-node2[1]
                if direction1 != 0 and direction2 != 0:  # 对角线方向
                    if self.grid[node1[0]][node2[1]] == 0 and self.grid[node2[0]][node1[1]] == 0:
                        return False
                else:
                    return False

        return True

    def process_state(self):
        """
            Compute optimal path costs to the goal
        """
        node =self.min_state() # Find the node whose value of node.k is the smallest.
        self.searched.append(node.position)

        if node is None:
            return -1

        k_old = self.get_kmin() # Find the minimum node.k as k_old
        self.delete(node) # Delete the node from openlist, and modify node.t from 'OPEN' to 'CLOSE'
        
        neighbors, distances = self.get_neighbors(node)
        # RASIE State, its path cost may not be optimal
        if k_old < node.h:                                                                              #
            for neighbor,distance in zip(neighbors,distances):                                          #
                if neighbor.h <= k_old and node.h > neighbor.h + distance:                              #
                    node.parent = neighbor.position # Added obstacles, replanning, find better neighbor #
                    node.h = neighbor.h + distance                                                      # 检查node的最优相邻状态,如果存在则降低 h 值
                   
        # LOWER State, its path cost is optimal since h ( X ) is equal to the old k_min .
        if k_old == node.h:
            for neighbor,distance in zip(neighbors,distances):
                if neighbor.t == 'NEW' or (neighbor.parent == node.position and neighbor.h != node.h+distance) \
                    or (neighbor.parent != node.position and neighbor.h > node.h+distance):
                    neighbor.parent = node.position # Searching commonly
                    self.insert(neighbor,node.h+distance)
                   
        else:
            for neighbor,distance in zip(neighbors,distances):
                if neighbor.t == 'NEW' or (neighbor.parent == node.position and neighbor.h != node.h+distance):
                    neighbor.parent = node.position
                    self.insert(neighbor,node.h+distance)
                else:
                    if neighbor.parent != node.position and neighbor.h > node.h + distance:
                        self.insert(node,node.h)
                    else:
                        if neighbor.parent != node.position and node.h > neighbor.h+distance \
                            and neighbor.t == 'CLOSED' and neighbor.h > k_old:
                            self.insert(neighbor,neighbor.h)
            

        return self.get_kmin()

    def min_state(self):
        """
            Return the node who possesses the minimum value of k.
        """
        if not self.open:
            return None
        min_state = min(self.open, key=lambda x: x.k)
        return min_state

    def get_kmin(self):
        """
            Return the minimum value of k.
        """
        if not self.open:
            return -1
        k_min = min([x.k for x in self.open])
        return k_min

    def delete(self, node) -> None:
        """
            Remove node from openlist, and change node.t from 'OPEN' to 'CLOSED'
        """
        if node.t == 'OPEN':
            node.t = 'CLOSED'
        self.open.remove(node)

    def insert(self, node: Node, h_new: float) -> None:
        """
            Modify the state of node as well as the node.h value and node.k value.
        """
        if node.t == 'NEW':         node.k = h_new
        elif node.t == 'OPEN':      node.k = min(node.k, h_new)
        elif node.t == 'CLOSED':    node.k = min(node.h, h_new)
        node.h = h_new
        node.t = 'OPEN'
        self.open.append(node)

    def modify_cost(self,node,node_parent):
        """
            Change the cost and enter affected nodes on the OPEN list.
        """
        if node.t == 'CLOSED':
            self.insert(node,node_parent.h+self.cost(node,node_parent))
        while True:
            k_min = self.process_state()
            if k_min >= node.h:
                break

    def cost(self, node1: Node, node2: Node) -> float:
        """
            Return Euclidean distance if there is no collision from node1 to node2 otherwise 'inf'
        """
        if self.isCollision(node1.position, node2.position):
            return float("inf")
        return math.hypot(node2.position[0] - node1.position[0], node2.position[1] - node1.position[1])

    def update(self, event) -> None:
        """
            Update obstacles and replan from affected node.
        """
        x, y = int(event.xdata), int(event.ydata)
        if y < self.board_size or y > len(self.grid) -self.board_size- 1 or x < self.board_size or x > len(self.grid[0])-self.board_size - 1:
            print("Please choose right area!")
        else:
            self.searched.clear()
            if self.grid[y][x] == 0:
                # update obstacles
                self.grid[y][x] = 1

                node = self.start
                cost = 0
                self.path.clear()
                while node != self.goal:
                    node_parent = self.map[node.parent]
                    if self.isCollision(node.position, node_parent.position): 
                        # when meeting collisions, call modify_cost() function
                        self.modify_cost(node,node_parent)
                        continue
                    self.path.append(node.position)
                    cost += self.cost(node, node_parent)
                    node = node_parent
                self.path.append(self.goal.position)

                plt.cla()
                self.visualize_grid(cost)

    def visualize_grid(self, cost):
        ...

在这里插入图片描述
完整代码:https://github.com/Benxiaogu/PathPlanning/tree/main/D_Star

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

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

相关文章

锋哥写一套前后端分离Python权限系统 基于Django5+DRF+Vue3.2+Element Plus+Jwt 视频教程 ,帅呆了~~

大家好&#xff0c;我是java1234_小锋老师&#xff0c;最近写了一套【前后端分离Python权限系统 基于Django5DRFVue3.2Element PlusJwt 】视频教程&#xff0c;持续更新中&#xff0c;计划月底更新完&#xff0c;感谢支持。 视频在线地址&#xff1a; 打造前后端分离Python权…

Java超详细知识点——I/O流(字节流和字符流)

File类&#xff1a; Java API&#xff1a;java.io.File 类 是用来操作文件或文件夹的&#xff0c;无法用来读写 1.首先创建一下file的对象&#xff1a; 里面可以写相对路径或者绝对路径 File file new File("CCC.java"); 也可以使用其他构造方法 //String path …

【计算机网络】电路交换、报文交换和分组交换——三种交换方式性能分析以及计算机网络的分类

【计算机网络】电路交换、电报交换、分组交换 目录 【计算机网络】电路交换、电报交换、分组交换1. 电路交换2. 电报交换3. 分组交换4. 基于分组交换~“虚电路交换”技术 【计算机网络】电路交换、报文交换和分组交换——三种交换方式性能分析电路交换性能分析报文交换性能分析…

在AD域中恢复被删除的账户(LDP.EXE)

在域账户被不小心删除后&#xff0c;客户端使用域账号登陆会失败&#xff0c;账号不存在&#xff1b; 为了客户端登陆回原来账户文件下面&#xff0c;重新创建一个相同账户&#xff0c;域中此新账号的ID是新的&#xff0c;客户端登陆也会按新用户生成用户文件&#xff1b;同样复…

只用一个 HTML 元素可以写出多少形状?——动画篇

为期一个多月&#xff0c;我们针对只用一个 div 元素一共可以写出多少种形状的话题&#xff0c;通过六个篇章&#xff08;分了八篇文章&#xff09;进行了详细的展开。 其中&#xff0c;前三个篇章&#xff0c;我们主要围绕欧几里得几何中的基本形状做的展开&#xff0c;其中蕴…

基于Matlab和OpenCV的双目测距(标定和代码教程)

基于Matlab和OpenCV的双目测距研究 *摘要*&#xff1a;双目测距的原理是利用左右两个摄像机拍摄同一物体形成的视差来确定物体距摄像机的距离。这其中需要通过标定得出的参数包括内参&#xff08;焦距fc, 主点Principal point, 径向畸变Radial Distortion, 切向畸变Tangential…

828华为云征文 | 使用Flexus云服务器X实例部署Kubernetes图形化管理平台

828华为云征文 | 使用Flexus云服务器X实例部署Kubernetes图形化管理平台 1. 基础部署环境说明2. 部署Kubernetes环境3. 部署Kubernetes Dashboard4. 创建登录账号token5. 访问Kubernetes Dashboard 1. 基础部署环境说明 Kubernetes作为当今最流行的容器编排平台&#xff0c;随着…

【Kubernetes】常见面试题汇总(七)

目录 20.简述 Kubernetes 创建一个 Pod 的主要流程&#xff1f; 21.简述 Kubernetes 中 Pod 的重启策略&#xff1f; 20.简述 Kubernetes 创建一个 Pod 的主要流程&#xff1f; Kubernetes 中创建一个 Pod 涉及多个组件之间联动&#xff0c;主要流程如下&#xff1a; &#…

如何让Google收录我的网站?

其实仅仅只是收录&#xff0c;只要在GSC提交网址&#xff0c;等个两三天&#xff0c;一般就能收录&#xff0c;但收录是否会掉&#xff0c;这篇内容收录了是否有展现&#xff0c;排名&#xff0c;就是另外一个课题了&#xff0c;如果不收录&#xff0c;除了说明你的网站有问题&…

人工智能赋能千行百业

人工智能将赋能千行百业 人工智能&#xff08;AI&#xff09;作为当今科技领域的核心驱动力之一&#xff0c;正以前所未有的速度和广度赋能千行百业&#xff0c;深刻改变着我们的生产、生活方式以及社会经济的运行模式。以下是人工智能在多个行业中的赋能作用的几个关键方面&am…

QT多个界面

主函数 #include "widget.h" #include "second.h" #include <QApplication>int main(int argc, char *argv[]) {QApplication a(argc, argv);Widget w;Second s;QObject::connect(&w,&Widget::my_signals,&s,&Second::my_slots);w.…

全面质量管理知识竞赛题库

全面质量管理知识竞赛题库 第 1 章 质量 三、单项选择题 1.根据 ISO9000 标准的定义&#xff0c;“质量”是指“客体的一组固有特性满足要求的程度”&#xff0c;以下&#xff08; B &#xff09;不属于产 品的“固有特性”。 A.产品的寿命 B.产品的价格 C.产品制造和使用的…

民宿|基于java的民宿推荐系统(源码+数据库+文档)

民宿推荐系统 目录 基于java的民宿推荐系统 一、前言 二、系统设计 三、系统功能设计 系统功能实现 前台&#xff1a; 后台&#xff1a; 四、数据库设计 五、核心代码 六、论文参考 七、最新计算机毕设选题推荐 八、源码获取&#xff1a; 博主介绍&#xff1a;✌…

react-问卷星项目(1)

学习的一位MOOC老师的经验&#xff0c;记录一下学习的过程 本项目技术栈&#xff1a;React18TS4AntDesign5Next.js13 项目&#xff1a;低代码&#xff0c;B/C react官方文档 核心价值&#xff1a; 组件化&#xff1a;不是React原创&#xff0c;但在React中流行开来 数据驱…

怎么用python打开文件

python文件读写文件是最常见的IO操作。Python内置了读写文件的函数&#xff0c;用法和C是兼容的。 读写文件前&#xff0c;我们先必须了解一下&#xff0c;在磁盘上读写文件的功能都是由操作系统提供的&#xff0c;现代操作系统不允许普通的程序直接操作磁盘。 读写文件就是请…

使用java对栅格数据的处理,对栅格文件进行导入导出

需求背景&#xff1a; 对栅格文件进行导入导出&#xff08;使用代码的方式&#xff0c;非命令方式&#xff09;&#xff1b; 当然也可以使用代码和GDAL的方式进行&#xff0c;但是GDAL配置部署不便捷&#xff0c;故选用GeoTools方式来实现。 ps&#xff1a;若是使用命令方式&am…

大模型api谁家更便宜

1 openai 可点此链接查询价格&#xff1a;https://openai.com/api/pricing/ 2 百度 可点此链接查询价格&#xff1a;https://console.bce.baidu.com/qianfan/chargemanage/list 需要注意&#xff0c;百度千帆平台上还提供其他家的模型调用服务&#xff0c; 如llama, yi-34b等…

IDE快速复制文件名

在很多情况下我们需要复制IDE中文件的名称&#xff0c;习惯性的F2却不能重命名 如图操作又比较繁琐 解决方法⭐⭐⭐ 其实直接CtrlC可以复制文件名&#x1f921;&#x1f921;&#x1f921;

7-Zip压缩包如何添加密码,加密后如何取消

压缩包文件大家经常使用&#xff0c;最熟悉的肯定是RAR、ZIP格式压缩文件&#xff0c;但是7z压缩文件格式也很好用&#xff0c;它是三种压缩文件格式中压缩率最大的。想要将文件压缩到最小&#xff0c;使用7z格式可以达到最大化。那么在使用7z压缩格式的时候&#xff0c;我们可…

银河麒麟V10系统软件商店手动更新方法

银河麒麟桌面操作系统V10重新安装之后&#xff0c;有些软件商店未能及时的自动更新&#xff0c;从而软件商店里无法获取最新的软件应用&#xff0c;这个时候就需要我们手动的进行升级更新一下软件商店了&#xff0c;更新之后软件商店里的内容就会增加不少&#xff0c;那么&…