实验指导.docx

上传人:b****5 文档编号:5718238 上传时间:2022-12-31 格式:DOCX 页数:25 大小:27.57KB
下载 相关 举报
实验指导.docx_第1页
第1页 / 共25页
实验指导.docx_第2页
第2页 / 共25页
实验指导.docx_第3页
第3页 / 共25页
实验指导.docx_第4页
第4页 / 共25页
实验指导.docx_第5页
第5页 / 共25页
点击查看更多>>
下载资源
资源描述

实验指导.docx

《实验指导.docx》由会员分享,可在线阅读,更多相关《实验指导.docx(25页珍藏版)》请在冰豆网上搜索。

实验指导.docx

实验指导

第一章线性表

1.内容要点

线性表(Linearlist)是最简单且最常用的一种数据结构。

这种结构具有下列特点:

存在一个唯一的没有前驱的(头)数据元素;存在一个唯一的没有后继的(尾)数据元素;此外,每一个数据元素均有一个直接前驱和一个直接后继数据元素。

线性表的顺序存储结构,也称为顺序表。

其存储方式为:

在内存中开辟一片连续存储空间,但该连续存储空间的大小要大于或等于顺序表的长度,然后让线性表中第一个元素存放在连续存储空间第一个位置,第二个元素紧跟着第一个之后,其余依此类推。

可见,在线性表上,逻辑关系相邻的两个元素在物理位置上也相邻。

——线性表顺序存储的特点。

很容易确定每个数据元素在存储单元中与起始地址的相对位置:

假设线性表中元素为(a1,a2,….,an),设第一个元素a1的内存地址为LOC(a1),而每个元素在计算机内占C个存贮单元,则第i个元素ai的首地址为LOC(ai)=LOC(a1)+(i-1)×C(其中1≤i≤n)

显然,顺序表便于进行随机访问,故线性表的顺序存储结构是一种随机存储的结构。

线性表的链式存贮结构,也称为链表。

链式存储是用一些任意的存储单元来存储线性表中的元素,这些单元在物理上可以是连续的,也可以是不连续的。

为了能正确地描述元素之间的逻辑关系,除了存储元素本身的信息外,还需存储指示元素之间逻辑关系的信息。

这两部分信息组成数据元素ai的存储映像,称为结点。

在链表中,每个结点所占的存储空间分为两部分:

存放数值的域称为数据域,存放结点之间相互关系的域称为指针域。

在定义的链表中,若只含有一个指针域来存放下一个元素地址,称这样的链表为单链表或线性链表。

2.基础实验

实验一:

多项式加法和乘法问题

【实验内容与要求】

问题描述:

设计一个一元稀疏多项式简单计算器。

基本要求:

一元稀疏多项式简单计算器的基本功能是:

(1)输入并建立多项式;

(2)输出多项式,输出形式为整数序列:

n,c1,e1,c2,e2,...,cn,en,其中n是多项式的项数,ci和ei分别是第i项的系数和指数,序列按指数降序排列。

(3)多项式a与多项式b相加,相减,相乘,分别建立多项式。

【实现提示】:

用带表头结点的单链表存储多项式。

【思考与提高】:

(1)计算多项式在x处的值。

(2)求多项式的导函数。

(3)计算器的仿真界面。

实验二:

约瑟夫(Josephus)环问题

【实验内容与要求】

问题描述:

编号是1,2,…,n(n>0)的n个人按照顺时针方向围坐一圈,每人持有一正整数密码。

开始时任选一个正整数作为报数上限值m,从某个人开始按顺时针方向自1开始顺序报数,报到m时停止报数,报m的人出列,将他的密码作为新的m值,从他在顺时针方向的下一个人开始重新从1报数,如此下去,直到所有人全部出列为止。

令n最大值取30。

设计一个程序来求出出列顺序,并输出结果。

基本要求:

利用单向循环链表存储结构模拟此过程,按照出列的顺序输出各人的编号。

【知识要点】

关于单循环链表的概念请参见基础实验6的知识要点。

循环链表上的运算与单链表上运算基本一致,区别只在于最后一个结点的判断(即循环的条件不同),但利用循环链表实现某些运算较单链表方便(从某个结点出发能求出它的直接前驱,而单链表是不行的,只能从头出发)。

【实现提示】

由于该问题是由古罗马著名史学家Josephus提出的问题演变而来,所以通常称之为Josephus问题。

Josephus问题的解决需要采用循环链表,先构造一个有n个结点的单循环链表,再给出一个报数上限值m(假设m>1),在链表的首结点开始从1计数,计到m时,对应的结点从链表中删除,然后在被删除结点的下一个结点又从1开始计数,直到最后一个结点从链表中删除算法结束。

【思考与提高】

如果要求围坐一圈的人并不全出列,要余下k(自己确定)个人不出列又该怎样改进此算法。

第二章栈和队列

1.内容要点

栈和队列是在软件设计中常用的两种数据结构,它们的逻辑结构和线性表相同。

其特点在于运算受到了限制:

栈按“后进先出”的规则进行操作,队列按“先进先出”的规则进行操作,故将栈和队列称作运算受限制的线性表。

栈是限制在表的一端进行插入和删除的线性表。

允许插入、删除的这一端称为栈顶,另一个固定端称为栈底。

当表中没有元素时称为空栈。

如图2.1所示栈中有三个元素,进栈的顺序是a1、a2、a3,当需要出栈时其顺序为a3、a2、a1,所以栈又称为后进先出的线性表(LastInFirstOut),简称LIFO表。

由于栈是运算受限的线性表,因此线性表的存储结构对栈也是适用的,只是操作不同而已。

栈有顺序存储和链式存储两种存储方法。

插入在表一端进行,而删除在表的另一端进行,这种数据结构称为队列,把允许插入的一端叫队尾(rear),把允许删除的一端叫队头(front)。

与线性表、栈类似,队列也有顺序存储和链式存储两种存储方法。

2.基础实验

实验一:

迷宫的求解

【实验内容与要求】

迷宫只有两个门,一个叫做入口,另一个叫做出口。

把一只老鼠从一个无顶盖的大盒子的入口处赶进迷宫。

迷宫中设置很多隔壁,对前进方向形成了多处障碍,在迷宫的唯一出口处放置了一块奶酪,吸引老鼠在迷宫中寻找通路以到达出口。

求解迷宫问题,即找出从入口到出口的路径。

【知识要点】

迷宫问题是栈应用的一个典型例子。

求解过程可采用回溯法。

回溯法是一种不断试探且及时纠正错误的搜索方法。

从入口出发,按某一方向向前探索,若能走通(未走过的),即某处可以到达,则到达新点,否则试探下一方向;若所有的方向均没有通路,则沿原路返回前一点,换下一个方向再继续试探,直到所有可能的通路都探索到,或找到一条通路,或无路可走又返回到入口点。

在求解过程中,为了保证在到达某一点后不能向前继续行走(无路)时,能正确返回前一点以便继续从下一个方向向前试探,则需要用一个栈保存所能够到达的每一点的下标及从该点前进的方向,栈中保存的就是一条迷宫的通路。

为了确保程序能够终止,调整时,必须保证曾被放弃过的填数序列不被再次试验,即要求按某种有序模型生成填数序列。

给解的候选者设定一个被检验的顺序,按这个顺序逐一生成候选者并检验。

【实现提示】

对于迷宫问题,用回溯法的难点就在如何为解空间排序,以确保曾被放弃过的填数序列不被再次试验,在二维迷宫里面,从出发点开始,每个点按四邻域算,按照右、上、左、下的顺序搜索下一落脚点,有路则进,无路即退,前点再从下一个方向搜索,即可构成一有序模型。

【思考与提高】

(1)迷宫程序如何防止重复到达某点,以避免发生死循环?

(2)迷宫程序如何找到所有的通路?

实验二:

停车场管理

【实验内容与要求】

设停车场内只有一个可停放n辆汽车的狭长通道,且只有一个大门可供汽车进出。

汽车在停车场内按车辆到达时间的先后顺序,依次由北向南排列(大门在最南端,最先到达的第一辆车停放在车场的最北端),若车场内已停满n辆汽车,则后来的汽车只能在门外的便道上等候,一旦有车开走,则排在便道上的第一辆车即可开入;当停车场内某辆车要离开时,在它之后开入的车辆必须先退出车场为它让路,待该辆车开出大门外,其它车辆再按原次序进入车场,每辆停放在车场的车在它离开停车场时必须按它停留的时间长短交纳费用。

试为停车场编制按上述要求进行管理的模拟程序。

【知识要点】

综合利用栈和队列模拟停车场管理,学习利用栈和队列解决实际问题。

【实现提示】

以栈模拟停车场,以队列模拟车场外的便道,按照从终端读入的输入数据序列进行模拟管理。

每一组输入数据包括三个数据项:

汽车“到达”或“离去”信息、汽车牌照号码及到达或离去的时刻,对每一组输入数据进行操作后的输出数据为:

若是车辆到达,则输出汽车在停车场内或便道上的停车位置;若是车离去;则输出汽车在停车场内停留的时间和应交纳的费用(在便道上停留的时间不收费)。

栈以顺序结构实现,队列以链表实现。

需另设一个栈,临时停放为给要离去的汽车让路而从停车场退出来的汽车,也用顺序存储结构实现。

输入数据按到达或离去的时刻有序。

栈中每个元素表示一辆汽车,包含两个数据项:

汽车的牌照号码和进入停车场的时刻。

设n=2,输入数据为:

(‘A’,1,5),(‘A’,2,10),(‘D’,1,15),(‘A’,3,20),(‘A’,4,25),(‘A’,5,30),(‘D’,2,35),(‘D’,4,40),(‘E’,0,0)。

每一组输入数据包括三个数据项:

汽车“到达”或“离去”信息、汽车牌照号码及到达或离去的时刻,其中,‘A’表示到达;‘D’表示离去,‘E’表示输入结束。

第三章串、多维数组和广义表

1.内容要点

·求串长strlen(char*s)

·串复制strcpy(char*to,char*from)

·串联接strcat(char*to,char*from)

·串比较charcmp(char*s1,char*s2)

·字符定位strchr(char*s,charc)

.串是特殊的线性表(结点是字符),所以串的存储结构与线性表的存储结构类似。

串的顺序存储结构简称为顺序串。

顺序串又可按存储分配的不同分为:

·静态存储分配:

直接用定长的字符数组来定义。

优点是涉及串长的操作速度快,但不适合插入、链接操作。

·动态存储分配:

是在定义串时不分配存储空间,需要使用时按所需串的长度分配存储单元。

串的链式存储就是用单链表的方式存储串值,串的这种链式存储结构简称为链串。

链串与单链表的差异只是它的结点数据域为单个字符。

为了解决"存储密度"低的状况,可以让一个结点存储多个字符,即结点的大小。

第四章树与二叉树

1.内容要点

树是n个结点的有限集合,非空时必须满足:

只有一个称为根的结点;其余结点形成m个不相交的子集,并称根的子树。

根是开始结点;结点的子树数称度;度为0的结点称叶子(终端结点);度不为0的结点称分支结点(非终端结点);除根外的分支结点称内部结点;

有序树是子树有左,右之分的树;无序树是子树没有左,右之分的树;森林是m个互不相交的树的集合;

树的四种不同表示方法:

·树形表示法;

·嵌套集合表示法;

·凹入表示法

·广义表表示法。

二叉树的定义:

是n≥0个结点的有限集,它是空集(n=0)或由一个根结点及两棵互不相交的分别称作这个根的左子树和右子树的二叉树组成。

二叉树不是树的特殊情形,与度数为2的有序树不同。

二叉树的4个重要性质:

·二叉树上第i层上的结点数目最多为2^(i-1)(i≥1).;

·深度为k的二叉树至多有(2^k)-1个结点(k≥1);

·在任意一棵二叉树中,若终端结点的个数为n0,度为2的结点数为n2,则n0=n2+1;

·具有n个结点的完全二叉树的深度为int(log2n)+1。

满二叉树是一棵深度为k,结点数为(2^k)-1的二叉树;完全二叉树是满二叉树在最下层自右向左去处部分结点;

二叉树的顺序存储结构就是把二叉树的所有结点按照层次顺序存储到连续的存储单元中。

(存储前先将其画成完全二叉树)树的存储结构多用的是链式存储。

BinTNode的结构为lchild|data|rchild,把所有BinTNode类型的结点,加上一个指向根结点的BinTree型头指针就构成了二叉树的链式存储结构,称为二叉链表。

它就是由根指针root唯一确定的。

共有2n个指针域,n+1个空指针。

根据访问结点的次序不同可得三种遍历:

先序遍历(前序遍历或先根遍历),中序遍历(或中根遍历)、后序遍历(或后根遍历)。

时间复杂度为O(n).

利用二叉链表中的n+1个空指针域来存放指向某种遍历次序下的前趋结点和后继结点的指针,这些附加的指针就称为"线索",加上线索的二叉链表就称为线索链表。

线索使得查找中序前趋和中序后继变得简单有效,但对于查找指定结点的前序前趋和后序后继并没有什么作用。

树和森林及二叉树的转换是唯一对应的。

转换方法:

·树变二叉树:

兄弟相连,保留长子的连线。

·二叉树变树:

结点的右孩子与其双亲连。

·森林变二叉树:

树变二叉树,各个树的根相连。

树的存储结构:

·有双亲链表表示法:

结点data|parent,对于求指定结点的双亲或祖先十分方便,但不适于求指定结点的孩子及后代。

·孩子链表表示法:

为树中每个结点data|next设置一个孩子链表firstchild,并将data|firstchild存放在一个向量中。

·双亲孩子链表表示法:

将双亲链表和孩子链表结合。

·孩子兄弟链表表示法:

结点结构leftmostchild|data|rightsibing,附加两个分别指向该结点的最左孩子和右邻兄弟的指针域。

树的前序遍历与相对应的二叉树的前序遍历一致;树的后序遍历与相对应的二叉树的中序遍历一致。

树的带权路径长度是树中所有叶结点的带权路径长度之和。

树的带权路径长度最小的二叉树就称为最优二叉树(即哈夫曼树)。

在叶子的权值相同的二叉树中,完全二叉树的路径长度最短。

哈夫曼树有n个叶结点,共有2n-1个结点,没有度为1的结点,这类树又称为严格二叉树。

变长编码技术可以使频度高的字符编码短,而频度低的字符编码长,但是变长编码可能使解码产生二义性。

如00、01、0001这三个码无法在解码时确定是哪一个,所以要求在字符编码时任一字符的编码都不是其他字符编码的前缀,这种码称为前缀码(其实是非前缀码)。

哈夫曼树的应用最广泛地是在编码技术上,它能够容易地求出给定字符集及其概率分布的最优前缀码。

哈夫曼编码的构造很容易,只要画好了哈夫曼树,按分支情况在左路径上写代码0,右路径上写代码1,然后从上到下到叶结点的相应路径上的代码的序列就是该结点的最优前缀码。

2.基础实验

实验一:

哈夫曼编/译码器

实验目的:

掌握哈夫曼树。

实验内容:

利用哈夫曼编码进行通信可以大大提高信道利用率,缩短信息传输时间,降低传输成本。

但是,这要求在发送端通过一个编码系统对待传数据预先编码,在接收端将传来的数据进行译(复原)。

对于双工信道(即可以双向传输信息的信道),每端都需要一个完整的编/译码系统。

试为这样的信息收发站写一个哈夫曼码的编/译码系统。

实验要求:

编写完整的系统,

要求具有以下功能:

1、I:

初始化(Initialization)。

从终端读入字符集大小n,以及n个字符和n个权值,建立哈夫曼树,并将它存入文件hfmTree中。

2、E:

编码(Encoding)。

利用以建好的哈夫曼树(如不在内存,则从文件hfmTree中读入),对文件ToBeTran中的正文进行编码,然后将结果存入文件CodeFile中。

3、D:

译码(Decoding)。

利用已建好的哈夫曼树将文件CodeFile中的代码进行译码,结果存入文件TextFile中。

4、P:

印代码文件(Print)。

将文件CodeFile以紧凑格式显示在终端上,每行50个代码。

同时将此字符形式的编码文件写入文件CodePrin中。

5、T:

印哈夫曼树(Treeprinting)。

将已在内存中的哈夫曼树以直观的方式(树或凹入表形式)显示在终端上,同时将此字符形式的哈夫曼树写入文件TreePrint中。

第5章图

1.内容要点

图的逻辑结构特征就是其结点(顶点)的前趋和后继的个数都是没有限制的,即任意两个结点之间之间都可能相关。

图GraphG=(V,E),V是顶点的有穷非空集合,E是顶点偶对的有穷集。

有向图Digraph:

每条边有方向;无向图Undigraph:

每条边没有方向。

有向完全图:

具有n*(n-1)条边的有向图;无向完全图:

具有n*(n-1)/2条边的无向图;

有根图:

有一个顶点有路径到达其它顶点的有向图;简单路径:

是经过顶点不同的路径;简单回路是开始和终端重合的简单路径;

网络:

是带权的图。

图的存储结构:

·邻接矩阵表示法:

用一个n阶方阵来表示图的结构是唯一的,适合稠密图。

·无向图:

邻接矩阵是对称的。

·有向图:

行是出度,列是入度。

建立邻接矩阵算法的时间是O(n+n^2+e),其时间复杂度为O(n^2)

·邻接表表示法:

用顶点表和邻接表构成不是唯一的,适合稀疏图。

·顶点表结构vertex|firstedge,指针域存放邻接表头指针。

·邻接表:

用头指针确定。

·无向图称边表;

·有向图又分出边表和逆邻接表;

·邻接表结点结构为adjvex|next,

时间复杂度为O(n+e).,空间复杂度为O(n+e).。

图的遍历:

·深度优先遍历:

借助于邻接矩阵的列。

使用栈保存已访问结点。

·广度优先遍历:

借助于邻接矩阵的行。

使用队列保存已访问结点。

生成树的定义:

若从图的某个顶点出发,可以系统地访问到图中所有顶点,则遍历时经过的边和图的所有顶点所构成的子图称作该图的生成树。

最小生成树:

图的生成树不唯一,从不同的顶点出发可得到不同的生成树,把权值最小的生成树称为最小生成树(MST)。

构造最小生成树的算法:

·Prim算法的时间复杂度为O(n^2)与边数无关适于稠密图。

·Kruskal算法的时间复杂度为O(lge),主要取决于边数,较适合于稀疏图。

最短路径的算法:

·Dijkstra算法,时间复杂度为O(n^2).·类似于prim算法。

拓扑排序:

是将有向无环图G中所有顶点排成一个线性序列,若∈E(G),则在线性序列u在v之前,这种线性序列称为拓扑序列。

拓扑排序也有两种方法:

·无前趋的顶点优先,每次输出一个无前趋的结点并删去此结点及其出边,最后得到的序列即拓扑序列。

·无后继的结点优先:

每次输出一个无后继的结点并删去此结点及其入边,最后得到的序列是逆拓扑序列。

2.基础实验

实验一:

校园导游咨询

实验目的:

掌握图的存储方法和最短路经算法。

实验内容:

设计一个校园导游程序,为来访客人提供各种信息查询服务。

测试数据根据实际情况指定。

提示:

一般情况下,校园的道路是双向通行的,可设校园平面图是一个无向图。

顶点和边均含有相关信息。

实验要求:

1、设计所在学校的校园平面图,所含景点不少于10个。

以图中顶点表示校内各景点,存放景点名称、代号、简介等信息;以边表示路径,存放路径长度等相关信息。

2、为来访客人提供图中任意景点相关信息的查询。

3、为来访客人提供图中任意景点的纹路查询,即查询任意两个景点之间的一条最短的简单路径。

第6章查找

1.内容要点

查找的同时对表做修改操作(如插入或删除)则相应的表称之为动态查找表,否则称之为静态查找表。

衡量查找算法效率优劣的标准是在查找过程中对关键字需要执行的平均比较次数(即平均查找长度ASL).

线性表查找的方法:

·顺序查找:

逐个查找,ASL=(n+1)/2;

·二分查找:

取中点int(n/2)比较,若小就比左区间,大就比右区间。

用二叉判定树表示。

ASL=(∑(每层结点数*层数))/N。

·分块查找。

要求“分块有序”,将表分成若干块内部不一定有序,并抽取各块中的最大关键字及其位置建立有序索引表。

二叉排序树(BST)定义是:

二叉排序树是空树或者满足如下性质的二叉树:

·若它的左子树非空,则左子树上所有结点的值均小于根结点的值;

·若它的右子树非空,则右子树上所有结点的值均大于根结点的值;

·左、右子树本身又是一棵二叉排序树。

二叉排序树的插入、建立、删除的算法平均时间性能是O(nlog2n)。

二叉排序树的删除操作可分三种情况进行处理:

·*P是叶子,则直接删除*P,即将*P的双亲*parent中指向*P的指针域置空即可。

·*P只有一个孩子*child,此时只需将*child和*p的双亲直接连接就可删去*p.

·*p有两个孩子,则先将*p结点的中序后继结点的数据到*p,删除中序后继结点。

关于B-树(多路平衡查找树)。

它适合在磁盘等直接存取设备上组织动态的查找表,是一种外查找算法。

建立的方式是从下向上拱起。

散列技术:

将结点按其关键字的散列地址存储到散列表的过程称为散列。

散列函数的选择有两条标准:

简单和均匀。

常见的散列函数构的造方法:

·.平方取中法:

hash=int((x^2)%100)

·.除余法:

表长为m,hash=x%m

·.相乘取整法:

hash=int(m*(x*A-int(x*A));A=0.618

·.随机数法:

hash=random(x)。

处理冲突的方法:

·开放定址法:

·一般形式为hi=(h(key)+di)%m1≤i≤m-1,开放定址法要求散列表的装填因子α≤1。

·开放定址法类型:

·线性探查法:

address=(hash(x)+i)%m;

·二次探查法:

address=(hash(x)+i^2)%m;

·双重散列法:

address=(hash(x)+i*hash(y))%m;

·拉链法:

·是将所有关键字为同义词的结点链接在同一个单链表中。

·拉链法的优点:

·拉链法处理冲突简单,且无堆积现象;

·链表上的结点空间是动态申请的适于无法确定表长的情况;

·拉链法中α可以大于1,结点较大时其指针域可忽略,因此节省空间;

·拉链法构造的散列表删除结点易实现。

·拉链法也有缺点:

当结点规模较小时,用拉链法中的指针域也要占用额外空间,还是开放定址法省空间。

第7章排序

1.内容要点

记录中可用某一项来标识一个记录,则称为关键字项,该数据项的值称为关键字。

排序是使文件中的记录按关键字递增(或递减)次序排列起来。

·基本操作:

比较关键字大小;改变指向记录的指针或移动记录。

·存储结构:

顺序结构、链表结构、索引结构。

经过排序后这些具有相同关键字的记录之间的相对次序保持不变,则称这种排序方法是稳定的,否则排序算法是不稳定的。

排序过程中不涉及数据的内、外存交换则称之为"内部排序"(内排序),反之,若存在数据的内外存交换,则称之为外排序。

内部排序方法可分五类:

插入排序、选择排序、交换排序、归并排序和分配排序。

评价排序算法好坏的标准主要有两条:

执行时间和所需的辅助空间,另外算法的复杂程序也是要考虑的一个因素。

插入排序:

·直接插入排序:

·逐个向前插入到合适位置。

·哨兵(监视哨)有两个作用:

·作为临变量存放R[i]

·是在查找循环中用来监视下标变量j是否越界。

·直接插入排序是就地的稳定排序。

时间复杂度为O(n^2),比较次数为(n+2)(n-1)/2;移动次数为(n+4)(n-1)/2;

希尔排序:

·等间隔的数据比较并按要求顺序排列,最后间隔为1。

·希尔排序是就地的不稳定排序。

时间复杂度为O(n^1.25),比较次数为(n^1.25);移动次数为(1.6n^1.25);

交换排序:

·冒泡排序:

·自下向上确定最轻的一个。

·自上向下确定最重的一个。

·自下向上确定最轻的一个,后自上向下确定最重的一个。

·冒泡排序是就地的稳定排序。

时间复杂度为O(n^2),比较次数为n(n-1)/2;移动次数为3n(n-1)/2;

·快速排序:

·以第一个元素为参考基准,设定、动两个指针,发生交换后指针交换位置,直到指针重合。

重复直到排序完成。

·快速排序是非就地的不稳定排序。

时间复杂度为O(nlog2n),比较次数为n(n-1)/2;

选择排序:

·直接选择排序:

·选择最小的放在比较区前。

·直接选择排序就地的不稳定排序。

时间复杂度为O(n^2)。

比较次数为n(n-1)/2;

·堆排序·建堆:

按层次将数据填入完全二叉树,从int(n/2)处向前逐个调整位置。

·然后将树根与最后一个叶

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 医药卫生 > 基础医学

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1