【C语言15】单链表,(对于二级指针与一级指针应用的详细讲述)

文章目录

  • 单链表
    • 1.单链表的介绍
    • 2.单链表的实现
        • 2.1.1单链表结点的创建与销毁
        • 2.1.2单链表尾插
        • 2.1.3单链表打印
        • 2.1.4尾删
        • 2.1.5头插
        • 2.1.6头删
        • 2.1.7查找
        • 2.1.8在pos位置之后插入数据
        • 2.1.9删除pos位置

单链表

1.单链表的介绍

链表是一种物理存储结构上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表
中的指针链接次序实现的 。

在上篇博客中,我们可以很清晰的看到顺序表的结构,但是链表不可以,链表的链接就是由指针指引的,

一个数据,他可能间隔着N个内存空间,但是它们却又是实实在在相连的,为了详细说明链表,我准备这么几张图片:
在这里插入图片描述

我们看到,单链表就像一个火车,由一个指针来确定他们不同节点的位置,从而串接起来,但是我们要了解一件事,图片中的箭头是虚拟的,是想象的,我们能确定下一个节点位置只有指针;

2.单链表的实现

#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<malloc.h>
typedef int SeDataType;
//定义结点
typedef struct SeqList
{
	SeDataType data;
	struct SeqList* next;
}SeNode;
//开辟节点
SeNode* BuySeqListNode(SeNode* phead, SeDataType x)
//销毁
void SeqListDestroy(SeNode** phead);
//打印
void SeqListPrint(SeNode* phead);
//尾插
void SeqListPushBack(SeNode** phead, SeDataType x);
//尾删
void SeqLIstPopBack(SeNode** phead);
//头插
void SeqListPushFront(SeNode** phead, SeDataType x);
//头删
void SeqListPopFront(SeNode** phead);
//pos位置之后插入
void SeqListInsterAfter(SeNode* pos, SeDataType x);
//删除pos位置
void SeqListEraseAfter(SeNode* pos);

为了实现单链表,我们需要实现以上接口

2.1.1单链表结点的创建与销毁

//初始化
SeNode* BuySeqListNode(SeDataType x)
{
	SeNode* newnode = (SeNode*)malloc(sizeof(SeNode));//创建结点
	if (newnode == NULL)//判断结点是否生成成功
	{
		perror("BuySeqListNode");
		exit(-1);
	}
	newnode->data = x;//赋值
	newnode->next = NULL;
	return newnode;//返回结点地址
}
//销毁
void SeqListDestroy(SeNode** phead)
{
	assert(phead);//判断是否为空
	while (*phead)//循环free空间
	{
		SeNode* next = (*phead)->next;//记录下一个节点,避免链接丢失
		free(*phead);//释放
		*phead = next;
	}
	*phead = NULL;//置空
}

当读完这串代码后,我们会发现这两个函数使用了完全不一样的指针类型.开辟节点使用的是一级指针,销毁结点使用的是二级指针.要注意,这是本篇博客难度最高的知识点,考验各位对指针的理解程度

在这里插入图片描述

在调用PushBack函数后,我们成功创建了一个节点node,我们在此时这个结点是孤立的
在这里插入图片描述

那么如何让让plist和node链接起来呢.那就是指针.,在此时,如果我们想要用pilst链接node,必须传递plist的地址,只有传递地址才能让plist的指向改变.如果不传递地址,后续操作只是一份临时拷贝

此时,一个纠结点就出现了.我plist本事就是指针,为什么要传递指针的地址呢.

我们来看一张图片

这张图生动的展示了指针本质上的区别.指针也是一种变量,是变量就会有地址.想要改变变量,就必须通过地址改变;在对plist进行修改的时候,虽然plist就是指针,但想要改变他存贮的值,就必须传递本身的地址,这就是为什么传递二级指针的原因.

2.1.2单链表尾插

如何进行尾插操作呢,我们要想明白一件事情,在我们创建的Sqnode类型中, next指向下一个结点.所以,如果我们想要尾插,必须找到next的前一个结点进行链接

void SeqListPushBack(SeNode** phead, SeDataType x)
{
	assert(phead);//判断指针是否为空
	SeNode* node = BuySeqListNode(x);//开辟节点
	if (*phead == NULL)//如果*phead为空,代表链表为空,之间赋值替换即可
	{
		*phead = node;
	}
	else
	{
		SeNode* tail = *phead;
		while (tail->next != NULL)//如果不为空,则遍历链表,在最后一个结点进行链接
		{
			tail = tail->next;
		}
		tail->next = node;
	}
}

此时,我们完成了尾插接口的实现,如何判断程序是否正确呢,我们可以通过调试直观地观察,也可以提前将打印接口实现观察,我们使用实现打印接口.

2.1.3单链表打印

应为我们只是要打印而无需任何改变指针的操作,所以只需要传递一级指针遍历整个数组即可

void SeqListPrint(SeNode* phead)
{
	SeNode* cur = phead;//记录位置
	while (cur)
	{
		printf("%d ", cur->data);//打印
		cur = cur->next;//赋值遍历
	}
}

在这里插入图片描述

程序正确,成功运行

2.1.4尾删

尾删的操作与尾插类似,不同的是我们需要遍历到倒数第二个结点,通过倒数第二个节点的next来释放最后一个节点达成尾删操作.因为需要改变内容,所以依旧传递二级指针
在这里插入图片描述

void SeqListPopBack(SeNode** phead)
{
	assert(phead);//判断指针是否为空
	assert(*phead);//判断指针指向的内容是否为空
	if ((*phead)->next == NULL)//如果只有一个节点,直接释放
	{
		free(*phead);
		*phead = NULL;
	}
	else
	{
		SeNode* tail = *phead;
		while (tail->next->next != NULL)//如果多个,遍历到末尾的前一个释放
		{
			tail = tail->next;
		}
		free(tail->next);
		tail->next = NULL;                       
	}
}

在这里插入图片描述

2.1.5头插

头插需要注意的是对于指针的操作,在有多个节点时,需要考虑如何在头插的同时链接原头结点

而在一个节点是直接替换赋值即可.

在这里插入图片描述

void SeqListPushFront(SeNode** phead, SeDataType x)
{
	assert(phead);//判断指针是否为空
	SeNode* newnode = BuySeqListNode(x);//创建新节点
	if (*phead == NULL)//当只有一个节点的时候,直接赋值
	{
		*phead = newnode;
	}
	else//多个节点是先链接在赋值
	{
		newnode->next = *phead;
		*phead = newnode;
	}
}

在这里插入图片描述

运行成功

2.1.6头删

头删要注意的与头插类似,直接上图
在这里插入图片描述

//头删
void SeqListPopFront(SeNode** phead)
{
	assert(phead);//判断指针是否为空
	assert(*phead);//判断指针指向的内容是否为空
	if ((*phead)->next == NULL)//只有一个节点时,直接释放
	{
		free(*phead);
		*phead = NULL;
	}
	else//多个节点时,记录新头结点,释放原头结点
	{	
		SeNode* pphead = (*phead)->next;
		free(*phead);
		*phead = pphead;
	}
}

在这里插入图片描述

运行成功

2.1.7查找

该接口原理与打印接口相同,同是遍历链表,不同点为该函数会返回一个地址

SeNode* SeqListFind(SeNode* phead,SeDataType x)
{
	assert(phead);//判断指针是否为空
	SeNode* cur = phead;//赋值遍历
	while (cur->next != NULL)
	{
		if (cur->data == x)//判断相等
		{
			return cur;//相等返回地址
		}
		cur = cur->next;
	}
	return NULL;	//不等返回NULL;
}

在这里插入图片描述

2.1.8在pos位置之后插入数据

在这里插入图片描述

void SeqListInsterAfter(SeNode**phead,SeNode* pos, SeDataType x)
{
	assert(pos);//判断指针是否为空
	assert(*phead);
	if (pos == *phead)//如果相等,就是头插
	{
		SeqListPushFront(phead,x);
	}
	else
	{
		SeNode* node = BuySeqListNode(x);
		SeNode* pphead = pos->next;//记录原结点链接的数据
		node->next = pphead;//链接
		pos->next = node;
	}
}

在这里插入图片描述

修改成功

2.1.9删除pos位置

在这里插入图片描述

void SeqListEraseAfter(SeNode** phead, SeNode* pos)
{
	assert(pos);//判断空指针
	if (pos==*phead)//如果相等就是头删
	{
		SeqListPopFront(phead);
	}
	else
	{
		SeNode* cur = *phead;
		while (cur->next != pos)//记录pos的前一个位置
		{
			cur = cur->next;
		}
		cur->next = pos->next;//链接
		free(pos);//释放
		pos = NULL;
	}
}

完整代码

//SeqList.h
#define _CRT_SECURE_NO_WARNINGS 1
#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<malloc.h>
typedef int SeDataType;
//定义结点
typedef struct SeqList
{
	SeDataType data;
	struct SeqList* next;
}SeNode;
//初始化
void SeqListInit(SeNode** phead);
//销毁
void SeqListDestroy(SeNode** phead);
//打印
void SeqListPrint(SeNode* phead);
//尾插
void SeqListPushBack(SeNode** phead, SeDataType x);
//尾删
void SeqListPopBack(SeNode** phead);
//头插
void SeqListPushFront(SeNode** phead, SeDataType x);
//头删
void SeqListPopFront(SeNode** phead);
//pos位置之后插入
void SeqListInsterAfter(SeNode** phead,SeNode* pos, SeDataType x);
//删除pos位置
void SeqListEraseAfter(SeNode** phead, SeNode* pos);

//SeqList.c
#define _CRT_SECURE_NO_WARNINGS 1
#include"SeqList.h"
//初始化
SeNode* BuySeqListNode(SeDataType x)
{
	SeNode* newnode = (SeNode*)malloc(sizeof(SeNode));//创建结点
	if (newnode == NULL)//判断结点是否生成成功
	{
		perror("BuySeqListNode");
		exit(-1);
	}
	newnode->data = x;//赋值
	newnode->next = NULL;
	return newnode;//返回结点地址
}
//销毁
void SeqListDestroy(SeNode** phead)
{
	assert(phead);//判断是否为空
	while (*phead)//循环free空间
	{
		SeNode* next = (*phead)->next;//记录下一个节点,避免链接丢失
		free(*phead);//释放
		*phead = next;
	}
	*phead = NULL;//置空
}
//打印
void SeqListPrint(SeNode* phead)
{
	SeNode* cur = phead;//记录位置
	while (cur)
	{
		printf("%d->", cur->data);//打印
		cur = cur->next;//赋值遍历
	}
	printf("NULL\n");
}
//尾插
void SeqListPushBack(SeNode** phead, SeDataType x)
{
	assert(phead);//判断指针是否为空
	SeNode* node = BuySeqListNode(x);//开辟节点
	if (*phead == NULL)//如果*phead为空,代表链表为空,之间赋值替换即可
	{
		*phead = node;
	}
	else
	{
		SeNode* tail = *phead;
		while (tail->next != NULL)//如果不为空,则遍历链表,在最后一个结点进行链接
		{
			tail = tail->next;
		}
		tail->next = node;
	}
}
//尾删
void SeqListPopBack(SeNode** phead)
{
	assert(phead);//判断指针是否为空
	assert(*phead);//判断指针指向的内容是否为空
	if ((*phead)->next == NULL)//如果只有一个节点,直接释放
	{
		free(*phead);
		*phead = NULL;
	}
	else
	{
		SeNode* tail = *phead;
		while (tail->next->next != NULL)//如果多个,遍历到末尾的前一个释放
		{
			tail = tail->next;
		}
		free(tail->next);
		tail->next = NULL;                       
	}
}
//头插
void SeqListPushFront(SeNode** phead, SeDataType x)
{
	assert(phead);//判断指针是否为空
	SeNode* newnode = BuySeqListNode(x);//创建新节点
	if (*phead == NULL)//当只有一个节点的时候,直接赋值
	{
		*phead = newnode;
	}
	else//多个节点是先链接在赋值
	{
		newnode->next = *phead;
		*phead = newnode;
	}
}
//头删
void SeqListPopFront(SeNode** phead)
{
	assert(phead);//判断指针是否为空
	assert(*phead);//判断指针指向的内容是否为空
	if ((*phead)->next == NULL)//只有一个节点时,直接释放
	{
		free(*phead);
		*phead = NULL;
	}
	else//多个节点时,记录新头结点,释放原头结点
	{	
		SeNode* pphead = (*phead)->next;
		free(*phead);
		*phead = pphead;
	}
}
SeNode* SeqListFind(SeNode* phead,SeDataType x)
{
	assert(phead);//判断指针是否为空
	SeNode* cur = phead;//赋值遍历
	while (cur->next != NULL)
	{
		if (cur->data == x)//判断相等
		{
			return cur;//相等返回地址
		}
		cur = cur->next;
	}
	return NULL;	//不等返回NULL;
}
//pos位置之后插入
void SeqListInsterAfter(SeNode**phead,SeNode* pos, SeDataType x)
{
	assert(pos);//判断指针是否为空
	assert(*phead);
	if (pos == *phead)//如果相等,就是头插
	{
		SeqListPushFront(phead,x);
	}
	else
	{
		SeNode* node = BuySeqListNode(x);
		SeNode* pphead = pos->next;//记录原结点链接的数据
		node->next = pphead;//链接
		pos->next = node;
	}
}
//删除pos位置
void SeqListEraseAfter(SeNode** phead, SeNode* pos)
{
	assert(pos);//判断空指针
	if (pos==*phead)//如果相等就是头删
	{
		SeqListPopFront(phead);
	}
	else
	{
		SeNode* cur = *phead;
		while (cur->next != pos)//记录pos的前一个位置
		{
			cur = cur->next;
		}
		cur->next = pos->next;//链接
		free(pos);//释放
		pos = NULL;
	}
}


//SeqListTest.c
#define _CRT_SECURE_NO_WARNINGS 1
#include"SeqList.h"
void SeqListTest()
{
	SeNode* plist = NULL;
	SeqListPushFront(&plist, 5);
	SeqListPushFront(&plist, 4);
	SeqListPushFront(&plist, 3);
	SeqListPushFront(&plist, 2);
	SeqListPushFront(&plist, 1);
	SeqListPushFront(&plist, 0);
	SeqListPrint(plist);
	SeNode* ptr = SeqListFind(plist, 3);
	if (ptr != NULL)
	{
		SeqListEraseAfter(&plist, ptr);
	}
	else
	{
		printf("数据有误\n");
	}
	SeqListPrint(plist);
	/*SeNode* ptr = SeqListFind(plist, 3);
	if (ptr != NULL)
	{
		printf("%p %d", ptr,ptr->data);
	}
	else
	{
		printf("数据有误\n");
	}*/
	//SeqListPopFront(&plist);
	//SeqListPopFront(&plist);
	//SeqListPopFront(&plist);
	//SeqListPopFront(&plist);
	//SeqListPopFront(&plist);
	//SeqListPrint(plist);
	//SeqListPopFront(&plist);
	//SeqListPrint(plist);
	/*SeqListPushBack(&plist, 1);
	SeqListPushBack(&plist, 2);
	SeqListPushBack(&plist, 3);
	SeqListPushBack(&plist, 4);
	SeqListPushBack(&plist, 5);
	SeqListPrint(plist);
	SeqListPopBack(&plist);
	SeqListPrint(plist);
	SeqListPopBack(&plist);
	SeqListPrint(plist);
	SeqListPopBack(&plist);
	SeqListPrint(plist);
	SeqListPopBack(&plist);
	SeqListPrint(plist);
	SeqListPopBack(&plist);
	SeqListPrint(plist);
	SeqListDestroy(&plist);*/

}
int main()
{
	SeqListTest();
	return 0;
}

ont(&plist);

//SeqListPrint(plist);
/SeqListPushBack(&plist, 1);
SeqListPushBack(&plist, 2);
SeqListPushBack(&plist, 3);
SeqListPushBack(&plist, 4);
SeqListPushBack(&plist, 5);
SeqListPrint(plist);
SeqListPopBack(&plist);
SeqListPrint(plist);
SeqListPopBack(&plist);
SeqListPrint(plist);
SeqListPopBack(&plist);
SeqListPrint(plist);
SeqListPopBack(&plist);
SeqListPrint(plist);
SeqListPopBack(&plist);
SeqListPrint(plist);
SeqListDestroy(&plist);
/

}
int main()
{
SeqListTest();
return 0;
}



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

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

相关文章

【MyBatis 学习一】认识MyBatis 第一个MyBatis查询

目录 一、认识MyBatis 1、MyBatis是什么&#xff1f; 2、为什么要学习MyBatis? 二、配置MyBatis环境 1、建库与建表 2、创建新项目 3、xml文件配置 &#xff08;1&#xff09;配置数据库连接 &#xff08;2&#xff09;配置 MyBatis 中的 XML 路径 三、测试&#x…

优惠券秒杀(二)

库存超卖问题分析 库存超卖问题其本质就是多个线程操作共享数据产生的线程安全问题&#xff0c;即当一个线程在执行操作共享数据的多条代码的过程中&#xff0c;其他线程也参与了进来&#xff0c;导致了线程安全问题的产生。例如&#xff1a;线程1发送请求&#xff0c;查询库存…

所有docker命令无效,解决办法

目录 ■前言 今天使用docker时&#xff0c;所有命令无效 ■解决办法如下 1.停止docker服务 2.查看状态 3.删除之前的docker相关的文件 4.再次查看状态 5.使用相关命令 &#xff08;好用了&#xff09; 6.重新下载镜像 ■前言 今天使用docker时&#xff0c;所有命令无…

MyBatis(简化数据库操作的持久层框架)--快速入门[上]

&#x1f600;前言 本篇博文是我在学习过程中的记录&#xff0c;分为上中下三个篇章&#xff0c;记录了我的一些学习心得&#xff0c;希望能够帮助到你&#x1f60a; &#x1f3e0;个人主页&#xff1a;晨犀主页 &#x1f9d1;个人简介&#xff1a;大家好&#xff0c;我是晨犀&…

炎热夏天,VR全景让你宅家也能逛风景

夏天的快乐都是空调给的&#xff0c;进入三伏天气以来&#xff0c;连续的高温让人坐着都是一身汗&#xff0c;尤其是活泼好动的小朋友们&#xff0c;不出去玩那是不可能的。不妨改变下策略&#xff0c;让小朋友们转战线上&#xff0c;还能学习知识&#xff0c;是不是美滋滋呢~~…

FPGA XDMA 中断模式实现 PCIE3.0 AD7606采集 提供2套工程源码和QT上位机源码

目录 1、前言2、我已有的PCIE方案3、PCIE理论4、总体设计思路和方案AD7606数据采集和缓存XDMA简介XDMA中断模式QT上位机及其源码 5、vivado工程1--BRAM缓存6、vivado工程2--DDR4缓存7、上板调试验证8、福利&#xff1a;工程代码的获取 1、前言 PCIE&#xff08;PCI Express&am…

BMapGL -- 生成多个maker,获取指定标识的maker,并清除他们

需求描述: 在使用 Baidu Map JavaScript API 创建多个标记时,可以为每个标记设置一个唯一的标识符(identifier),以便在以后可以根据标识符获取特定的标记,并清除它们。 代码: // 创建地图实例 var map = new BMapGL.Map("container");// 创建标记1 var poin…

Jmeter配置起来太繁琐?试试RunnerGo

在用jmeter做性能测试时想看完整一点的测试报告&#xff0c;想配置阶梯模式来压测&#xff0c;想配置不同的接口并发这些都需要安装插件并且影响机器性能&#xff0c;想做自动化测试还得放到jenkins&#xff0c;这些配置起来太繁琐。今天给大家推荐一款测试平台RunnerGo&#x…

1334179-85-9,BTTAA,是各种化学生物学实验中生物偶联所需

资料编辑|陕西新研博美生物科技有限公司小编MISSwu​ BTTAA试剂 | 基础知识概述&#xff08;部分&#xff09;: 中文名称&#xff1a;2-[4-({双[(1-叔丁基-1H-1,2,3-三唑-4-基)甲基]氨基}甲基)-1H-1,2,3-三唑-1-基]乙酸 英文名称&#xff1a;BTTAA CAS号&#xff1a;1334179-8…

如何区分接口测试和功能测试

接口测试和功能测试的区别&#xff1a; 2023最新Jmeter接口测试从入门到精通&#xff08;全套项目实战教程&#xff09; 本文主要分为两个部分&#xff1a; 第一部分&#xff1a;主要从问题出发&#xff0c;引入接口测试的相关内容并与前端测试进行简单对比&#xff0c;总结两者…

护网行动:ADSelfService Plus引领企业网络安全新纪元

随着信息技术的飞速发展&#xff0c;企业网络的重要性变得愈发显著。然而&#xff0c;随之而来的网络安全威胁也日益增多&#xff0c;网络黑客和恶意软件不断涌现&#xff0c;给企业的数据和机密信息带来巨大风险。在这个信息安全威胁层出不穷的时代&#xff0c;企业急需一款强…

微服务学习笔记-----Nacos安装教程(Windows和Linux版本)

Nacos安装教程 Nacos安装指南1.Windows安装1.1.下载安装包1.2.解压1.3.端口配置1.4.启动1.5.访问 2.Linux安装2.1.安装JDK2.2.上传安装包2.3.解压2.4.端口配置2.5.启动 3.Nacos的依赖 Nacos安装指南 1.Windows安装 开发阶段采用单机安装即可。 1.1.下载安装包 在Nacos的Git…

EAP设备自动化控制系统在设备数采和控制方面的优势

随着科技的不断进步和工业自动化的发展&#xff0c;EAP&#xff08;Equipment Automation Program&#xff09;设备自动化控制系统在各个行业中扮演着越来越重要的角色。作为连接MES&#xff08;Manufacturing Execution System&#xff09;和设备层的沟通桥梁&#xff0c;EAP系…

git stash 内容丢失找回【亲测好用】

直接将下列代码复制到 终端 会出现所有列表 也包括你删除/丢失的stash git log --graph --oneline --decorate $( git fsck --no-reflog | awk /dangling commit/ {print $3} ) 前面的黄色就是他的编号 例如我想回复 自己编辑修改项目 将编号复制重链即可 git stash apply …

Docker Compose 实现单机容器集群编排管理

目录 Docker ComposeDocker Compose 三大概念1. Docker Compose 环境安装2. YAML 文件格式及编写注意事项3. Docker Compose配置restart 设置重启策略&#xff0c;no&#xff0c;always&#xff0c;no-failure&#xff0c;unless-stopped 4. Docker Compose 常用命令选项5. Doc…

Llama 2 来袭 - 在 Hugging Face 上玩转它

&#x1f917; 宝子们可以戳 阅读原文 查看文中所有的外部链接哟&#xff01; 引言 今天&#xff0c;Meta 发布了 Llama 2&#xff0c;其包含了一系列最先进的开放大语言模型&#xff0c;我们很高兴能够将其全面集成入 Hugging Face&#xff0c;并全力支持其发布。Llama 2 的社…

香港二手电子产品分销商【创智环球】申请纳斯达克IPO上市

来源&#xff1a;猛兽财经 猛兽财经获悉&#xff0c;总部位于香港的二手电子产品分销商【创智环球】&#xff08;Creative Global Technology Holdings Limited&#xff09;近期已向美国证券交易委员会&#xff08;SEC&#xff09;提交招股书&#xff0c;申请在纳斯达克IPO上市…

Redis学习2--使用java操作Redis

1、java操作Redis库的比较 Redis有各种语言的客户端可以来操作redis数据库&#xff0c;其中java语言主要有Jedis与lettuce &#xff0c;Spring Data Redis封装了上边两个客户端&#xff0c;优缺点如下&#xff1a; 2、使用Jedis操作Redis Jedis使用的基本步骤&#xff1a; 引…

HANA学习笔记

1、安装 准备安装介质&#xff0c;我这儿用的是HANA2.00.059.00&#xff0c;注意会用到三个lib包和saptune&#xff0c;提前准备好。 执行./hdblcm开启数据库安装&#xff0c;过程中会涉及到需要用户设置一些参数&#xff0c;按照自己需求设置即可。 安装完成会生成一个安装日…

HCIA 第二课总结

配置网络设备的明文密钥实验组网 实验拓扑 将一个路由器使用配置口进行连接 sys #进入系统视图模式 sysname RTA #给设备命名 user-interface console 0 #进入用户接口配置界面 authentication-mode password #配置认证模式为密钥认证 set authentication password ciphe…