博客主页: 程序员好冰
欢迎 【点赞 关注 收藏⭐️ 留言】
本文由 程序员好冰 原创,CSDN 首发!
入站时间: 2022 年 07 月 13 日
✉️ 是非不入松风耳,花落花开只读书。
推荐书籍:《Java编程思想》,《Java 核心技术卷》
参考在线编程网站:牛客网力扣
作者水平很有限,如果发现错误,一定要及时告知作者哦!感谢感谢!
利用一维数组存储二叉树中的结点,并通过结点之间的下标来体现结点之间的逻辑关系。
通过完全二叉树的结构构建而成,把不存在的结点设置为特殊字符。
对一般的二叉树而言,这样做比较浪费空间。
所以顺序存储结构一般只用于完全二叉树。
#include
#include
#include
/*二叉树的顺序存储结构*/
#define OK 1
#define ERROR 0
#define TRUE 1
#define FALSE 0
#define MAX_TREE_SIZE 100//二叉树的最大结点数
typedef int Status;
typedef int ElemType;
typedef ElemType SqBiTree[MAX_TREE_SIZE];//0号单元存储根结点
typedef struct Position
{
int level;//当前结点所在的层数
int order;//当前结点的本层序号
}Position;
ElemType Nil=0;//0表示 不存在此结点
//1、构造空二叉树T
Status InitBiTree(SqBiTree T)
{
int i;
for(i=0;i<MAX_TREE_SIZE;i++){
T[i]=Nil;//将所有元素赋初值为空
}
return OK;
}
//2、构造一个按层序输入的顺序存储二叉树T
Status CreateBiTree(SqBiTree T)
{
printf("请按层序依次输入结点的值(0表示空结点,输入999表示结束),输入的结点数不能超过%d.\n",MAX_TREE_SIZE);
ElemType input;
int index=0;
while(1){
scanf("%d",&input);
if(input==999){
break;
}
T[index]=input;
//1、index!=0说明这个结点不是根节点
//2、T[(index+1)/2-1]==Nil说明当前结点不存在父节点
/*
T[(index+1)/2-1]是求一个结点的父节点
index+1是由于这里的数组是从0开始的
(index+1)/2隐藏着向下取整的功能,获得父节点的位置
(index+1)/2-1,减一是由于从0开始的
*/
//3、T[index]!=Nil说明当前结点不是空结点
/*
显然在二叉树中找不到这样的结点
1、只有根节点才没有父节点
2、其他结点都有父节点
*/
if(index!=0&&T[(index+1)/2-1]==Nil&&T[index]!=Nil){
printf("出现了无父节点的非根结点.\n");
return ERROR;
}
index++;
}
return OK;
}
//3、清空一棵树
#define ClearBiTree InitBiTree
//4、判断这棵树是否为空
Status BiTreeEmpty(SqBiTree T)
{
if(T[0]==Nil){
return TRUE;
}
return FALSE;
}
//5、返回这棵树的深度(按性质)
//根据二叉树的性质4
int BiTreeDepth(SqBiTree T)
{
int index=MAX_TREE_SIZE-1;
while(T[index]==Nil){
index--;
}
index+=1;//现在这个index代表着总的非空结点的个数
return ((int)(log10(index)/log10(2)))+1;
}
//6、返回这棵树的深度(按先序遍历)
int leftNum=0;
int rightNum=0;
//按照遍历递增的结果,使用前序遍历
int PreOrderTraverse_getDepth(SqBiTree T,int root)
{
if(T[2*root+1]!=Nil){
PreOrderTraverse_getDepth(T,2*root+1);
leftNum++;
}
if(T[2*root+2]!=Nil){
PreOrderTraverse_getDepth(T,2*root+2);
rightNum++;
}
return (leftNum>rightNum?leftNum:rightNum);
}
//7、返回这棵树的根结点
ElemType Root(SqBiTree T)
{
return T[0];
}
//8、返回处于指定位置的结点的值
ElemType Value(SqBiTree T,Position p)
{
/*
1、先算1到level-1层:2^(level-1)-1
2、再算第level层:order
3、考虑数组是从0开始的,再-1
4、总共:2^(levle-1)+order-2
*/
return T[(int)powl(2,p.level-1)+p.order-2];
}
//9、更新指定位置的值
Status SetValue(SqBiTree T,Position p,ElemType value)
{
/*
注意:
1、不能给一个没有父结点的结点赋非空值
2、不能给一个有左孩子或右孩子的结点赋空值
*/
int index;//从0开始
index=(int)pow(2,(p.level-1))+p.order-2;
if(value!=Nil&&T[(index+1)/2-1]==Nil){
return ERROR;
}
if(value==Nil&&(T[2*index+1]||T[2*index+2])){
return ERROR;
}
T[index]=value;
return OK;
}
//10、返回树中某个结点的父节点
ElemType GetParent(SqBiTree T,ElemType e)
{
//异常情况返回Nil
/*
异常情况:
1、树为空
2、该结点为根节点
*/
int i;
if(T[0]==Nil||T[0]==e){
return Nil;
}
for(i=1;i<MAX_TREE_SIZE;i++){
if(T[i]==e){
return T[(i+1)/2-1];
}
}
return Nil;
}
//11、返回树中某个结点的左孩子
ElemType GetLeftChild(SqBiTree T,ElemType e)
{
/*
1、空树没有左孩子
2、每个结点和其左孩子的关系:2*i+1
*/
if(T[0]==Nil){
return Nil;
}
int i;
for(i=0;i<MAX_TREE_SIZE;i++){
if(T[i]==e){
return T[2*i+1];
}
}
return Nil;
}
//12、返回树中某个结点的右孩子
ElemType GetRightChild(SqBiTree T,ElemType e)
{
/*
1、空树没有右孩子
2、每个结点和其左孩子的关系:2*i+2
*/
if(T[0]==Nil){
return Nil;
}
int i;
for(i=0;i<MAX_TREE_SIZE;i++){
if(T[i]==e){
return T[2*i+2];
}
}
return Nil;
}
//13、返回树中某个结点的左兄弟
ElemType GetLeftSibling(SqBiTree T,ElemType e)
{
if(T[0]==Nil){
return Nil;
}
int i;
for(i=0;i<MAX_TREE_SIZE;i++){
//怎么找到这个结点
/*
1、值为e——T[i]==e
2、有左兄弟的前提是自己是右孩子——i%2==0
其中,i的通式为:2*index+2
*/
if(T[i]==e&&i%2==0){
return T[i-1];
}
}
return Nil;
}
//14、返回树中某个结点的右兄弟
ElemType GetRightSibling(SqBiTree T,ElemType e)
{
if(T[0]==Nil){
return Nil;
}
int i;
for(i=0;i<MAX_TREE_SIZE;i++){
//怎么找到这个结点
/*
1、值为e——T[i]==e
2、有右兄弟的前提是自己是左孩子——i%2!=0
其中,i的通式为:2*index+1
*/
if(T[i]==e&&i%2!=0){
return T[i+1];
}
}
return Nil;
}
//15、先序遍历这棵树
//参数里的root有递归思想,是指每棵主树或者子树的根
Status PreOrderTraverse(SqBiTree T,int root)
{
printf("%d ",T[root]);
if(T[2*root+1]!=Nil){
PreOrderTraverse(T,2*root+1);
}
if(T[2*root+2]!=Nil){
PreOrderTraverse(T,2*root+2);
}
return OK;
}
//16、中序遍历这棵树
Status InOrderTraverse(SqBiTree T,int root)
{
if(T[2*root+1]!=Nil){
InOrderTraverse(T,2*root+1);
}
printf("%d ",T[root]);
if(T[2*root+2]!=Nil){
InOrderTraverse(T,2*root+2);
}
return OK;
}
//17、后续遍历这棵树
Status PostOrderTraverse(SqBiTree T,int root)
{
if(T[2*root+1]!=Nil){
PostOrderTraverse(T,2*root+1);
}
if(T[2*root+2]!=Nil){
PostOrderTraverse(T,2*root+2);
}
printf("%d ",T[root]);
return OK;
}
//18、层序遍历这棵树
void LevelOrderTraverse(SqBiTree T)
{
//先找到这棵树的最后一个结点
int i=MAX_TREE_SIZE-1;
int j;
while(T[i]==Nil){
i--;//找到最后一个非空结点的序号
}
for(j=0;j<=i;j++){
if(T[j]!=Nil){
printf("%d ",T[j]);
}
}
}
//19、逐层、按本层序号输出这棵树
void Print(SqBiTree T)
{
int level;
int order;
Position p;
for(level=1;level<=BiTreeDepth(T);level++){
printf("第%d层:",level);
for(order=1;order<=(int)pow(2,level-1);order++){
//按照位置找值
p.level=level;
p.order=order;
if(Value(T,p)!=Nil){
printf("%d ",Value(T,p));
}
}
printf("\n");
}
}
int main()
{
printf("请继续操作...\n");
SqBiTree T;
int input;
Position p;
ElemType value;
while(1){
printf("\n---------------------------------\n");
printf("1、构造空二叉树T.\n");
printf("2、构造一个按层序输入的顺序存储二叉树T.\n");
printf("3、清空一棵树.\n");
printf("4、判断这棵树是否为空.\n");
printf("5、返回这棵树的深度(按性质).\n");
printf("6、返回这棵树的深度(按先序遍历).\n");
printf("7、返回这棵树的根结点.\n");
printf("8、返回处于指定位置的结点的值.\n");
printf("9、更新指定位置的值.\n");
printf("10、返回树中某个结点的父节点.\n");
printf("11、返回树中某个结点的左孩子.\n");
printf("12、返回树中某个结点的右孩子.\n");
printf("13、返回树中某个结点的左兄弟.\n");
printf("14、返回树中某个结点的右兄弟.\n");
printf("15、先序遍历这棵树.\n");
printf("16、中序遍历这棵树.\n");
printf("17、后序遍历这棵树.\n");
printf("18、层序遍历这棵树.\n");
printf("19、逐层、按本层序号输出这棵树.\n");
printf("---------------------------------\n");
printf("\n");
printf("请输入对应操作的序号:");
scanf("%d",&input);
switch(input)
{
case 1:
if(InitBiTree(T)){
printf("构造成功.\n");
}
break;
case 2:
if(CreateBiTree(T)){
printf("创建成功.\n");
}
break;
case 3:
if(ClearBiTree(T)){
printf("成功清空这棵树.\n");
}
break;
case 4:
if(BiTreeEmpty(T)){
printf("这棵树为空.\n");
}else
{
printf("这棵树不为空.\n");
}
break;
case 5:
printf("树T的深度为%d.\n",BiTreeDepth(T));
break;
case 6:
printf("树T的深度为%d.\n",PreOrderTraverse_getDepth(T,0));
break;
case 7:
printf("树的根节点为:%d.\n",Root(T));
break;
case 8:
printf("按满二叉树计算...\n");
printf("请输入一个指定位置p(所在层数level,在该层中的序号order):");
scanf("%d,%d",&p.level,&p.order);
printf("第%d层第%d个元素为:%d.\n",p.level,p.order,Value(T,p));
break;
case 9:
printf("按满二叉树计算...\n");
printf("请输入一个指定位置e(所在层数level,在该层中的序号order):");
scanf("%d,%d",&p.level,&p.order);
printf("请输入需要赋的新值(value):");
scanf("%d",&value);
if(SetValue(T,p,value)){
printf("值修改成功.\n");
}
break;
case 10:
printf("请输入一个要求其父节点的结点值:");
scanf("%d",&value);
printf("结点e的父节点为:%d.\n",GetParent(T,value));
break;
case 11:
printf("请输入一个要求其左节点的结点值:");
scanf("%d",&value);
printf("结点e的左节点为:%d.\n",GetLeftChild(T,value));
break;
case 12:
printf("请输入一个要求其右节点的结点值:");
scanf("%d",&value);
printf("结点e的右节点为:%d.\n",GetRightChild(T,value));
break;
case 13:
printf("请输入一个要求其左兄弟的结点值:");
scanf("%d",&value);
printf("结点e的左兄弟为:%d.\n",GetLeftSibling(T,value));
break;
case 14:
printf("请输入一个要求其右兄弟的结点值:");
scanf("%d",&value);
printf("结点e的右兄弟为:%d.\n",GetRightSibling(T,value));
break;
case 15:
printf("先序遍历这棵树:");
PreOrderTraverse(T,0);
printf("\n");
break;
case 16:
printf("中序遍历这棵树:");
InOrderTraverse(T,0);
printf("\n");
break;
case 17:
printf("后序遍历这棵树:");
PostOrderTraverse(T,0);
printf("\n");
break;
case 18:
printf("层序遍历这棵树:");
LevelOrderTraverse(T);
printf("\n");
break;
case 19:
printf("打印这棵树的层次结构:\n");
Print(T);
printf("\n");
break;
default:
printf("输入的序号有误,请重新操作...\n");
break;
}
}
return 0;
}
#include
#include
#include
/*二叉树的顺序存储结构*/
#define OK 1
#define ERROR 0
#define TRUE 1
#define FALSE 0
#define MAX_TREE_SIZE 100//二叉树的最大结点数
typedef int Status;
typedef int ElemType;
typedef ElemType SqBiTree[MAX_TREE_SIZE];//0号单元存储根结点
typedef struct Position
{
int level;//当前结点所在的层数
int order;//当前结点的本层序号
}Position;
ElemType Nil=0;//0表示 不存在此结点
//1、构造空二叉树T
Status InitBiTree(SqBiTree T)
{
int i;
for(i=0;i<MAX_TREE_SIZE;i++){
T[i]=Nil;//将所有元素赋初值为空
}
return OK;
}
//2、构造一个按层序输入的顺序存储二叉树T
Status CreateBiTree(SqBiTree T)
{
printf("请按层序依次输入结点的值(0表示空结点,输入999表示结束),输入的结点数不能超过%d.\n",MAX_TREE_SIZE);
ElemType input;
int index=0;
while(1){
scanf("%d",&input);
if(input==999){
break;
}
T[index]=input;
//1、index!=0说明这个结点不是根节点
//2、T[(index+1)/2-1]==Nil说明当前结点不存在父节点
/*
T[(index+1)/2-1]是求一个结点的父节点
index+1是由于这里的数组是从0开始的
(index+1)/2隐藏着向下取整的功能,获得父节点的位置
(index+1)/2-1,减一是由于从0开始的
*/
//3、T[index]!=Nil说明当前结点不是空结点
/*
显然在二叉树中找不到这样的结点
1、只有根节点才没有父节点
2、其他结点都有父节点
*/
if(index!=0&&T[(index+1)/2-1]==Nil&&T[index]!=Nil){
printf("出现了无父节点的非根结点.\n");
return ERROR;
}
index++;
}
return OK;
}
//3、清空一棵树
#define ClearBiTree InitBiTree
//4、判断这棵树是否为空
Status BiTreeEmpty(SqBiTree T)
{
if(T[0]==Nil){
return TRUE;
}
return FALSE;
}
//5、返回这棵树的深度(按性质)
//根据二叉树的性质4
int BiTreeDepth(SqBiTree T)
{
int index=MAX_TREE_SIZE-1;
while(T[index]==Nil){
index--;
}
index+=1;//现在这个index代表着总的非空结点的个数
return ((int)(log10(index)/log10(2)))+1;
}
//6、返回这棵树的深度(按先序遍历)
int leftNum=0;
int rightNum=0;
//按照遍历递增的结果,使用前序遍历
int PreOrderTraverse_getDepth(SqBiTree T,int root)
{
if(T[2*root+1]!=Nil){
PreOrderTraverse_getDepth(T,2*root+1);
leftNum++;
}
if(T[2*root+2]!=Nil){
PreOrderTraverse_getDepth(T,2*root+2);
rightNum++;
}
return (leftNum>rightNum?leftNum:rightNum);
}
//7、返回这棵树的根结点
ElemType Root(SqBiTree T)
{
return T[0];
}
//8、返回处于指定位置的结点的值
ElemType Value(SqBiTree T,Position p)
{
/*
1、先算1到level-1层:2^(level-1)-1
2、再算第level层:order
3、考虑数组是从0开始的,再-1
4、总共:2^(levle-1)+order-2
*/
return T[(int)powl(2,p.level-1)+p.order-2];
}
//9、更新指定位置的值
Status SetValue(SqBiTree T,Position p,ElemType value)
{
/*
注意:
1、不能给一个没有父结点的结点赋非空值
2、不能给一个有左孩子或右孩子的结点赋空值
*/
int index;//从0开始
index=(int)pow(2,(p.level-1))+p.order-2;
if(value!=Nil&&T[(index+1)/2-1]==Nil){
return ERROR;
}
if(value==Nil&&(T[2*index+1]||T[2*index+2])){
return ERROR;
}
T[index]=value;
return OK;
}
//10、返回树中某个结点的父节点
ElemType GetParent(SqBiTree T,ElemType e)
{
//异常情况返回Nil
/*
异常情况:
1、树为空
2、该结点为根节点
*/
int i;
if(T[0]==Nil||T[0]==e){
return Nil;
}
for(i=1;i<MAX_TREE_SIZE;i++){
if(T[i]==e){
return T[(i+1)/2-1];
}
}
return Nil;
}
//11、返回树中某个结点的左孩子
ElemType GetLeftChild(SqBiTree T,ElemType e)
{
/*
1、空树没有左孩子
2、每个结点和其左孩子的关系:2*i+1
*/
if(T[0]==Nil){
return Nil;
}
int i;
for(i=0;i<MAX_TREE_SIZE;i++){
if(T[i]==e){
return T[2*i+1];
}
}
return Nil;
}
//12、返回树中某个结点的右孩子
ElemType GetRightChild(SqBiTree T,ElemType e)
{
/*
1、空树没有右孩子
2、每个结点和其左孩子的关系:2*i+2
*/
if(T[0]==Nil){
return Nil;
}
int i;
for(i=0;i<MAX_TREE_SIZE;i++){
if(T[i]==e){
return T[2*i+2];
}
}
return Nil;
}
//13、返回树中某个结点的左兄弟
ElemType GetLeftSibling(SqBiTree T,ElemType e)
{
if(T[0]==Nil){
return Nil;
}
int i;
for(i=0;i<MAX_TREE_SIZE;i++){
//怎么找到这个结点
/*
1、值为e——T[i]==e
2、有左兄弟的前提是自己是右孩子——i%2==0
其中,i的通式为:2*index+2
*/
if(T[i]==e&&i%2==0){
return T[i-1];
}
}
return Nil;
}
//14、返回树中某个结点的右兄弟
ElemType GetRightSibling(SqBiTree T,ElemType e)
{
if(T[0]==Nil){
return Nil;
}
int i;
for(i=0;i<MAX_TREE_SIZE;i++){
//怎么找到这个结点
/*
1、值为e——T[i]==e
2、有右兄弟的前提是自己是左孩子——i%2!=0
其中,i的通式为:2*index+1
*/
if(T[i]==e&&i%2!=0){
return T[i+1];
}
}
return Nil;
}
//15、先序遍历这棵树
//参数里的root有递归思想,是指每棵主树或者子树的根
Status PreOrderTraverse(SqBiTree T,int root)
{
printf("%d ",T[root]);
if(T[2*root+1]!=Nil){
PreOrderTraverse(T,2*root+1);
}
if(T[2*root+2]!=Nil){
PreOrderTraverse(T,2*root+2);
}
return OK;
}
//16、中序遍历这棵树
Status InOrderTraverse(SqBiTree T,int root)
{
if(T[2*root+1]!=Nil){
InOrderTraverse(T,2*root+1);
}
printf("%d ",T[root]);
if(T[2*root+2]!=Nil){
InOrderTraverse(T,2*root+2);
}
return OK;
}
//17、后续遍历这棵树
Status PostOrderTraverse(SqBiTree T,int root)
{
if(T[2*root+1]!=Nil){
PostOrderTraverse(T,2*root+1);
}
if(T[2*root+2]!=Nil){
PostOrderTraverse(T,2*root+2);
}
printf("%d ",T[root]);
return OK;
}
//18、层序遍历这棵树
void LevelOrderTraverse(SqBiTree T)
{
//先找到这棵树的最后一个结点
int i=MAX_TREE_SIZE-1;
int j;
while(T[i]==Nil){
i--;//找到最后一个非空结点的序号
}
for(j=0;j<=i;j++){
if(T[j]!=Nil){
printf("%d ",T[j]);
}
}
}
//19、逐层、按本层序号输出这棵树
void Print(SqBiTree T)
{
int level;
int order;
Position p;
for(level=1;level<=BiTreeDepth(T);level++){
printf("第%d层:",level);
for(order=1;order<=(int)pow(2,level-1);order++){
//按照位置找值
p.level=level;
p.order=order;
if(Value(T,p)!=Nil){
printf("%d ",Value(T,p));
}
}
printf("\n");
}
}
int main()
{
printf("请继续操作...\n");
SqBiTree T;
int input;
Position p;
ElemType value;
while(1){
printf("\n---------------------------------\n");
printf("1、构造空二叉树T.\n");
printf("2、构造一个按层序输入的顺序存储二叉树T.\n");
printf("3、清空一棵树.\n");
printf("4、判断这棵树是否为空.\n");
printf("5、返回这棵树的深度(按性质).\n");
printf("6、返回这棵树的深度(按先序遍历).\n");
printf("7、返回这棵树的根结点.\n");
printf("8、返回处于指定位置的结点的值.\n");
printf("9、更新指定位置的值.\n");
printf("10、返回树中某个结点的父节点.\n");
printf("11、返回树中某个结点的左孩子.\n");
printf("12、返回树中某个结点的右孩子.\n");
printf("13、返回树中某个结点的左兄弟.\n");
printf("14、返回树中某个结点的右兄弟.\n");
printf("15、先序遍历这棵树.\n");
printf("16、中序遍历这棵树.\n");
printf("17、后序遍历这棵树.\n");
printf("18、层序遍历这棵树.\n");
printf("19、逐层、按本层序号输出这棵树.\n");
printf("---------------------------------\n");
printf("\n");
printf("请输入对应操作的序号:");
scanf("%d",&input);
switch(input)
{
case 1:
if(InitBiTree(T)){
printf("构造成功.\n");
}
break;
case 2:
if(CreateBiTree(T)){
printf("创建成功.\n");
}
break;
case 3:
if(ClearBiTree(T)){
printf("成功清空这棵树.\n");
}
break;
case 4:
if(BiTreeEmpty(T)){
printf("这棵树为空.\n");
}else
{
printf("这棵树不为空.\n");
}
break;
case 5:
printf("树T的深度为%d.\n",BiTreeDepth(T));
break;
case 6:
printf("树T的深度为%d.\n",PreOrderTraverse_getDepth(T,0));
break;
case 7:
printf("树的根节点为:%d.\n",Root(T));
break;
case 8:
printf("按满二叉树计算...\n");
printf("请输入一个指定位置p(所在层数level,在该层中的序号order):");
scanf("%d,%d",&p.level,&p.order);
printf("第%d层第%d个元素为:%d.\n",p.level,p.order,Value(T,p));
break;
case 9:
printf("按满二叉树计算...\n");
printf("请输入一个指定位置e(所在层数level,在该层中的序号order):");
scanf("%d,%d",&p.level,&p.order);
printf("请输入需要赋的新值(value):");
scanf("%d",&value);
if(SetValue(T,p,value)){
printf("值修改成功.\n");
}
break;
case 10:
printf("请输入一个要求其父节点的结点值:");
scanf("%d",&value);
printf("结点e的父节点为:%d.\n",GetParent(T,value));
break;
case 11:
printf("请输入一个要求其左节点的结点值:");
scanf("%d",&value);
printf("结点e的左节点为:%d.\n",GetLeftChild(T,value));
break;
case 12:
printf("请输入一个要求其右节点的结点值:");
scanf("%d",&value);
printf("结点e的右节点为:%d.\n",GetRightChild(T,value));
break;
case 13:
printf("请输入一个要求其左兄弟的结点值:");
scanf("%d",&value);
printf("结点e的左兄弟为:%d.\n",GetLeftSibling(T,value));
break;
case 14:
printf("请输入一个要求其右兄弟的结点值:");
scanf("%d",&value);
printf("结点e的右兄弟为:%d.\n",GetRightSibling(T,value));
break;
case 15:
printf("先序遍历这棵树:");
PreOrderTraverse(T,0);
printf("\n");
break;
case 16:
printf("中序遍历这棵树:");
InOrderTraverse(T,0);
printf("\n");
break;
case 17:
printf("后序遍历这棵树:");
PostOrderTraverse(T,0);
printf("\n");
break;
case 18:
printf("层序遍历这棵树:");
LevelOrderTraverse(T);
printf("\n");
break;
case 19:
printf("打印这棵树的层次结构:\n");
Print(T);
printf("\n");
break;
default:
printf("输入的序号有误,请重新操作...\n");
break;
}
}
return 0;
}
先看后赞,养成习惯!
先看后赞,养成习惯!
觉得文章写得不错的老铁们,点赞评论关注走一波!谢谢啦!