当前位置: 首页 > news >正文

Java进阶(7)——手动实现LinkedList 内部node类的实现 增删改查的实现 toString方法 源码的初步理解

目录

  • 引出
  • 从ArrayList到Linkedlist
    • 手动实现ArrayList
    • 从ArrayList到LinkedList
  • 总体设计
    • Node类
    • Node的方法:根据index找node
  • 增删改查的实现
    • 增加元素
    • 删除元素
    • 修改元素
    • 查询元素
  • toString方法
  • 完整代码
    • List接口类
    • LinkedList的实现
    • 测试类
  • 总结

引出


1.linkedList的节点,当前,上一个,下一个的思想;
2.根据index找node的方法,根据index确定从头部还是尾部;
3.linkedlist的增删改查的实现,本质是改变节点的信息;
4.递归方法实现自定义链表的toString方法;

从ArrayList到Linkedlist

在这里插入图片描述

手动实现ArrayList

Java进阶(3)——手动实现ArrayList & 源码的初步理解分析 & 数组插入数据和删除数据的问题

在这里插入图片描述

从ArrayList到LinkedList

如果发生对表的一些插入和删除操作,特别是对表的前端进行,那么数组就不是一种好的选择。另一种数据结构:链表(linked list)。

在这里插入图片描述

链表由一系列节点组成,这些节点不必在内存中相连。每一个节点均含有表元素和到包含该元素后继元的节点的链(link)。我们称之为next链。最后一个单元的next链引用null。

在这里插入图片描述

链表的插入

在这里插入图片描述

让每一个节点持有一个指向它在表中的前驱节点的链,我们称之为双链表(doubly linked list)。

在这里插入图片描述

总体设计

在这里插入图片描述

在考虑设计方面,我们将需要提供三个类:
1.MyLinkedList类本身,它包含到两端的链、表的大小以及一些方法。
2.Noe类,它可能是一个私有的嵌套类。一个节点包含数据以及到前一个节点的链和到下一个节点的链,还有一些适当的构造方法。
3.LinkedListIterator类,该类抽象了位置的概念,是一个私有类,并实现接口Iterator。它提供了方法next、hasNext和remove的实现。

标记节点:

前端创建一个额外的节点,逻辑上代表开始的标记。这些额外的节点有时候就叫作标记节点(sentinel node);特别地,在前端的节点有时候也叫作头节点(header node),而在末端的节点有时候也叫作尾节点(tail node)

在这里插入图片描述

Node类

私有的内部类

  • 当前节点,前置节点,后续节点;
  • 表示链表中的一个基本元素;

在这里插入图片描述

/*** 内部类,节点;属性,当前节点,前置节点,后续节点* @param <T>*/private static class Node<T> {T item; // 当前的节点Node<T> next; // 下一个节点Node<T> prev; // 前置节点Node(Node<T> prev,T element,Node<T> next) {this.item = element;this.prev = prev;this.next = next;}@Overridepublic String toString() {String nextStr = null;if (next!=null){nextStr = next.item.toString();}String prevStr = null;if (prev!=null){prevStr = prev.item.toString();}return "Node{" +" prev=" + prevStr +",item=" + item +", next=" + nextStr +'}';}}

在这里插入图片描述

Node的方法:根据index找node

思路:从头部开始找,进行循环

    public Node<T> NodeByIndex(int index){Node<T> x = first; // 从头部开始找for (int i = 0; i<index;i++){x = x.next;}return x;}

源码采用如下策略

  • 1.根据index和list的size确定从头部还是尾部找;
  • 2.根据index找node节点;

在这里插入图片描述

分析:

降低了复杂度:

如果都从头部找,时间复杂度就是O(i),在最极端的情况下,根据index找最后一个,时间复杂度是O(N);

如果是先确定从头部找,还是从尾部找,则时间复杂度最大是O(N/2);

增删改查的实现

增加元素

最简单的情况,都是从尾部新增元素

  • 1.新的节点的上一个节点为之前的尾部节点;
  • 2.新的尾部节点为当前新增的节点;
  • 3.如果是第一个节点,则需要把first设置为当前的节点
  • 4.链表的size+1;

在这里插入图片描述

    @Overridepublic void add(T e) {Node<T> l = last;Node<T> newNode = new Node<>(l, e, null); // 新增的节点,尾部添加last = newNode;if (l==null){// 是第一个节点first = newNode;System.out.println("FirstNode --->"+first);}else {l.next = newNode;System.out.println("Add {"+e+"} ---->"+l);}size++;}

更一般的情况如下,插入一个元素

在这里插入图片描述

删除元素

删除头部?尾部?中间

  • 1.如果删除的是头部节点,则让被删除的节点的下一个节点为first节点;
  • 2.如果删除的尾部节点,则让被删除的节点的上一个节点的下一个节点为null;
  • 3.如果删除的是中间的节点,让该节点的前置节点的下一个节点指向该节点的下一个节点;

在这里插入图片描述

    @Overridepublic void remove(int index) {// 找到要删除的节点,前置节点,后续节点// 1.如果删除的是头部节点if (index==0){first = NodeByIndex(index+1);return;}// 2.如果不是头部节点Node<T> tNode = NodeByIndex(index); // 当前节点Node<T> prev = tNode.prev; // 当前节点的上一个节点Node<T> next = tNode.next; // 当前节点的下一个节点if (next==null){// 删除的是尾部节点prev.next = null;return;}// 删除的是中间的某个节点// 让该节点的前置节点的下一个节点指向该节点的下一个节点prev.next = next;next.prev = prev;size--;}

修改元素

被修改的节点的节点关系不变,只需要把当前节点的元素变为最新的元素即可

在这里插入图片描述

代码实现

在这里插入图片描述

查询元素

调用node方法即可

    @Overridepublic T get(int index) {// 索引不能大于等于sizeif (index<0 || index>=size){throw new IndexOutOfBoundsException("LinkedList的索引越界");}return NodeByIndex(index).item;}

toString方法

在这里插入图片描述

完整代码

List接口类

package com.tianju.book.jpa.mlist;/*** 手工打造ArrayList*/
public interface MyList<T> {/*** 增加一个元素,涉及到容量的变化*/void add(T t);/*** 根据索引删除元素* @param index 要删除元素的索引,超过索引?索引不存在?*/void remove(int index);/*** 根据索引修改一个元素* @param index 要修改的索引* @param t 修改的值*/void set(int index,T t);/*** 根据索引获取元素* @param index 索引* @return 获取的元素*/T get(int index);int size();String toString();}

LinkedList的实现

package com.tianju.book.jpa.myLinkList;import com.tianju.book.jpa.mlist.MyList;public class MyLinkedList<T> implements MyList<T> {int size = 0;Node<T> first; // 头部节点Node<T> last; // 尾部节点/*** 内部类,节点;属性,当前节点,前置节点,后续节点* @param <T>*/private static class Node<T> {T item; // 当前的节点Node<T> next; // 下一个节点Node<T> prev; // 前置节点Node(Node<T> prev,T element,Node<T> next) {this.item = element;this.prev = prev;this.next = next;}@Overridepublic String toString() {String nextStr = null;if (next!=null){nextStr = next.item.toString();}String prevStr = null;if (prev!=null){prevStr = prev.item.toString();}return "Node{" +" prev=" + prevStr +",item=" + item +", next=" + nextStr +'}';}}@Overridepublic void add(T e) {Node<T> l = last;Node<T> newNode = new Node<>(l, e, null); // 新增的节点,尾部添加last = newNode;if (l==null){// 是第一个节点first = newNode;System.out.println("FirstNode --->"+first);}else {l.next = newNode;System.out.println("Add {"+e+"} ---->"+l);}size++;}public Node<T> NodeByIndex(int index){Node<T> x = first; // 从头部开始找for (int i = 0; i<index;i++){x = x.next;}return x;}@Overridepublic void remove(int index) {// 找到要删除的节点,前置节点,后续节点// 1.如果删除的是头部节点if (index==0){first = NodeByIndex(index+1);return;}// 2.如果不是头部节点Node<T> tNode = NodeByIndex(index); // 当前节点Node<T> prev = tNode.prev; // 当前节点的上一个节点Node<T> next = tNode.next; // 当前节点的下一个节点if (next==null){// 删除的是尾部节点prev.next = null;return;}// 删除的是中间的某个节点// 让该节点的前置节点的下一个节点指向该节点的下一个节点prev.next = next;next.prev = prev;size--;}@Overridepublic void set(int index, T element) {// 索引不能大于等于sizeif (index<0 || index>=size){throw new IndexOutOfBoundsException("LinkedList的索引越界");}Node<T> tNode = NodeByIndex(index); // 当前节点T oldVal = tNode.item; // 获取旧的元素tNode.item = element; // 把当前节点的元素设置成新的
//        System.out.println(oldVal);}@Overridepublic T get(int index) {// 索引不能大于等于sizeif (index<0 || index>=size){throw new IndexOutOfBoundsException("LinkedList的索引越界");}return NodeByIndex(index).item;}@Overridepublic int size() {return size;}/*** 为了实现toString方法*/String str = "null-->";// 通过第一个节点递归调用,获得LinkedList的链private String recursion(Node<T> first){if (!str.contains(first.item.toString())){str = str + first.item;}if (first.next==null){return str + "-->null";}str = str + "-->" +  first.next.item.toString();first = first.next;return recursion(first);}// 在每次调用后把str归位;private void backStr(){str = "null-->";}@Overridepublic String toString() {String recursion = recursion(first);backStr();return "MyLinkedList{ " + recursion +" }";}
}

测试类

package com.tianju.book.jpa.myLinkList;import org.hibernate.event.spi.SaveOrUpdateEvent;import java.util.List;public class MyLinkedListTest1 {public static void main(String[] args) {MyLinkedList<String> list = new MyLinkedList<>();list.add("PET1");list.add("PET2");list.add("PET3");System.out.println("**********");System.out.println(list);list.add("PET4");System.out.println(list);System.out.println(list.size());//        System.out.println(list.get(4));
//        list.remove(0);
//        System.out.println("删除头部节点");
//        System.out.println(list);
//
//        System.out.println("删除尾部节点");
//        list.remove(3-1);
//        System.out.println(list);System.out.println("删除中间的节点");list.remove(2);System.out.println(list);System.out.println("进行set");list.set(0, "SHI1");System.out.println(list);}
}

在这里插入图片描述


总结

1.linkedList的节点,当前,上一个,下一个的思想;
2.根据index找node的方法,根据index确定从头部还是尾部;
3.linkedlist的增删改查的实现,本质是改变节点的信息;
4.递归方法实现自定义链表的toString方法;

相关文章:

Java进阶(7)——手动实现LinkedList 内部node类的实现 增删改查的实现 toString方法 源码的初步理解

目录 引出从ArrayList到Linkedlist手动实现ArrayList从ArrayList到LinkedList 总体设计Node类Node的方法&#xff1a;根据index找node 增删改查的实现增加元素删除元素修改元素查询元素 toString方法完整代码List接口类LinkedList的实现测试类 总结 引出 1.linkedList的节点&am…...

CPU总线的理解

目录 CPU总线CPU总线是什么&#xff1f;CPU总线可以分为前端部分和后端部分吗&#xff1f; CPU总线 CPU总线是什么&#xff1f; CPU总线&#xff08;Central Processing Unit Bus&#xff09;是计算机硬件中的一个重要组成部分&#xff0c;它是连接CPU和其他硬件组件的通道。…...

Spring Boot 中的 AOP,到底是 JDK 动态代理还是 Cglib 动态代理

大家都知道&#xff0c;AOP 底层是动态代理&#xff0c;而 Java 中的动态代理有两种实现方式&#xff1a; 基于 JDK 的动态代理 基于 Cglib 的动态代理 这两者最大的区别在于基于 JDK 的动态代理需要被代理的对象有接口&#xff0c;而基于 Cglib 的动态代理并不需要被代理对…...

记录一下在工作中使用 LayUI bug的问题

前言&#xff1a; LayUI是一个很老的框架了&#xff0c;经常会碰到一些 bug。不过由于他的轻量级&#xff0c;仍然有一些项目在使用。解决这些 bug 可能会对大家产生一些意义。 layui中 slect form表单元素 不美化显现的问题 layui中美化的表单元素 在渲染完成要添加 form.re…...

手机自动无人直播,实景无人直播真的有用吗?

继数字人直播之后&#xff0c;手机自动直播开始火热了起来&#xff0c;因为其门槛低&#xff0c;成本低&#xff0c;一部手机一个账号就可以实现直播&#xff0c;一时深受广大商家的好评。那么&#xff0c;手机自动无人直播究竟是如何实现自动直播的呢&#xff1f; 在传统的直…...

python 面试题--2(15题)

目录 1.解释Python中的 GIL&#xff08;全局解释器锁&#xff09;是什么&#xff0c;它对多线程编程有什么影响&#xff1f; 2.Python中的装饰器是什么&#xff1f;如何使用装饰器&#xff1f; 3.解释Python中的迭代器和生成器的区别。 4.什么是Python中的列表解析&#xf…...

kafka复习:(11)auto.offset.reset的默认值

在ConsumerConfig这个类中定义了这个属性的默认值&#xff0c;如下图 也就是默认值为latest,它的含义是&#xff1a;如果没有客户端提交过offset的话&#xff0c;当新的客户端消费时&#xff0c;把最新的offset设置为当前消费的offset. 默认是自动提交位移的&#xff0c;每5秒…...

【javaweb】学习日记Day7 - Mysql 数据库 DQL 多表设计

之前学习过的SQL语句笔记总结戳这里→【数据库原理与应用 - 第六章】T-SQL 在SQL Server的使用_Roye_ack的博客-CSDN博客 目录 一、DQL 数据查询 1、基本查询 2、条件查询 3、分组查询 &#xff08;1&#xff09;聚合函数 ① count函数 ② max min avg sum函数 &…...

线程的生命周期

线程的生命周期 与人有生老病死一样&#xff0c;线程也同样要经历开始&#xff08;等待&#xff09;、运行、挂起和停止四种不同的状态。这四种状态都可以通过Thread类中的方法进行控制。下面给出了Thread类中和这四种状态相关的方法。 // 开始线程 public void start( ); …...

GAN | 论文精读 Generative Adversarial Nets

提出一个GAN &#xff08;Generative Adversarial Nets&#xff09; 1 方法 &#xff08;1&#xff09;生成模型G&#xff08;Generative&#xff09;&#xff0c;是用来得到分布的&#xff0c;在统计学眼里&#xff0c;整个世界是通过采样不同的分布得到的&#xff0c;生成…...

Yolo系列-yolov2

YOLO-V2 更快&#xff01;更强&#xff01; YOLO-V2-BatchNormalization BatchNormalization&#xff08;批归一化&#xff09;是一个常用的深度神经网络优化技术&#xff0c;它可以将输入数据进行归一化处理&#xff0c;使得神经网络更容易进行学习。在YOLOv2中&#xff0c;B…...

Linux下的系统编程——vim/gcc编辑(二)

前言&#xff1a; 在Linux操作系统之中有很多使用的工具&#xff0c;我们可以用vim来进行程序的编写&#xff0c;然后用gcc来生成可执行文件&#xff0c;最终运行程序。下面就让我们一起了解一下vim和gcc吧 目录 一、vim编辑 1.vim的三种工作模式 2.基本操作之跳转字符 &a…...

2023年国赛 高教社杯数学建模思路 - 案例:最短时间生产计划安排

文章目录 0 赛题思路1 模型描述2 实例2.1 问题描述2.2 数学模型2.2.1 模型流程2.2.2 符号约定2.2.3 求解模型 2.3 相关代码2.4 模型求解结果 建模资料 0 赛题思路 &#xff08;赛题出来以后第一时间在CSDN分享&#xff09; https://blog.csdn.net/dc_sinor?typeblog 最短时…...

芯科科技推出专为Amazon Sidewalk优化的全新片上系统和开发工具,加速Sidewalk网络采用

芯科科技为Sidewalk开发提供专家级支持 中国&#xff0c;北京 - 2023年8月22日 – 致力于以安全、智能无线连接技术&#xff0c;建立更互联世界的全球领导厂商Silicon Labs&#xff08;亦称“芯科科技”&#xff0c;NASDAQ&#xff1a;SLAB&#xff09;今日在其一年一度的第四…...

Kotlin 丰富的函数特性

Kotlin 是一门基于 JVM 的现代编程语言&#xff0c;它提供了丰富的函数特性&#xff0c;使得编写简洁、灵活且可读性强的代码成为可能。以下是 Kotlin 函数的一些主要特性&#xff1a; 一、函数声明与调用 在 Kotlin 中&#xff0c;使用 fun 关键字来声明函数。函数声明的基本…...

Node.js怎么搭建HTTP服务器

在 Node.js 中搭建一个简单的 HTTP 服务器非常容易。以下是一个基本的示例&#xff0c;演示如何使用 Node.js 创建一个简单的 HTTP 服务器&#xff1a; // 导入 http 模块 const http require(http); // 创建一个 HTTP 服务器 const server http.createServer((req, res) …...

基于Redisson的联锁(MultiLock)

基于Redis的分布式MultiLock对象允许对Lock对象进行分组并将它们作为单个锁进行处理。每个RLock对象可能属于不同的Redisson实例。 如果获取的Redisson实例MultiLock崩溃&#xff0c;那么它可能永远挂在获取状态。为了避免这种情况&#xff0c;Redisson维护了一个锁看门狗&…...

人脸识别平台批量导入绑定设备的一种方法

因为原先平台绑定设备是通过一个界面进行人工选择绑定或一个人一个人绑定设备。如下&#xff1a; 但有时候需要在几千个里选择出几百个&#xff0c;那这种方式就不大现实了&#xff0c;需要另外一种方法。 目前相到可以通过导入批量数据进行绑定的方式。 一、前端 主要是显示…...

MySQL—MySQL的NULL值是怎么存放的

一、引言 1、MySQL数据存放在哪个文件&#xff1f; 创建一个数据库会产生三种格式的文件&#xff0c;分别是.opt格式、.frm格式、.ibd格式。 opt格式&#xff1a;用来存储当前数据库的默认字符集和字符校验规则。 frm格式&#xff1a;该文件是用来保存每个表的元数据信息的&…...

sql server删除历史数据

1 函数 datediff函数: DATEDIFF ( datepart , startdate , enddate )datepart的取值可以是year,quarter,Month,dayofyear,Day,Week,Hour,minute,second,millisecond startdate 是从 enddate 减去。如果 startdate 比 enddate 晚&#xff0c;返回负值。 2 例子 删除2023年以…...

目标检测项目中,使用python+xml.etree.ElementTree修改xml格式标注文件中的类别名称

需求&#xff1a; 数据集的数据增强中&#xff0c;有时需要将xml标注文件中的类别做修改为新类别&#xff0c;或者将几个类别合并为一个类别。 解决方法&#xff1a; 使用pythonimport xml.etree.ElementTree将xml标注文件中的类别名称做修改。代码如下&…...

最新域名和子域名信息收集技术

域名信息收集 1&#xff0e;WHOIS查询 WHOIS是一个标准的互联网协议&#xff0c;可用于收集网络注册信息、注册域名﹑IP地址等信息。简单来说&#xff0c;WHOIS就是一个用于查询域名是否已被注册及注册域名详细信息的数据库&#xff08;如域名所有人、域名注册商&#xff09;…...

C语言基础之——指针(上)

前言&#xff1a;小伙伴们又见面啦&#xff01;本期内容&#xff0c;博主将展开讲解有关C语言中指针的上半部分基础知识&#xff0c;一起学习起来叭&#xff01;&#xff01;&#xff01; 目录 一.什么是指针 二.指针类型 1.指针的解引用 2.指针-整数 三.野指针 1.野指针…...

构建 NodeJS 影院预订微服务并使用 docker 部署(04/4)

一、说明 构建一个微服务的电影网站&#xff0c;需要Docker、NodeJS、MongoDB&#xff0c;这样的案例您见过吗&#xff1f;如果对此有兴趣&#xff0c;您就继续往下看吧。 我们前几章的快速回顾 第一篇文章介绍了微服务架构模式&#xff0c;并讨论了使用微服务的优缺点。第二篇…...

SpringBootWeb案例 Part3

目录 1. 新增员工 1.1 需求 1.2 接口文档 1.3 思路分析 PostMapping RequestBody //把前端传递的JSON数据填充到实体类中 1.4 功能开发 1.5 功能测试 1.6 前后端联调 2. 文件上传 2.1 文件上传简介 Spring中提供了一个API&#xff1a;MultipartFile&#xff0c;使…...

C++中using 用法

C中的 using 关键字用于引入命名空间、类型别名和模板别名。以下是 using 关键字的几种常见用法及其中文解析&#xff1a; 1. 引入命名空间&#xff1a; using namespace std; 中文解析&#xff1a;引入 std 命名空间&#xff0c;使得命名空间中的成员在当前作用域内可直接使…...

window下jdk安装及更换jdk版本的一些问题。

目录 jdk安装jdk的选择。oracle的jdk怎么安装。openjdk怎么安装。 jdk的版本控制。更换jdk的一些问题。 jdk安装 jdk的选择。 目前有两种可选的jdk&#xff0c;oracle的和开源的Openjdk&#xff0c;这两种jdk的区别可以自行查阅&#xff0c;就结果而言&#xff0c;openjdk开源…...

GPT4模型架构的泄漏与分析

迄今为止&#xff0c;GPT4 模型是突破性的模型&#xff0c;可以免费或通过其商业门户&#xff08;供公开测试版使用&#xff09;向公众提供。它为许多企业家激发了新的项目想法和用例&#xff0c;但对参数数量和模型的保密却扼杀了所有押注于第一个 1 万亿参数模型到 100 万亿参…...

GEE/PIE遥感大数据处理与典型案例丨数据整合Reduce、云端数据可视化、数据导入导出及资产管理、机器学习算法等

目录 ​专题一&#xff1a;初识GEE和PIE遥感云平台 专题二&#xff1a;GEE和PIE影像大数据处理基础 专题三&#xff1a;数据整合Reduce 专题四&#xff1a;云端数据可视化 专题五&#xff1a;数据导入导出及资产管理 专题六&#xff1a;机器学习算法 专题七&#xff1a;…...

STM32--DMA

文章目录 DMA简介DMA特性 DMA框图DMA基本结构DMA请求数据宽度对齐DMA数据转运工程DMAADC多通道 DMA简介 直接存储器存取(DMA)用来提供在外设和存储器之间或者存储器和存储器之间的高速数据传输。无须CPU干预&#xff0c;数据可以通过DMA快速地移动&#xff0c;这就节省了CPU的…...

怎么上网站/互联网推广平台有哪些公司

1、self是什么&#xff0c;一般都说指对象本身&#xff0c;这样说了没了用&#xff0c;说了后还是很难懂&#xff0c;因为这样说了后&#xff0c;仍然完全搞不清楚&#xff0c;什么时候变量前需要加self&#xff0c;什么时候不需要加self。 造成很多人&#xff0c;已经怕了self…...

门户网站建设研究/情感式软文广告

CONF_DONE信号是一个双向信号并且是Open-Drain。在配置过程中和配置之前作为输出&#xff0c;且为低电平。配置完成之后CONF_DONE作为输入脚&#xff0c;因为Open-Drain&#xff0c;所以必须由外部拉高&#xff0c;但二极管压降比较大&#xff0c;很可能造成CONF_DONE不能拉高。…...

dede网站后台导入文档/如何刷seo关键词排名

传送门:bzoj2989 题解 二进制分组-CA 欧几里得距离转成曼哈顿距离(x,y),(xy,x−y)(x,y),(xy,x-y)(x,y),(xy,x−y)之后问题就变成了每次给一个点1&#xff0c;询问某个矩形范围内的总值。 通常方法是cdqcdqcdq&#xff0c;二进制分组可以解决强制在线的限制。 具体来说&…...

网站广告做的好的企业案例分析/google关键词优化排名

在互联网业务蒸蒸日上的今时今日&#xff0c;系统架构日渐复杂&#xff0c;随着软件产品和工程团队的变革&#xff0c;许多开源的监控工具应运而生&#xff0c;其中有一些相当出名&#xff0c;比如 Zabbix、Nagios 还有 StatsD。也有一些问题被大家不断讨论&#xff0c;例如&am…...

郴州网站网络推广平台/盘多多网盘搜索

Werb项目地址&#xff1a;Werb/Werb简介&#xff1a;第三方微博更多&#xff1a;作者 提 Bug 标签&#xff1a;weibo-问题说明目前 sina 规定只能设置 15 个测试账号&#xff0c;而且现在单单提供测试账号貌似有很多问题&#xff0c;我建议你&#xff1a;自己去新浪新建一个…...

做谷歌网站使用什么统计代码/网站推广公司大家好

导读&#xff1a;本文主要介绍 CentOS 系统二进制安装 MySQL 5.7.23 版本的安装步骤&#xff0c;其他版本安装过程相似。1.前置准备卸载旧版MySQL查看rpm包rpm -qa|grep mysql 若有可用rpm -e卸载查找mysql残留包&#xff0c;有则删除&#xff0c;没有则忽略find / -name mysql…...