【C项目】无头单向不循环链表

简介:本系列博客为C项目系列内容,通过代码来具体实现某个经典简单项目
适宜人群:已大体了解C语法同学
作者留言:本博客相关内容如需转载请注明出处,本人学疏才浅,难免存在些许错误,望留言指正
作者博客链接:睡觉待开机

下面是本项目的大体思路梳理:
在这里插入图片描述

全部接口一览:

在这里插入图片描述

void SLTPrint(SLTNode* phead);//打印
void SLTPushBack(SLTNode** pphead,SLTDateType x);//尾插
void SLTPushiFront(SLTNode** pphead, SLTDateType x);//头插
void SLTPopBack(SLTNode** pphead);//尾删
void SLTPopFront(SLTNode** pphead);//头删
void SLTInsert(SLTNode** pphead,SLTNode* pos,SLTDateType x);//任意位置之前插入
SLTNode* SLTFind(SLTNode** pphead, SLTDateType x);//查找接口
void SLTInsertAfter(SLTNode* pos, SLTDateType x);//任意位置之后插入
void SLTErase(SLTNode** pphead, SLTNode* pos);//删除pos指向的节点
void SLTEraseAfter(SLTNode* pos);//删除pos指向之后的节点
void SLTDestroy(SLTNode** pphead);//销毁链表接口

1.创建链表的结构体

在这里插入图片描述
在这里插入图片描述

//定义单链表结构体
#define SLTDateType int
typedef struct SListNode
{SLTDateType date;//每个节点的数据struct SListNode* next;//每个节点存储下一个节点的地址
}SLTNode;

2.打印链表的接口实现

首先制造一些节点并进行相连操作
在这里插入图片描述
打印函数实现的思路:
在这里插入图片描述
在这里插入图片描述

void SLTPrint(SLTNode* phead)
{//定义一个新的指针SLTNode* pcur = phead;//循环打印即可,什么时候停止?pcur不指向空便不停止while (pcur){//打印数据printf("%d->", pcur->date);//更新指针pcur = pcur->next;}//为了完善,我给最后也加一个NULLprintf("NULL\n");
}

3.尾插接口实现

思路:定义一个新指针,找到原链表的尾节点,找到了接上即可。
在这里插入图片描述
这里为什么要分类进行讨论?这由思路决定的,因为如果是空链表的情况下,ptail->next根本就是错误的,因为不存在。
在这里插入图片描述
在这里插入图片描述
新空间开辟接口:
在这里插入图片描述

void SLTPushBack(SLTNode** pphead, SLTDateType x)
{assert(pphead);//申请一块新的空间SLTNode* newnode = SLTBuyNode(x);//分两种情况//链表为空if (*pphead == NULL){*pphead = newnode;}else//链表不为空{SLTNode* ptail = *pphead;//用于找到链表的尾节点while (ptail->next){ptail = ptail->next;}//找到尾节点ptail->next = newnode;//给他接上}
}
SLTNode* SLTBuyNode(SLTDateType x)
{//申请一块新的空间SLTNode* newnode = (SLTNode*)malloc(sizeof(SLTNode));//放内容newnode->date = x;newnode->next = NULL;//返回地址return newnode;
}

4.头插接口实现

思路:
在这里插入图片描述
在这里插入图片描述
尾插需要分情况讨论而头插怎么不需要呢?还是思路决定的,这个思路没有用到ptail->next所以就不需要考虑空链表的情况

void SLTPushiFront(SLTNode** pphead, SLTDateType x)
{assert(pphead);//申请一块新的空间SLTNode* newnode = SLTBuyNode(x);//把原来第一个结点的地址交给新节点的nextnewnode->next = *pphead;*pphead = newnode;//把头部指针更新一下
}

5.尾删接口实现

思路:
在这里插入图片描述
在这里插入图片描述
这里为什么要分只有一个节点和多个节点的不同情况?因为涉及到prev问题如果是只有一个节点,ptail指向第一个节点,那prev指针指向哪里?所以要对只有一个节点的链表单独进行处理。

void SLTPopBack(SLTNode** pphead)
{//检验assert(pphead);//原本的指针不能是空assert(*pphead);//传过来的不能是空指针给我删除啊//删除//这里分两种情况//1.只有一个节点的情况if (*pphead == NULL){free(*pphead);*pphead = NULL;return;}else//多个节点的情况{//需要找到最后一个节点和倒数第二个节点//最后一个节点是为了释放空间//倒数第二个节点是为了把他的next部分置为空SLTNode* ptail = *pphead;SLTNode* prev = *pphead;while (ptail->next){prev = ptail;ptail = ptail->next;}//第二个节点next置为空prev->next = NULL;//销毁第一个节点free(ptail);ptail = NULL;}
}

6.头删接口的实现

思路:
在这里插入图片描述
在这里插入图片描述

void SLTPopFront(SLTNode** pphead)
{//检验assert(pphead);//检验你别给我传个空assert(*pphead);//检验链表不为空,空链表删除什么?//开始准备删除SLTNode* next = (*pphead)->next;//记录一下要接上的地址free(*pphead);//释放第一个节点*pphead = next;
}

7.查找接口实现

查找接口是做什么的呢?找一个节点的地址的。
思路实现:
在这里插入图片描述
在这里插入图片描述

SLTNode* SLTFind(SLTNode** pphead, SLTDateType x)
{//检查assert(pphead);//别传空指针进来//这里可以传空链表吗?可以!顶多找不到给你返回一个NULL嘛//遍历链表SLTNode* pcur = *pphead;while (pcur)//当pcur找到NULL时候就会停止{if (pcur->date == x){return pcur;//满足条件,返回该节点的地址}pcur = pcur->next;//更新指针}//如果什么都没有找到的话,是不是会不太合适\// 所以我们规定如果没有找到,返回NULL地址return NULL;
}

8.在指定位置之前插入数据

在这里插入图片描述
在这里插入图片描述

void SLTInsert(SLTNode** pphead, SLTNode* pos, SLTDateType x)
{//检验assert(pphead);//传入地址不得为空assert(pos);//pos不得为空assert(*pphead);//要加上链表不得为空,\这是因为pos是链表的一个节点的地址,如 \果链表不存在,那么pos也会不存在//这里要分情况进行处理//1.pos刚好是头节点if (pos == *pphead){//直接调用头插SLTPushiFront(pphead,x);return;}else//2.如果pos不是头节点{SLTNode* prev = *pphead;//让prev找到pos之前的节点的地址while (prev->next != pos){prev = prev->next;}SLTNode* newnode = SLTBuyNode(x);//申请空间prev->next = newnode;//把新空间链接到我们前一个节点newnode->next = pos;//把新空间与pos指向的空间链接在一起}
}

9.在指定位置之后插入数据的接口实现

思路:
在这里插入图片描述
在这里插入图片描述
思考:上面说的关联新节点的错误是如何引起的呢?
答:因为新节点的后面的节点的地址表示是靠的pos->next

void SLTInsertAfter(SLTNode* pos, SLTDateType x)//之后
{//检查assert(pos);//申请空间SLTNode* newnode = SLTBuyNode(x);//关联新节点的错误写法,原因:pos值的改变//pos->next = newnode;//newnode->next = pos->next;//关联新节点的正确写法://先接后面,再接前面newnode->next = pos->next;pos->next = newnode;}

10.删除指定位置的节点

思路:
在这里插入图片描述

在这里插入图片描述

void SLTErase(SLTNode** pphead, SLTNode* pos)
{//检查assert(pphead);//不得传空assert(*pphead);//不得为空链表assert(pos);//pos刚好是头节点的情况,头删if (*pphead == pos){//头删SLTPopFront(pphead);return;}//如果不是头节点else {//找到pos之前的节点SLTNode* prev = *pphead;while (prev->next != pos){prev = prev->next;}prev->next = pos->next;free(pos);pos = NULL;}}

11.删除指定位置之后的节点接口实现

思路:
在这里插入图片描述
在这里插入图片描述

void SLTEraseAfter(SLTNode* pos)
{//检查assert(pos);//传过来的地址不可以为空assert(pos->next);//传过来的地址的下一个地址不得为空SLTNode* del = pos->next;//记录要删除的节点的地址pos->next = pos->next->next;//更新pos中next的地址free(del);//释放空间del = NULL;//临时指针及时置为空
}

12.销毁链表接口

思路:
在这里插入图片描述
在这里插入图片描述

void SLTDestroy(SLTNode** pphead)
{assert(pphead);//传过来的指针不得为空assert(*pphead);//链表不得为空,空链表不用销毁//创建遍历指针SLTNode* pcur = *pphead;//循环销毁while (pcur)//啥时候停止?pcur指向NULL{SLTNode* next = pcur->next;free(pcur);pcur = next;}//最后把头指针也置为NULL*pphead = NULL;
}

全部代码合集

//SList.h
#pragma once
#include<stdlib.h>
#include<stdio.h>
#include<assert.h>//定义单链表结构体
#define SLTDateType int
typedef struct SListNode
{SLTDateType date;//每个节点的数据struct SListNode* next;//每个节点存储下一个节点的地址
}SLTNode;void SLTPrint(SLTNode* phead);//打印
void SLTPushBack(SLTNode** pphead,SLTDateType x);//尾插
void SLTPushiFront(SLTNode** pphead, SLTDateType x);//头插
void SLTPopBack(SLTNode** pphead);//尾删
void SLTPopFront(SLTNode** pphead);//头删
void SLTInsert(SLTNode** pphead,SLTNode* pos,SLTDateType x);//任意位置之前插入
SLTNode* SLTFind(SLTNode** pphead, SLTDateType x);//查找接口
void SLTInsertAfter(SLTNode* pos, SLTDateType x);//任意位置之后插入
void SLTErase(SLTNode** pphead, SLTNode* pos);//删除pos指向的节点
void SLTEraseAfter(SLTNode* pos);//删除pos指向之后的节点
void SLTDestroy(SLTNode** pphead);//销毁链表接口
//SList.c
#include"SList.h"SLTNode* SLTBuyNode(SLTDateType x)
{//申请一块新的空间SLTNode* newnode = (SLTNode*)malloc(sizeof(SLTNode));//放内容newnode->date = x;newnode->next = NULL;//返回地址return newnode;
}SLTNode* SLTFind(SLTNode** pphead, SLTDateType x)
{//检查assert(pphead);//别传空指针进来//这里可以传空链表吗?可以!顶多找不到给你返回一个NULL嘛//遍历链表SLTNode* pcur = *pphead;while (pcur)//当pcur找到NULL时候就会停止{if (pcur->date == x){return pcur;//满足条件,返回该节点的地址}pcur = pcur->next;//更新指针}//如果什么都没有找到的话,是不是会不太合适\// 所以我们规定如果没有找到,返回NULL地址return NULL;
}void SLTPrint(SLTNode* phead)
{//定义一个新的指针SLTNode* pcur = phead;//循环打印即可,什么时候停止?pcur不指向空便不停止while (pcur){//打印数据printf("%d->", pcur->date);//更新指针pcur = pcur->next;}//为了完善,我给最后也加一个NULLprintf("NULL\n");
}void SLTPushBack(SLTNode** pphead, SLTDateType x)
{assert(pphead);//申请一块新的空间SLTNode* newnode = SLTBuyNode(x);//分两种情况//链表为空if (*pphead == NULL){*pphead = newnode;}else//链表不为空{SLTNode* ptail = *pphead;//用于找到链表的尾节点while (ptail->next){ptail = ptail->next;}//找到尾节点ptail->next = newnode;//给他接上}
}void SLTPushiFront(SLTNode** pphead, SLTDateType x)
{assert(pphead);//申请一块新的空间SLTNode* newnode = SLTBuyNode(x);//把原来第一个结点的地址交给新节点的nextnewnode->next = *pphead;*pphead = newnode;//把头部指针更新一下
}void SLTPopBack(SLTNode** pphead)
{//检验assert(pphead);//原本的指针不能是空assert(*pphead);//传过来的不能是空指针给我删除啊//删除//这里分两种情况//1.只有一个节点的情况if (*pphead == NULL){free(*pphead);*pphead = NULL;return;}else//多个节点的情况{//需要找到最后一个节点和倒数第二个节点//最后一个节点是为了释放空间//倒数第二个节点是为了把他的next部分置为空SLTNode* ptail = *pphead;SLTNode* prev = *pphead;while (ptail->next){prev = ptail;ptail = ptail->next;}//第二个节点next置为空prev->next = NULL;//销毁第一个节点free(ptail);ptail = NULL;}
}void SLTPopFront(SLTNode** pphead)
{//检验assert(pphead);//检验你别给我传个空assert(*pphead);//检验链表不为空,空链表删除什么?//开始准备删除SLTNode* next = (*pphead)->next;//记录一下要接上的地址free(*pphead);//释放第一个节点*pphead = next;
}void SLTInsert(SLTNode** pphead, SLTNode* pos, SLTDateType x)
{//检验assert(pphead);//传入地址不得为空assert(pos);//pos不得为空assert(*pphead);//要加上链表不得为空,//这是因为pos是链表的一个节点的地址,如 //果链表不存在,那么pos也会不存在//这里要分情况进行处理//1.pos刚好是头节点if (pos == *pphead){//直接调用头插SLTPushiFront(pphead,x);return;}else//2.如果pos不是头节点{SLTNode* prev = *pphead;//让prev找到pos之前的节点的地址while (prev->next != pos){prev = prev->next;}SLTNode* newnode = SLTBuyNode(x);//申请空间prev->next = newnode;//把新空间链接到我们前一个节点newnode->next = pos;//把新空间与pos指向的空间链接在一起}
}void SLTInsertAfter(SLTNode* pos, SLTDateType x)//之后
{//检查assert(pos);//申请空间SLTNode* newnode = SLTBuyNode(x);//关联新节点的错误写法,原因:pos值的改变//pos->next = newnode;//newnode->next = pos->next;//关联新节点的正确写法://先接后面,再接前面newnode->next = pos->next;pos->next = newnode;}void SLTErase(SLTNode** pphead, SLTNode* pos)
{//检查assert(pphead);//不得传空assert(*pphead);//不得为空链表assert(pos);//pos刚好是头节点的情况,头删if (*pphead == pos){//头删SLTPopFront(pphead);return;}//如果不是头节点else {//找到pos之前的节点SLTNode* prev = *pphead;while (prev->next != pos){prev = prev->next;}prev->next = pos->next;free(pos);pos = NULL;}}void SLTEraseAfter(SLTNode* pos)
{//检查assert(pos);//传过来的地址不可以为空assert(pos->next);//传过来的地址的下一个地址不得为空SLTNode* del = pos->next;//记录要删除的节点的地址pos->next = pos->next->next;//更新pos中next的地址free(del);//释放空间del = NULL;//临时指针及时置为空
}void SLTDestroy(SLTNode** pphead)
{assert(pphead);//传过来的指针不得为空assert(*pphead);//链表不得为空,空链表不用销毁//创建遍历指针SLTNode* pcur = *pphead;//循环销毁while (pcur)//啥时候停止?pcur指向NULL{SLTNode* next = pcur->next;free(pcur);pcur = next;}//最后把头指针也置为NULL*pphead = NULL;
}
//test.c
#define _CRT_SECURE_NO_WARNINGS 1
#include"SList.h"void test1()
{//头指针SLTNode* phead = NULL;//造一点结点SLTNode* node1 = (SLTNode*)malloc(sizeof(SLTNode));node1->date = 1;SLTNode* node2 = (SLTNode*)malloc(sizeof(SLTNode));node2->date = 2;SLTNode* node3 = (SLTNode*)malloc(sizeof(SLTNode));node3->date = 3;SLTNode* node4 = (SLTNode*)malloc(sizeof(SLTNode));node4->date = 4;SLTNode* node5 = (SLTNode*)malloc(sizeof(SLTNode));node5->date = 5;//链接这些节点phead = node1;node1->next = node2;node2->next = node3;node3->next = node4;node4->next = node5;node5->next = NULL;//调用一下打印函数SLTPrint(phead);
}void test2()
{SLTNode* phead = NULL;SLTPushBack(&phead,6);SLTPrint(phead);SLTPushiFront(&phead,0);SLTPushiFront(&phead,1);SLTPushiFront(&phead,2);SLTPushiFront(&phead,3);SLTPushiFront(&phead,4);SLTPushiFront(&phead,5);SLTPrint(phead);//5->4->3->2->1->0->6->NULLSLTPopBack(&phead);SLTPrint(phead);//5->4->3->2->1->0->NULLSLTPopFront(&phead);SLTPopFront(&phead);SLTPopFront(&phead);SLTPopFront(&phead);SLTPrint(phead);//1->0->NULLSLTNode* find = SLTFind(&phead,1);SLTInsert(&phead, find, 2);SLTPrint(phead);//2->1->0->NULLSLTInsertAfter(find, 8);SLTPrint(phead);//2->1->8->0->NULLSLTEraseAfter(find);SLTPrint(phead);//2->8->0->NULLSLTDestroy(&phead);SLTPrint(phead);//NULL}int main()
{//测试我的打印函数//test1();//测试我的插入与删除函数test2();return 0;
}

完。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Rabbitmq入门与应用(五)-延迟队列的设计与实现

延迟队列设计 在开发过程中涉及到延迟队列的应用&#xff0c;例如订单生成后有30分钟的付款时间&#xff0c;注册是有60秒的邮件或者短信的发送读取时间等。 常规使用rabbitmq设计延迟队列有两种方式 使用创建一个延迟队列阻塞消息使用延迟队列插件 Dead Letter Exchanges —…

Linux——信号(2)

在上一张博客我们介绍了Linux中信号的概念和信号是如何产生的&#xff0c;虽然信号 有多种产生方式&#xff0c;但是最终只能由操作系统给对应进程发送特定信号。现在 我将更加规范的介绍Linux中的信号。上一章的遗留问题 我们上一章中在观察信号的默认处理的时候发现终止信号…

canal监听binlog记录业务数据的变更;canalAdmin对instance做web配置

概述 平时在开发中会通过logback打印一些开发日志&#xff0c;有时也会需要记录一些业务日志&#xff0c;简单的就直接用log记录一下&#xff0c;但是系统中需要记录日志的地方越来越多时&#xff0c;不能每个地方都写一套log记录&#xff1b; 由于平常用的大多都是mysql&…

【论文阅读笔记】Contrastive Learning with Stronger Augmentations

Contrastive Learning with Stronger Augmentations 摘要 基于提供的摘要&#xff0c;该论文的核心焦点是在对比学习领域提出的一个新框架——利用强数据增强的对比学习&#xff08;Contrastive Learning with Stronger Augmentations&#xff0c;简称CLSA&#xff09;。以下…

【Jvm】性能调优(上)线上问题排查工具汇总

文章目录 一.互联网概念1.产品闭环和业务闭环2.软件设计中的上游和下游3.JDK运行时常量池 二.CPU相关概念1.查询CPU信息2.CPU利用率&#xff08;CPU utilization&#xff09;和 CPU负载&#xff08;CPU load&#xff09;2.1.如何理解CPU负载2.2.top命令查看CPU负载均值2.3.CPU负…

Pytorch 配置 GPU 环境

1、Pytorch 深度学习跑代码的时候&#xff0c;因为简单的操作不适合cpu运行&#xff0c;我们更习惯用GPU加速代码。 本章将介绍怎么安装pytorch的gpu环境&#xff0c;以及常见的问题 关于conda的安装&#xff0c;参考之前文章&#xff1a;深度学习环境配置&#xff1a;Anaco…

初始树莓派 + VMware17 安装树莓派(Raspberry Pi 4B/5)

文章目录 树莓派入门 VMware17 安装树莓派(Raspberry Pi 4/5B)前言一、树莓派入门指南&#xff1a;从零开始探索树莓派树莓派4B和5对比 二、在VMware Workstation 17上安装树莓派4B/5操作系统&#xff1a;实现强大性能与便捷模拟工具准备开始安装树莓派1.创建一个虚拟机2. 选择…

PyCharm 取消所有断点

PyCharm 取消所有断点 1. Run -> View Breakpoints...2. Python Line Breakpoint3. Remove - DoneReferences 1. Run -> View Breakpoints… 2. Python Line Breakpoint ​​​ 3. Remove - Done References [1] Yongqiang Cheng, https://yongqiang.blog.csdn.net/

【web安全】渗透测试实战思路

步骤一&#xff1a;选目标 1. 不建议太小的公司&#xff08;可能都是请别人来开发的&#xff0c;用现成成熟的框架&#xff09; 2. 不建议一线大厂&#xff1a;腾讯&#xff0c;字节&#xff0c;阿里等&#xff0c;你懂的 3. 不建议政府部门&#xff0c;安全设备多&#xff…

Spring MVC(基于 Spring4.x)基础学习

一、SpringMVC概述 二、SpringMVC的HelloWorld 三、使用RequestMapping映射请求 四、映射请求参数&请求头 五、处理模型数据 六、视图和视图解析器 七、RESTful CRUD 八、SpringMVC表单标签&处理静态资源 九、数据转换&数据格式化&数据校验 十、处理JSON:使用…

前端win10如何设置固定ip(简单明了)

1、右击这个 2、点击属性 3、双击协议版本4设置成以下就ok

原生微信小程序开发记录

1. 拿到项目 先构建 2.小程序与普通网页开发的区别 网页开发渲染线程和脚本线程是互斥的&#xff0c;这也是为什么长时间的脚本运行可能会导致页面失去响应&#xff0c;而在小程序中&#xff0c;二者是分开的&#xff0c;分别运行在不同的线程中。网页开发者可以使用到各种浏览…

【HarmonyOS】鸿蒙开发之Slider组件——第3.5章

组件应用场景: 设备音量大小&#xff0c;调节屏幕亮度等需求 slider组件内options属性简介 value&#xff1a;滑动条当前进度值。 min&#xff1a;设置滑动条设置最小值。 max&#xff1a;设置滑动条设置最大值&#xff0c;默认为 100 。 step&#xff1a;设置滑动条滑动跳动…

Python从进阶到高级—通俗易懂版

Python从进阶到高级—通俗易懂版 # # Author : Mikigo # Time : 2021/12/23 # 一、简介 Python 进阶是我一直很想写的&#xff0c;作为自己学习的记录&#xff0c;过去自己在看一些代码的时候经常会困惑&#xff0c;看不懂&#xff0c;然后自己去查资料、看书籍&#xff0…

JAVA之HashMap详解

HashMap 1. 设计原理 HashMap 基于哈希表的 Map 接口实现&#xff0c;是以 key-value 存储形式存在&#xff0c;即主要用来存放键值对。HashMap 的实现不是同步的&#xff0c;这意味着它不是线程安全的。它的 key、value 都可以为 null&#xff0c;此外&#xff0c;HashMap 中…

appium实现自动化测试原理

目录 1、Appium原理 1.1、Android Appium原理图文解析 1.1.2、原理详解 1.1.2.1、脚本端 1.1.2.2、appium-server 1.1.2.3、中间件bootstrap.jar 1.1.2.4、驱动引擎uiautomator 1.2、 IOS Appium原理 1、Appium原理 1.1、Android Appium原理图文解析 执行测试脚本全过…

C#,二进制数的按位交换(Bits swap)的算法与源代码

数字在指定位置指定位数的交换是常见算法。 1 源程序 using System; using System.Text; using System.Collections; using System.Collections.Generic; namespace Legalsoft.Truffer.Algorithm { public static partial class Algorithm_Gallery { /// <…

专业140+总分420+南京信息工程大学811信号与系统考研经验南信大电子信息与通信工程,真题,大纲,参考书

今年顺利被南信大电子信息录取&#xff0c;初试420&#xff0c;专业811信号与系统140&#xff08;Jenny老师辅导班上140很多&#xff0c;真是大佬云集&#xff09;&#xff0c;今年应该是南信大电子信息最卷的一年&#xff0c;复试线比往年提高了很多&#xff0c;录取平均分380…

扭蛋机小程序开发:发展优势

商场中精美的扭蛋机一直都是年轻人的心头好&#xff0c;目前&#xff0c;扭蛋机商品也不在局限于各种小型玩具&#xff0c;也逐渐与各类热门IP合作&#xff0c;打造出了各类手办、周边等&#xff0c;深受各个年龄层的喜爱。 如今&#xff0c;扭蛋机在互联网的推动下&#xff0…

算法的基本概念

设么是算法&#xff1f; 什么是好的算法/ 什么是算法&#xff1a; 量水的问题&#xff1a; 方案如下&#xff1a;&#xff08;核心思路就是两个桶差值为2&#xff0c;两次差值为4&#xff0c;7-(5-4) 6&#xff09; 算法&#xff1a;准确描述的 “操作步骤 (问题求解步骤)”&…