游戏AI的创造思路-技术基础-遗传算法

news2024/11/23 2:51:20

遗传算法,选对了遗传算子,那就是优秀的继承者,选错了,那就是传说在祸害遗千年~~~~~

目录

1. 定义

2. 发展历史

3. 遗传算法的基本原理和流程

3.1. 基本原理

3.1.1.基本原理

3.1.2. 算法流程

3.1.3. 关键要素

3.2. 函数和方法

3.2.1. 适应度函数(Fitness Function)

3.2.2. 选择函数(Selection Function)

3.2.3. 交叉函数(Crossover Function)

3.2.4. 变异函数(Mutation Function)

3.2.5. 辅助函数

3.2.6. Python实现示例(概念性)

3.3. Python实现代码

4. 遗传算法的优缺点

5. 在游戏中的应用实例

5.1. 概述

5.2. 举个例子

5.2.1. 猜数字游戏

5.2.2. 遗传算法设计

5.2.3. Python 实现

6. 对比退火算法

6.1. 基本原理

6.2. 操作方式

6.3. 应用场景

6.4. 优缺点比较

6.5. 对比结果


1. 定义

遗传算法(Genetic Algorithms, GA)是一种模拟自然选择和遗传学机制的搜索算法。

它通过模拟生物进化过程中的选择、交叉(杂交)和变异等操作来求解优化问题。

2. 发展历史

遗传算法的概念起源于20世纪60年代,由美国密歇根大学的John Holland教授及其学生首次提出。

经过几十年的发展,遗传算法已经被广泛应用于各种优化和搜索问题中。

3. 遗传算法的基本原理和流程

3.1. 基本原理

3.1.1.基本原理

遗传算法是一种基于自然选择和群体遗传机理的搜索算法,它模拟了自然选择和自然遗传过程中的繁殖、杂交和突变现象。在遗传算法中,问题的每一个可能解都被编码成一个“染色体”,即个体,若干个个体构成了群体(所有可能解)。遗传算法通过迭代的方式,逐步优化群体中的个体,最终找到问题的最优解或近似最优解。

3.1.2. 算法流程

遗传算法的基本流程通常包括以下几个步骤:

  1. 初始化:随机生成一定数量的个体作为初始种群。
  2. 个体评价:计算种群中每个个体的适应度值。适应度函数是根据问题的目标函数设计的,用于评估个体的优劣。
  3. 选择运算:根据个体的适应度值,选择一部分优秀个体作为父代,用于产生下一代种群。选择操作体现了“适者生存”的原理。
  4. 交叉运算:将选中的父代个体进行交叉操作,生成新的个体。交叉操作模拟了生物繁殖过程中的基因重组现象,是遗传算法产生新个体的主要手段。
  5. 变异运算:以一定的概率对种群中的个体进行变异操作,改变其某些基因的值。变异操作模拟了生物进化过程中的基因突变现象,增加了种群的多样性,有助于算法跳出局部最优解。
  6. 终止条件判断:判断算法是否满足终止条件(如达到最大进化代数、找到满足精度的解等)。如果满足终止条件,则算法结束;否则,返回步骤2继续迭代。

3.1.3. 关键要素

  1. 编码:将问题的解空间映射到遗传算法的搜索空间,即对问题的解进行编码。常用的编码方式有二进制编码、实数编码等。
  2. 适应度函数:用于评估个体的适应度值,是遗传算法进行个体选择的依据。适应度函数的设计应根据问题的目标函数来确定。
  3. 遗传算子:包括选择算子、交叉算子和变异算子。这些算子模拟了生物进化过程中的选择、交叉和变异现象,是遗传算法实现优化搜索的关键。

3.2. 函数和方法

在遗传算法中,并没有特定的“公式”来直接解决问题,而是依赖于一系列的操作和函数来迭代优化解集。以下是遗传算法中常用的函数和这些函数的基本描述:

3.2.1. 适应度函数(Fitness Function)

  • 定义:适应度函数是遗传算法中最重要的函数之一,用于评估每个个体的适应度表现。它通常基于个体的目标函数值或其他特定的性能指标来计算个体的适应度得分。
  • 作用:适应度函数决定了哪些个体更有可能被选中进行繁殖,从而影响算法的搜索方向和速度。

3.2.2. 选择函数(Selection Function)

  • 定义:选择函数用于根据适应度得分排名,选择一些个体作为繁殖下一代的“父代”。
  • 常用方法:轮盘赌选择、锦标赛选择、最佳选择等。这些方法基于个体的适应度得分,以不同的概率选择个体。

3.2.3. 交叉函数(Crossover Function)

  • 定义:交叉函数用于将父代的染色体段进行随机交叉,产生新的个体组合,从而丰富种群的性状。
  • 常用方法:单点交叉、多点交叉、均匀交叉等。这些方法在父代染色体上随机选择交叉点,并交换交叉点两侧的部分基因。

3.2.4. 变异函数(Mutation Function)

  • 定义:变异函数用于随机改变个体的染色体上的某些位点,以提高搜索空间的探索性和多样性。
  • 常用方法:基本变异、非一致性变异、可逆变异等。这些方法以一定的概率随机改变个体的某些基因值。

3.2.5. 辅助函数

除了上述核心函数外,遗传算法还可能涉及一些辅助函数,如种群初始化函数、终止条件判定函数等。这些函数用于初始化种群、设置算法的运行参数和判断算法的终止条件等。

3.2.6. Python实现示例(概念性)

虽然无法直接给出遗传算法的完整Python实现代码(因为这取决于具体问题的编码和适应度函数的设计),但可以提供一些概念性的代码片段来说明这些函数是如何在遗传算法中工作的。

# 假设fitness_function是已经定义的适应度函数  
# population是种群,个体以某种编码形式表示(如二进制串)  
  
def selection(population, fitnesses):  
    # 根据适应度选择个体,这里以轮盘赌选择为例  
    # ...(实现轮盘赌选择的代码)  
    return selected_individuals  
  
def crossover(parent1, parent2):  
    # 对两个父代个体进行交叉操作,生成子代  
    # ...(实现交叉操作的代码,如单点交叉)  
    return child1, child2  
  
def mutation(individual, mutation_rate):  
    # 对个体进行变异操作  
    # ...(实现变异操作的代码)  
    return mutated_individual  
  
# 遗传算法主循环(概念性)  
for generation in range(num_generations):  
    fitnesses = [fitness_function(ind) for ind in population]  
    selected = selection(population, fitnesses)  
    offspring = []  
    for i in range(0, len(selected), 2):  
        parent1, parent2 = selected[i], selected[i+1]  
        child1, child2 = crossover(parent1, parent2)  
        offspring.append(mutation(child1, mutation_rate))  
        offspring.append(mutation(child2, mutation_rate))  
    # 可能还需要一些额外的逻辑来处理种群大小不变的情况  
    # ...  
    population = offspring  # 或者基于某种策略合并父代和子代

 上述代码是概念性的,并没有直接运行的能力。在实际应用中,您需要根据具体问题来定义适应度函数、编码方案、选择、交叉和变异等操作的具体实现。

3.3. Python实现代码

以下是一个简单的遗传算法实现,用于优化一个简单的函数:

import numpy as np  
  
# 假设的游戏适应度函数  
def game_fitness(individual):  
    # 个体是一个二进制串,适应度是其中1的个数  
    return np.sum(individual),  
  
# 选择操作:轮盘赌选择  
def selection(population, fitnesses, num_parents):  
    fitnesses = np.array(fitnesses)  
    total_fitness = np.sum(fitnesses)  
    probabilities = fitnesses / total_fitness  
    indices = np.random.choice(np.arange(len(population)), size=num_parents, replace=False, p=probabilities)  
    return population[indices]  
  
# 交叉操作:单点交叉  
def crossover(parents, num_children):  
    children = []  
    for _ in range(num_children // 2):  
        parent1, parent2 = np.random.choice(parents, 2, replace=False)  
        cross_point = np.random.randint(len(parent1))  
        child1 = np.concatenate([parent1[:cross_point], parent2[cross_point:]])  
        child2 = np.concatenate([parent2[:cross_point], parent1[cross_point:]])  
        children.extend([child1, child2])  
    return np.array(children)  
  
# 变异操作  
def mutation(individual, mutation_rate=0.01):  
    for i in range(len(individual)):  
        if np.random.rand() < mutation_rate:  
            individual[i] = 1 - individual[i]  # 翻转基因  
    return individual  
  
# 遗传算法主函数  
def genetic_algorithm(num_generations, population_size, num_parents, num_children, mutation_rate):  
    population = np.random.randint(0, 2, (population_size, 10))  # 假设个体长度为10  
    for generation in range(num_generations):  
        fitnesses = np.array([game_fitness(individual)[0] for individual in population])  
        parents = selection(population, fitnesses, num_parents)  
        children = crossover(parents, num_children)  
        for i in range(len(children)):  
            children[i] = mutation(children[i], mutation_rate)  
        population = np.concatenate([parents, children])[:population_size]  
        print(f"Generation {generation}: Best Fitness = {np.max(fitnesses)}")  
    return population[np.argmax(fitnesses)]  
  
# 运行遗传算法  
best_individual = genetic_algorithm(num_generations=100, population_size=100, num_parents=20, num_children=80, mutation_rate=0.01)  
print("Best Individual:", best_individual)

在这个例子中,我们定义了一个简单的游戏适应度函数,它计算个体中1的个数作为适应度。

然后,我们实现了选择、交叉和变异操作,并在遗传算法主函数中迭代地应用这些操作来优化种群。

最后,我们输出了最优个体和其对应的适应度。

4. 遗传算法的优缺点

优点

  • 全局搜索能力强:通过交叉和变异操作,遗传算法能够在整个解空间内进行搜索,避免陷入局部最优解。
  • 并行性好:遗传算法采用种群的方式组织搜索,可以同时处理多个解,提高了搜索效率。
  • 鲁棒性强:遗传算法对问题的依赖性小,只需要根据问题的目标函数设计适应度函数即可,无需对问题进行过多的数学处理。
  • 易于实现:遗传算法的流程简单,易于编程实现,且不需要复杂的数学推导和证明。
  • 通用性强:可以应用于多种类型的问题,可以处理离散和连续变量。

缺点

  • 编程实现比较复杂。
  • 容易过早收敛到局部最优解。
  • 参数(如交叉率、变异率)的选择对算法性能有很大影响。

5. 在游戏中的应用实例

5.1. 概述

遗传算法在游戏AI中常用于生成内容、策略优化和自动游戏测试等。

例如,可以使用遗传算法来优化游戏中的NPC行为策略,使其更加智能和逼真。

通过定义适应度函数来评估不同策略的效果,然后使用遗传算法来搜索最优策略。

5.2. 举个例子

遗传算法在游戏AI中的应用通常涉及优化游戏策略或行为决策。以下是一个简单的例子,我们将使用遗传算法来训练一个AI,使其在玩一个简单的猜数字游戏时能够更有效地猜测数字。

5.2.1. 猜数字游戏

游戏规则如下:

  • 游戏有一个目标数字,范围是0到100。
  • AI每次猜测一个数字,游戏会告诉AI它的猜测是太高、太低还是正确。
  • AI的目标是尽可能少地猜测次数内找到目标数字。

5.2.2. 遗传算法设计

  1. 个体表示:每个个体是一个包含100个基因的二进制串,每个基因代表一个数字(0-99),如果某个基因位为1,则表示AI会猜测这个数字。

  2. 适应度函数:适应度函数计算个体在猜数字游戏中的表现,即猜测次数越少,适应度越高。

  3. 选择:使用轮盘赌选择方法。

  4. 交叉:使用单点交叉。

  5. 变异:随机翻转某个基因位。

5.2.3. Python 实现

 

import numpy as np  
  
# 参数设置  
POP_SIZE = 100        # 种群大小  
GENES = 100           # 基因数量(代表0-99的数字)  
MAX_GUESSES = 20      # 最大猜测次数  
MUTATION_RATE = 0.01  # 变异率  
NUM_GENERATIONS = 50  # 进化代数  
TARGET = 42           # 目标数字  
  
# 适应度函数  
def fitness(individual):  
    guesses = 0  
    for i in range(GENES):  
        if individual[i] == 1:  
            guesses += 1  
            if i == TARGET:  
                return 1 / guesses  # 猜测次数越少,适应度越高  
    return 0  # 没有猜对则适应度为0  
  
# 选择函数  
def select(population, fitnesses):  
    total_fitness = sum(fitnesses)  
    pick = np.random.rand() * total_fitness  
    current = 0  
    for i, fitness in enumerate(fitnesses):  
        current += fitness  
        if current > pick:  
            return population[i]  
  
# 交叉函数  
def crossover(parent1, parent2):  
    crossover_point = np.random.randint(0, GENES)  
    child1 = parent1[:crossover_point] + parent2[crossover_point:]  
    child2 = parent2[:crossover_point] + parent1[crossover_point:]  
    return child1, child2  
  
# 变异函数  
def mutation(individual):  
    for i in range(GENES):  
        if np.random.rand() < MUTATION_RATE:  
            individual[i] = 1 - individual[i]  
    return individual  
  
# 初始化种群  
population = [[np.random.randint(0, 2) for _ in range(GENES)] for _ in range(POP_SIZE)]  
  
# 遗传算法主循环  
for generation in range(NUM_GENERATIONS):  
    fitnesses = [fitness(ind) for ind in population]  
    new_population = []  
    for _ in range(POP_SIZE // 2):  # 生成新种群,因为每次交叉产生两个后代  
        parent1 = select(population, fitnesses)  
        parent2 = select(population, fitnesses)  
        child1, child2 = crossover(parent1, parent2)  
        new_population.append(mutation(child1))  
        new_population.append(mutation(child2))  
    population = new_population  
      
    # 输出当前代的最佳适应度和对应的猜测次数  
    best_fitness = max(fitnesses)  
    best_guesses = int(1 / best_fitness) if best_fitness > 0 else MAX_GUESSES + 1  
    print(f"Generation {generation}: Best Fitness = {best_fitness}, Best Guesses = {best_guesses}")  
  
# 输出最终的最佳个体和猜测次数  
best_individual = max(population, key=fitness)  
best_guesses = sum(best_individual)  
print(f"Best Individual: {best_individual}")  
print(f"Best Guesses: {best_guesses}")

这段代码实现了一个简单的遗传算法来训练AI玩猜数字游戏。

每一代中,算法都会评估种群中每个个体的适应度,选择适应度高的个体进行交叉和变异,生成新的种群。

最终,算法会输出一个最佳个体,它代表了AI在猜数字游戏中的最优策略。


6. 对比退火算法

 遗传算法(Genetic Algorithm, GA)和模拟退火算法(Simulated Annealing, SA)是两种常用的优化算法,它们在原理、操作方式及应用场景上存在一定的区别。以下是两者的详细比较:

6.1. 基本原理

模拟退火算法

  • 模拟退火算法是一种基于物理退火过程的随机搜索和优化算法。它模拟了固体退火过程中温度逐渐降低,系统内部能量趋于最小的过程,通过接受一定概率的劣解来跳出局部最优解,从而找到全局最优解或接近全局最优的解。
  • 模拟退火算法的主要操作包括初始化温度、生成新解、计算能量差、计算接受概率以及接受或拒绝新解,并逐步降低温度直至收敛。

6.2. 操作方式

模拟退火算法

  • 单个体搜索:模拟退火算法通常以一个解作为当前状态进行搜索。
  • 随机性:模拟退火算法通过引入随机性来接受一定概率的劣解,从而跳出局部最优解。
  • 温度控制:模拟退火算法通过逐步降低温度来控制搜索过程,温度越高接受劣解的概率越大,温度越低接受劣解的概率越小。

6.3. 应用场景

遗传算法

  • 遗传算法适用于处理传统搜索方法难以解决的复杂和非线性问题,如函数优化、自动控制、图像识别、机器学习等。
  • 遗传算法具有广泛的应用范围,不受问题领域的限制,只需根据问题的目标函数设计适应度函数即可。

模拟退火算法

  • 模拟退火算法同样适用于解决组合优化问题,如旅行商问题、排课问题等。
  • 模拟退火算法通过引入随机性和温度参数来克服传统优化算法容易陷入局部最小值的问题,从而找到全局最优解或接近全局最优的解。

6.4. 优缺点比较

遗传算法的优点

  • 全局搜索能力强,不易陷入局部最优解。
  • 并行性好,搜索效率高。
  • 对问题领域无限制,适用范围广泛。

遗传算法的缺点

  • 编程实现较复杂,需要对问题进行编码和解码。
  • 算法参数(如交叉率、变异率)的选择对解的品质影响较大,且目前大部分依赖于经验。
  • 在实际应用中容易产生早熟收敛的问题。

模拟退火算法的优点

  • 能够以随机搜索技术从概率的意义上找出目标函数的全局最小点。
  • 具有摆脱局部最优解的能力。

模拟退火算法的缺点

  • 优化过程长,效率不高。
  • 温度参数的控制对算法性能有较大影响。

6.5. 对比结果

综上所述,遗传算法和模拟退火算法在基本原理、操作方式及应用场景上存在一定的区别。

在实际应用中,可以根据问题的具体特点选择合适的算法进行优化求解。

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

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

相关文章

栈和队列---循环队列

1.循环队列的出现 &#xff08;1&#xff09;上面的这个就是一个普通的数据的入队和出队的过程我们正常情况下去实现这个入队和出队的过程&#xff0c;就是这个数据从这个队尾进入&#xff0c;从队头离开&#xff0c;但是这个加入的时候肯定是没有其他的问题的&#xff0c;直接…

Java多线程不会?一文解决——

方法一 新建类如MyThread继承Thread类重写run()方法再通过new MyThread类来新建线程通过start方法启动新线程 案例&#xff1a; class MyThread extends Thread {public MyThread(String name) {super(name);}Overridepublic void run() {for(int i0;i<10;i){System.out.…

java项目总结8

1.方法引用 1.方法引用概述 注意注意&#xff1a; 1.引用出必须是函数式接口 2.被引用的方法必须已经存在 3.被引用方法的型参和返回值需要跟抽象方法保持一致 4.被引方法的功能要满足当前需求 Arrays.sort(arr,Main::subtraction); Main是该类的名称&#xff0c;&#xff1a…

代码随想录算法训练营第二十七天 |56. 合并区间 738.单调递增的数字 968.监控二叉树 (可跳过)

56. 合并区间 以数组 intervals 表示若干个区间的集合&#xff0c;其中单个区间为 intervals[i] [starti, endi] 。请你合并所有重叠的区间&#xff0c;并返回 一个不重叠的区间数组&#xff0c;该数组需恰好覆盖输入中的所有区间 。 示例 1&#xff1a; 输入&#xff1a;in…

linux固定主机ip

1.查看虚拟网络配置 NAT设置&#xff1a; 2.修改网卡配置文件 [rootlocalhost ~]# vim /etc/sysconfig/network-scripts/ifcfg-ens33 TYPE"Ethernet" PROXY_METHOD"none" BROWSER_ONLY"no" BOOTPROTO"static" DEFROUTE"yes"…

PD虚拟机不能复制Mac的文件怎么回事 PD虚拟机不能复制Mac的文件怎么办 Parallels Desktop怎么用

PD虚拟机不仅能提供跨系统协作的服务&#xff0c;还能进行虚拟机系统与原生系统间的文件共享、文本复制、文件复制等操作&#xff0c;让系统间的资源可以科学利用。但在实际操作过程中&#xff0c;PD虚拟机不能复制Mac的文件怎么回事&#xff1f;PD虚拟机不能复制Mac的文件怎么…

PDM系统中物料分类与编码规则生成方案

在企业管理软件中&#xff0c;PDM系统是企业管理的前端软件&#xff0c;用于管理研发图纸、BOM等数据&#xff0c;然后生成相关物料表或BOM&#xff0c;递交给后端ERP系统进行生产管理。在PDM系统中&#xff0c;有两种方式可以生成物料编码。 1第一种是用户可以通过软件接口将…

Open3D 点云的圆柱形邻域搜索

目录 一、概述 1.1原理 1.2应用 二、代码实现 2.1完整代码 2.2程序说明 三、实现效果 3.1原始点云 3.2搜索后点云 一、概述 1.1原理 圆柱邻域搜索的基本思想是确定点云中的哪些点位于给定圆柱的内部。一个圆柱可以由以下几个参数定义&#xff1a; 中心点&#xff1a;…

RedHat9 | Zabbix-Server监控服务部署

系统版本以及软件版本 使用的系统版本&#xff1a; Red Hat Enterprise Linux release 9.2 软件版本&#xff1a; zabbix-release-7.0-3.el9.noarchzabbix-web-7.0.0-release1.el9.noarchzabbix-web-mysql-7.0.0-release1.el9.noarchzabbix-web-deps-7.0.0-release1.el9.noar…

Vue3+.NET6前后端分离式管理后台实战(二十七)

1&#xff0c;Vue3.NET6前后端分离式管理后台实战(二十七)

C++ 函数高级——函数重载——基本语法

作用&#xff1a;函数名可以相同&#xff0c;提高复用性 函数重载满足条件&#xff1a; 1.同一个作用域下 2.函数名称相同 3.函数参数类型不同 或者 个数不同 或者 顺序不同 注意&#xff1a;函数的返回值不可以作为函数重载的条件 示例&#xff1a; 运行结果&#xff1a;

排序格式排序格式

排序格式排序格式

探讨4层代理和7层代理行为以及如何获取真实客户端IP

准备工作 实验环境 IP角色192.168.1.100客户端请求IP192.168.1.100python 启动的HTTP服务192.168.1.102nginx服务192.168.1.103haproxy 服务 HTTP服务 这是一个简单的HTTP服务&#xff0c;主要打印HTTP报文用于分析客户端IP #!/usr/bin/env python # coding: utf-8import …

【c++刷题笔记-数组】day29:452. 用最少数量的箭引爆气球、 435. 无重叠区间 、 763.划分字母区间

452. 用最少数量的箭引爆气球 - 力扣&#xff08;LeetCode&#xff09; 思路&#xff1a;先按照左边界排序&#xff0c;当前的左边界大于前一个的右边界的时候&#xff0c;表示没有覆盖所以需要一根箭&#xff0c;反之则要更新为最小的右边界 重点&#xff1a;是区间覆盖问题…

FMEA在大型光伏电站安全生产管理中的应用

一、FMEA概述 FMEA&#xff08;Failure Modes and Effects Analysis&#xff09;即失效模式和影响分析&#xff0c;是一种用于识别和分析产品或过程中潜在故障模式及其影响的方法。它通过对产品或过程中可能出现的故障模式进行系统性地梳理和分析&#xff0c;评估其可能的影响…

Day59 动态规划part12

LC115不同的子序列&#xff08;未掌握&#xff09; 递推公式与LC392类似&#xff0c;但是初始化略有不同 LC392的dp数组含义为相同字符个数而本体的dp数组含义为出现的次数&#xff0c;因此dp[i][0]1 两种情况 s[i-1]t[j-1] dp[i][j] dp[i-1][j-1]dp[i][j] dp[i-1][j] s[…

CosyVoice - 阿里最新开源语音克隆、文本转语音项目 支持情感控制及粤语 本地一键整合包下载

近日&#xff0c;阿里通义实验室发布开源语音大模型项目FunAudioLLM&#xff0c;而且一次包含两个模型&#xff1a;SenseVoice和CosyVoice。 CosyVoice专注自然语音生成&#xff0c;支持多语言、音色和情感控制&#xff0c;支持中英日粤韩5种语言的生成&#xff0c;效果显著优于…

JAVA集合框架、CAS、AQS

目录 一、java 的集合框架有哪些? 二、说-下 ArrayList 和 LinkedList? 三、HashSet和TreeSet的区别? 四、HashMap 的数据结构是什么? 五、CAS机制 六、AQS理解 一、java 的集合框架有哪些? Collection 是 Java 集合框架中的一个根接口&#xff0c;位于 java.util 包中。它…

那些年背过的面试题——MySQL篇

本文是技术人面试系列 MySQL 篇&#xff0c;面试中关于 MySQL 都需要了解哪些基础&#xff1f;一文带你详细了解&#xff0c;欢迎收藏&#xff01; WhyMysql&#xff1f; NoSQL 数据库四大家族 列存储 Hbase K-V 存储 Redis 图像存储 Neo4j 文档存储 MongoDB 云存储 OSS …

RabbitMQ中常用的三种交换机【Fanout、Direct、Topic】

目录 1、引入 2、Fanout交换机 案例&#xff1a;利用SpringAMQP演示Fanout交换机的使用 3、Direct交换机 案例&#xff1a;利用SpringAMQP演示Direct交换机的使用 4、Topic交换机 案例&#xff1a;利用SpringAMQP演示Topic交换机的使用 1、引入 真实的生产环境都会经过e…