顺序表漫谈

目录

​编辑

1.线性表

2.顺序表

2.1概念及结构

2.2接口实现

1.顺序表的动态存储

2.顺序表初始化

3.顺序表销毁

4.顺序表增容

5.顺序表头插

6.顺序表尾插

7.顺序表头删

8.顺序表尾删

9.顺序表打印

10.顺序表在任意下标位置插入数据

11.顺序表删除任意下标位置的值

12.顺序表查找

2.3菜单

3.源码


1.线性表

  • 线性表(linear list)是n个具有相同特性的数据元素的有限序列。
  • 线性表是一种在实际中广泛使用的数据结构,常见的线性表有:顺序表、链表、栈、队列、字符串...
  • 线性表在逻辑上是线性结构,也就说是连续的一条直线。但是在物理结构上并不一定是连续的,线性表在物理上存储时,通常以数组和链式结构的形式存储。


 

2.顺序表

2.1概念及结构

顺序表是一种线性表的实现方式,它通过一段物理地址连续的存储单元依次存储数据元素,数据元素之间的逻辑关系通过元素在内存中的相对位置来表示,一般情况下采用数组存储。在数组上完成数据的增删查改。

顺序表简单来说就是一个数组,它和数组的唯一区别就是里边的数据只能从头开始连续存储

🌵顺序表一般可以分为:

1.静态顺序表:使用定长数组存储元素

2.动态顺序表:使用动态开辟的数组存储元素

2.2接口实现

静态顺序表只适用于确定知道需要存储数据的场景。静态顺序表的定长数组导致N定大了,空间开多了浪费,开少了不够用。所以现实中基本都是使用动态顺序表,根据需要动态的分配空间大小,所以下面我们实现动态顺序表。

1.顺序表的动态存储

要实现动态的顺序表,我们首先得有一个指向数组的指针,因为内存是malloc或者realloc出来的。还得有一个size,知道到底存了多少个数据,以及得有一个capacity,用来记录空间容量。

typedef int SLDataType;

typedef struct SeqList
{
    assert(psl);

	SLDataType* arr; //指向动态开辟的数组
	int size;        //有效数据个数,看作下标时,它指向最后一个数据的下一个位置
	int capacity;    //空间容量
}SeqList;

2.顺序表初始化

因为形参是实参的一份临时拷贝,改变形参的值不会影响实参,所以传值的时候要传地址,形参用指针接收。

//顺序表初始化
void SeqListInit(SeqList* psl)
{
	assert(psl);

	psl->arr = NULL;
	psl->size = 0;
	psl->capacity = 0;
}

3.顺序表销毁

//顺序表销毁
void SeqListDestory(SeqList* psl)
{
	assert(psl);

	if (psl->arr != NULL)
	{
		free(psl->arr);
		psl->arr = NULL;
		psl->size = 0;
		psl->capacity = 0;
	}
}

4.顺序表增容

即检查空间,如果满了,就进行增容。因为头插和尾插都需要增容,所以我们把它成一个公共的函数,方便管理。 关于动态内存开辟有不清楚的铁子们可以看这篇博客:动态内存管理详解

//增容
void SeqListCheckCapacity(SeqList* psl)
{
	assert(psl);

	if (psl->size == psl->capacity)
	{
		int newCapacity = psl->capacity == 0 ? 4 : psl->capacity * 2;
		//防止扩容失败将原来的空间给覆盖掉,所以用一个临时变量来接收
		SLDataType* tmp = (SLDataType*)realloc(psl->arr, sizeof(SLDataType) * newCapacity);
		if (tmp == NULL)
		{
			perror("realloc");
			return;
		}
		psl->arr = tmp;
		psl->capacity = newCapacity;
	}
}

5.顺序表头插

要想在头部插入数据,必须将所有的数据先向后挪动一个位置,然后将要插入的数据放在第一个位置。我们可以先定义一个变量end,让它等于最后一个数据,然后利用while循环将所有的数据向后挪动一个位置,再将数据插入头部,然后让数据个数size+1。

//头插
void SeqListPushFront(SeqList* psl, SLDataType x)
{
	assert(psl);

	SeqListCheckCapacity(psl);

	//挪动数据
	int end = psl->size - 1;
	while (end >= 0)
	{
		psl->arr[end + 1] = psl->arr[end];
		end--;
	}
	psl->arr[0] = x;
	psl->size++;
}

6.顺序表尾插

尾插相对来说比较简单,如果空间不够,增容之后直接将要插入的数据放在尾部即可,然后将数据个数size+1。

//尾插
void SeqListPushBack(SeqList* psl, SLDataType x)
{
	assert(psl);

	//增容
	SeqListCheckCapacity(psl);

	psl->arr[psl->size] = x;
	psl->size++;
}

7.顺序表头删

头删时我们采用的方法还是挪动数据,但是要从前面开始挪动,因为如果从后往前挪的话会将前面的数据给覆盖掉。先定义一个变量begin,让它等于1,然后利用while循环将所有的数据向前挪动一个位置(让后一个数据将前一个数据覆盖掉),直到begin小于size就跳出循环,然后让数据个数size-1。

//头删
void SeqListPopFront(SeqList* psl)
{
	assert(psl);

	//暴力检查
	assert(psl->size);

	int begin = 1;
	while (begin < psl->size)
	{
		psl->arr[begin - 1] = psl->arr[begin];
		begin++;
	}
	psl->size--;
}

8.顺序表尾删

尾删时我们只需让有效数据 size-- 就行,但是必须进行检查看顺序表是否为空,因为如果为空,后面我们在头插时就会出现问题。

//尾删
void SeqListPopBack(SeqList* psl)
{
	assert(psl);

	//若顺序表为空,则进行检查
	//温柔的检查
	/*if (psl->size == 0)
	{
		return;
	}*/

	//暴力检查
	assert(psl->size > 0);

	psl->size--;
}

9.顺序表打印

//顺序表打印
void SeqListPrint(SeqList* psl)
{
	assert(psl);

	for (int i = 0; i < psl->size; i++)
	{
		printf("%d ", psl->arr[i]);
	}
	printf("\n");
}

10.顺序表在任意下标位置插入数据

首先要保证指针不为空以及pos位置的合法性。然后定义变量end,让它指向最后一个数据的位置,通过while循环将 pos到end 位置的值向后挪动一个位置,将要插入的数据放入pos位置,再将size+1。

//顺序表在任意下标位置插入数据
void SeqListInsert(SeqList* psl, int pos, SLDataType x)
{
	assert(psl);
	assert(pos >= 0 && pos <= psl->size);

	int end = psl->size - 1;
	while (end >= pos)
	{
		psl->arr[end + 1] = psl->arr[end];
		end--;
	}
	psl->arr[pos] = x;
	psl->size++;
}

11.顺序表删除任意下标位置的值

//顺序表删除任意下标位置的值
void SeqListErase(SeqList* psl, int pos)
{
	assert(psl);
	assert(pos >= 0 && pos < psl->size);
    
    //挪动数据
	int begin = pos + 1;
	while (begin < psl->size)
	{
		psl->arr[begin - 1] = psl->arr[begin];
		begin++;
	}
	psl->size--;
}

12.顺序表查找

在顺序表中查找数据,如果找到了,就返回下标;如果没有找到,则返回-1。

//顺序表查找
int SeqListFind(SeqList* psl, SLDataType x)
{
	assert(psl);

	for (int i = 0; i < psl->size; i++)
	{
		if (psl->arr[i] == x)
		{
			return i;
			break;
		}
	}
	return -1;
}

2.3菜单

void menu()
{
	printf("*************************************\n");
	printf("***   1.头插数据    2.尾插数据    ***\n");
	printf("***   3.头删数据    4.尾删数据    ***\n");
	printf("***   5.查找数据    6.打印顺序表  ***\n");
	printf("***   7.在任意下标位置插入数据    ***\n");
	printf("***   8.删除任意下标位置的数据    ***\n");
	printf("***   0.退出系统                  ***\n");
	printf("*************************************\n");
}

void Test()
{
	SeqList sl;
	SeqListInit(&sl);//初始化
	int x = 0, pos = 0;
	int input = 0;
	do
	{
		printf("欢迎来到顺序表系统!\n");
		menu();
		printf("请输入你的选择:>");
		scanf("%d", &input);
		switch (input)
		{
		case 1:
			printf("请输入你要头插的数据:\n");
			scanf("%d", &x);
			SeqListPushFront(&sl, x);
			printf("头插成功!\n");
			break;
		case 2:
			printf("请输入你要尾插的数据:\n");
			scanf("%d", &x);
			SeqListPushBack(&sl, x);
			printf("尾插成功!\n");
			break;
		case 3:
			SeqListPopFront(&sl);
			printf("头删成功!\n");
			break;
		case 4:
			SeqListPopBack(&sl);
			printf("尾删成功!\n");
			break;
		case 5:
			printf("请输入你要查找的数据(查找成功则返回下标, 负责返回-1):\n");
			scanf("%d", &x);
			int pos = SeqListFind(&sl, x);
			printf("%d\n", pos);
			break;
		case 6:
			printf("顺序表目前的数据为:\n");
			SeqListPrint(&sl);
			break;
		case 7:
			printf("请输入你要插入的数据:");
			scanf("%d", &x);
			printf("请输入你要插入数据的下标(下标从0开始):");
			scanf("%d", &pos);
			SeqListInsert(&sl, pos, x);
			printf("插入数据成功!\n");
			break;
		case 8:
			printf("请输入你要删除数据的下标:");
			scanf("%d", &pos);
			SeqListErase(&sl, pos);
			printf("删除成功!\n");
			break;
		case 0:
			printf("退出系统!\n");
			break;
		default:
			printf("选择错误,请重新选择!\n");
			break;
		}
	} while (input);

	SeqListDestory(&sl);//销毁
}

3.源码

🌻test.c

#include "SeqList.h"

void menu()
{
	printf("*************************************\n");
	printf("***   1.头插数据    2.尾插数据    ***\n");
	printf("***   3.头删数据    4.尾删数据    ***\n");
	printf("***   5.查找数据    6.打印顺序表  ***\n");
	printf("***   7.在任意下标位置插入数据    ***\n");
	printf("***   8.删除任意下标位置的数据    ***\n");
	printf("***   0.退出系统                  ***\n");
	printf("*************************************\n");
}

void Test()
{
	SeqList sl;
	SeqListInit(&sl);
	int x = 0, pos = 0;
	int input = 0;
	do
	{
		printf("欢迎来到顺序表系统!\n");
		menu();
		printf("请输入你的选择:>");
		scanf("%d", &input);
		switch (input)
		{
		case 1:
			printf("请输入你要头插的数据:\n");
			scanf("%d", &x);
			SeqListPushFront(&sl, x);
			printf("头插成功!\n");
			break;
		case 2:
			printf("请输入你要尾插的数据:\n");
			scanf("%d", &x);
			SeqListPushBack(&sl, x);
			printf("尾插成功!\n");
			break;
		case 3:
			SeqListPopFront(&sl);
			printf("头删成功!\n");
			break;
		case 4:
			SeqListPopBack(&sl);
			printf("尾删成功!\n");
			break;
		case 5:
			printf("请输入你要查找的数据(查找成功则返回下标, 负责返回-1):\n");
			scanf("%d", &x);
			int pos = SeqListFind(&sl, x);
			printf("%d\n", pos);
			break;
		case 6:
			printf("顺序表目前的数据为:\n");
			SeqListPrint(&sl);
			break;
		case 7:
			printf("请输入你要插入的数据:");
			scanf("%d", &x);
			printf("请输入你要插入数据的下标(下标从0开始):");
			scanf("%d", &pos);
			SeqListInsert(&sl, pos, x);
			printf("插入数据成功!\n");
			break;
		case 8:
			printf("请输入你要删除数据的下标:");
			scanf("%d", &pos);
			SeqListErase(&sl, pos);
			printf("删除成功!\n");
			break;
		case 0:
			printf("退出系统!\n");
			break;
		default:
			printf("选择错误,请重新选择!\n");
			break;
		}
	} while (input);

	SeqListDestory(&sl);
}

int main()
{
	Test();

	return 0;
}

🌻SeqList.h

#pragma once
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>

typedef int SLDataType;

typedef struct SeqList
{
	SLDataType* arr;//指向动态开辟的数组
	int size;     //有效数据
	int capacity; //空间容量
}SeqList;

//顺序表初始化
void SeqListInit(SeqList* psl);
//顺序表销毁
void SeqListDestory(SeqList* psl);
//顺序表打印
void SeqListPrint(SeqList* psl);
//增容
void SeqListCheckCapacity(SeqList* psl);

//头插
void SeqListPushFront(SeqList* psl, SLDataType x);
//尾插
void SeqListPushBack(SeqList* psl, SLDataType x);
//头删
void SeqListPopFront(SeqList* psl);
//尾删
void SeqListPopBack(SeqList* psl);

//顺序表在任意位置插入数据
void SeqListInsert(SeqList* psl, int pos, SLDataType x);
//顺序表删除任意位置的值
void SeqListErase(SeqList* psl, int pos);

//顺序表查找
int SeqListFind(SeqList* psl, SLDataType x);

🌻SeqList.c

#include "SeqList.h"

//顺序表初始化
void SeqListInit(SeqList* psl)
{
	assert(psl);

	psl->arr = NULL;
	psl->size = 0;
	psl->capacity = 0;
}

//顺序表销毁
void SeqListDestory(SeqList* psl)
{
	assert(psl);

	if (psl->arr != NULL)
	{
		free(psl->arr);
		psl->arr = NULL;
		psl->size = 0;
		psl->capacity = 0;
	}
}

//顺序表打印
void SeqListPrint(SeqList* psl)
{
	assert(psl);

	for (int i = 0; i < psl->size; i++)
	{
		printf("%d ", psl->arr[i]);
	}
	printf("\n");
}

//增容
void SeqListCheckCapacity(SeqList* psl)
{
	assert(psl);

	if (psl->size == psl->capacity)
	{
		int newCapacity = psl->capacity == 0 ? 4 : psl->capacity * 2;
		//防止扩容失败将原来的空间给覆盖掉,所以用一个临时变量来接收
		SLDataType* tmp = (SLDataType*)realloc(psl->arr, sizeof(SLDataType) * newCapacity);
		if (tmp == NULL)
		{
			perror("realloc");
			return;
		}
		psl->arr = tmp;
		psl->capacity = newCapacity;
	}
}

//头插
void SeqListPushFront(SeqList* psl, SLDataType x)
{
	assert(psl);
	SeqListCheckCapacity(psl);

	//挪动数据
	int end = psl->size - 1;
	while (end >= 0)
	{
		psl->arr[end + 1] = psl->arr[end];
		end--;
	}
	psl->arr[0] = x;
	psl->size++;
}

//尾插
void SeqListPushBack(SeqList* psl, SLDataType x)
{
	assert(psl);

	//增容
	SeqListCheckCapacity(psl);

	psl->arr[psl->size] = x;
	psl->size++;
}
//头删
void SeqListPopFront(SeqList* psl)
{
	assert(psl);

	//暴力检查
	assert(psl->size);

	int begin = 1;
	while (begin < psl->size)
	{
		psl->arr[begin - 1] = psl->arr[begin];
		begin++;
	}
	psl->size--;
}

//尾删
void SeqListPopBack(SeqList* psl)
{
	assert(psl);

	//若顺序表为空,则进行检查
	
	//温柔的检查
	/*if (psl->size == 0)
	{
		return;
	}*/
	//暴力检查
	assert(psl->size);

	psl->size--;
}

//顺序表在任意下标位置插入数据
void SeqListInsert(SeqList* psl, int pos, SLDataType x)
{
	assert(psl);
	assert(pos >= 0 && pos <= psl->size);

	int end = psl->size - 1;
	while (end >= pos)
	{
		psl->arr[end + 1] = psl->arr[end];
		end--;
	}
	psl->arr[pos] = x;
	psl->size++;
}

//顺序表删除任意下标位置的值
void SeqListErase(SeqList* psl, int pos)
{
	assert(psl);
	assert(pos >= 0 && pos < psl->size);

	int begin = pos + 1;
	while (begin < psl->size)
	{
		psl->arr[begin - 1] = psl->arr[begin];
		begin++;
	}
	psl->size--;
}

//顺序表查找
int SeqListFind(SeqList* psl, SLDataType x)
{
	assert(psl);

	for (int i = 0; i < psl->size; i++)
	{
		if (psl->arr[i] == x)
		{
			return i;
			break;
		}
	}
	return -1;
}

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

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

相关文章

VIO第2讲:IMU标定实验

VIO第2讲&#xff1a;IMU标定实验 文章目录 VIO第2讲&#xff1a;IMU标定实验5 IMU标定实验5.1 仿真数据产生5.1.1 c代码分析5.1.2 生成ros包数据 5.2 Allan方差实验&#xff08;港科大imu_utils&#xff09;5.2.1 安装5.2.2 运行 5.3 Allan方差实验&#xff08;matlab代码kali…

深度学习基础——GAN生成对抗网络

生成对抗网络(GAN)的简介 生成对抗网络GAN(Generative adversarial networks)是Goodfellow等在2014年提出的一种生成式模型。GAN在结构上受博弈论中的二元零和博弈(即二元的利益之和为零&#xff0c;一方的所得正是另一方的所失)的启发&#xff0c;系统由一个生成器和一个判别器…

pc微信逆向最新3.9.8.25版本

朋友让我开发一个关于微信的计数、统计、自动回复功能的机器人&#xff0c;主要是用在win10上面。 先看看结果&#xff01; 之前写过手机端的逆向&#xff0c;PC端逆向很长时间没写了&#xff0c;所以就在网上找了找。基本都是基于3.6&#xff0c;3.7&#xff0c;3.8版本的&a…

python读取txt文档数据并断言value值的大小

本文主要介绍&#xff1a;将接口返回的字典值{"x1":1,"x2":2....}手动存到txt&#xff0c;然后写代码断言每个value值是否都满足某个区间。运用到&#xff1a; 1、读取txt文件中的数据 2、pytest写用例格式 3、pytest.assume断言方式&#xff08;出现报错A…

C++力扣题目139--单词拆分 198--打家劫舍 213--打家劫舍II 337打家劫舍III

139.单词拆分 力扣题目链接(opens new window) 给定一个非空字符串 s 和一个包含非空单词的列表 wordDict&#xff0c;判定 s 是否可以被空格拆分为一个或多个在字典中出现的单词。 说明&#xff1a; 拆分时可以重复使用字典中的单词。 你可以假设字典中没有重复的单词。 …

【IEEE出版会议征稿】第七届计算机信息科学与应用技术国际学术会议(CISAT 2024)

【IEEE出版】第七届计算机信息科学与应用技术国际学术会议&#xff08;CISAT 2024&#xff09; 2024 7th International Conference on Computer Information Science and Application Technology 第七届计算机信息科学与应用技术国际学术会议&#xff08;CISAT 2024&#x…

低代码:更高效、简单的方式开发出专业级的项目

你是否为编程世界的各种挑战感到头痛&#xff1f;想要以更高效、简单的方式开发出专业级的项目&#xff1f; JNPF低代码工具正是你苦心寻找的产品&#xff01;它是一款专为稍微懂一点点编程思想的入门级人员设计的神奇工具&#xff0c;集成了丰富的功能和组件&#xff0c;让你轻…

[NOIP2016 普及组] 魔法阵(枚举的典型例题,值得一看)

在透视这道题之前&#xff0c;先用一道小题来练练手 密码锁&#xff08;这道题是我根据魔法阵改的&#xff09; Description 叮当在探索迷宫时被一扇大门挡住了去路&#xff0c;门上刻画了很多乱七八糟的数字&#xff0c;门被锁上了&#xff0c;无法打开&#xff0c;但是门上…

WebGIS开发常用的JS库:VUE/React/Angular对比

Angular: 作用&#xff1a; Angular是一个完整的基于TypeScript的Web应用开发框架&#xff0c;主要用于构建单页Web应用&#xff08;SPA&#xff09;。它适用于大型和复杂的项目&#xff0c;具有强大的组件集合和丰富的文档。 架构&#xff1a; Angular采用组件化的方式&am…

【DC-DC】世微AP5192 LED恒流IC 摩托电动车货车 12-80V 1.5A 有极输入 电源驱动芯片

产品描述 AP5192是一款PWM工作模式,效率高、简单、内置功率MOS管&#xff0c;适用于4.5-100V输入的高精度降压LED恒流驱动芯片。电流1.5A。AP5192可实现线性调光和PWM调光&#xff0c;线性调光脚有效电压范围0.55-2.6V.AP5192 工作频率可以通过RT 外部电阻编程来设定&#xff0…

[经验] 动车盒饭价格2022 #其他#职场发展

动车盒饭价格2022 1、动车盒饭 近年来&#xff0c;随着中国高速铁路的发展&#xff0c;动车盒饭也成为了不可忽视的一份美食。它不仅解决了旅途中的饮食需求&#xff0c;还体现了中国美食文化的多样性和可口。 动车盒饭是一种便捷且美味的餐食&#xff0c;在火车上也不失为一…

胶原蛋白市场研究:预计2029年将达到27亿美元

胶原蛋白是一种白色、无支链的纤维状蛋白&#xff0c;是细胞外间质蛋白质的主要成分&#xff0c;占人体总蛋白质的25%到30%。 按胶原蛋白来源划分&#xff0c;可分为天然胶原蛋白和人工合成的胶原蛋白&#xff0c;后者以重组类人胶原蛋白为主&#xff0c;而重组类人胶原蛋白又可…

失败了,又继续失败了

这是一个普通的老人在小县城坚持写作的故事。与很多人的老年生活不同&#xff0c;78岁的舒绍平每天过着规律的写作生活&#xff0c;不做家务的时候&#xff0c;他便坐在书房&#xff0c;打开笔记本电脑&#xff0c;时断时续地敲字写作。 年轻时&#xff0c;他当过老师&#xf…

五种多目标优化算法(MOJS、MOGWO、NSWOA、MOPSO、NSGA2)性能对比,包含6种评价指标,9个测试函数(提供MATLAB代码)

一、5种多目标优化算法简介 1.1MOJS 1.2MOGWO 1.3NSWOA 1.4MOPSO 1.5NSGA2 二、5种多目标优化算法性能对比 为了测试5种算法的性能将其求解9个多目标测试函数&#xff08;zdt1、zdt2 、zdt3、 zdt4、 zdt6 、Schaffer、 Kursawe 、Viennet2、 Viennet3&#xff09;&#xff0…

C++学习Day08之函数模板

目录 前言一、程序及输出1.1 不使用函数模板1.2 使用函数模板1.2.1 自动类型推导1.2.2 显示指定类型 二、分析与总结 前言 C 函数模板是一种通用编程技术&#xff0c;允许您编写通用的函数代码&#xff0c;以适用于不同类型的数据。 一、程序及输出 1.1 不使用函数模板 每一…

【riscv】使用qemu运行riscv裸机freestanding程序

文章目录 1. 运行显示2. 工具准备3. 裸机代码和编译3.1 源码3.2 编译 4. 使用qemu仿真运行riscv裸机程序 1. 运行显示 详见左下角&#xff0c; 运行时串口输出的字符 A ; 2. 工具准备 # for riscv64-linux-gnu-gcc sudo apt-get install gcc-riscv64-linux-gnu# for qemu-s…

【RT-DETR有效改进】大核注意力 | LSKAttention助力极限涨点

一、本文介绍 在这篇文章中,我们将讲解如何将LSKAttention大核注意力机制应用于RT-DETR,以实现显著的性能提升。首先,我们介绍LSKAttention机制的基本原理,它主要通过将深度卷积层的2D卷积核分解为水平和垂直1D卷积核,减少了计算复杂性和内存占用。接着,我们介绍将这一…

记录留下的脚印

记录走过的脚印&#xff01;

【爬虫JS逆向-工具篇】浏览器内存漫游加密参数Hook实战教程

文章目录 1. 写在前面2. 环境搭建2. 加密定位实战 【作者主页】&#xff1a;吴秋霖 【作者介绍】&#xff1a;Python领域优质创作者、阿里云博客专家、华为云享专家。长期致力于Python与爬虫领域研究与开发工作&#xff01; 【作者推荐】&#xff1a;对JS逆向感兴趣的朋友可以关…

数据库的备份模式(完全备份,增量备份,差异备份)

数据库的备份 备份原因 数据的丢失 数据的删除 备份目标 数据的一致性 数据的可用性 备份技术 物理备份/冷备份 直接复制数据库文件&#xff0c;适用于大型数据库环境&#xff0c;不受存储引擎的限制&#xff0c;但不能恢复到不同的MySQL版本。 常用的冷备份工具 ta…