顺序表的实现
目录
一. 数据结构相关概念
二、线性表
三、顺序表概念及结构
3.1顺序表一般可以分为:
3.2 接口实现:
四、基本操作实现
4.1顺序表初始化
4.2检查空间,如果满了,进行增容编辑
4.3顺序表打印
4.4顺序表销毁
4.5顺序表尾插
4.6顺序表头插
4.7顺序表头删
4.8顺序表尾删
4.9顺序表在pos位置插入x
4.10顺序表删除pos位置的值
链表相关知识:
链表基础知识(二、双向链表头插、尾插、头删、尾删、查找、删除、插入)-CSDN博客
链表基础知识(一、单链表、头插、尾插、头删、尾删、查找、删除、插入)-CSDN博客
一. 数据结构相关概念
什么是数据结构?
数据结构是由“数据”和“结构”两词组合而来。
什么是数据?常见的数值1、2、3、4.....、教务系统里保存的用户信息(姓名、性别、年龄、学历等等)、网页里肉眼可以看到的信息(文字、图片、视频等等),这些都是数据什么是结构?
当我们想要使用大量使用同一类型的数据时,通过手动定义大量的独立的变量对于程序来说,可读性非常差,我们可以借助数组这样的数据结构将大量的数据组织在一起,结构也可以理解为组织数据的方式。
概念:数据结构是计算机存储、组织数据的方式。数据结构是指相互之间存在一种或多种特定关系
的数据元素的集合。数据结构反映数据的内部构成,即数据由那部分构成,以什么方式构成,以及数据元素之间呈现的结构。
总结:
1)能够存储数据(如顺序表、链表等结构)
2)存储的数据能够方便查找
2、为什么需要数据结构?
通过数据结构,能够有效将数据组织和管理在一起。按照我们的方式任意对数据进行增删改查等操
作。最基础的数据结构:数组。
【思考】有了数组,为什么还要学习其他的数据结构?
假定数组有10个空间,已经使用了5个,向数组中插入数据步骤:
求数组的长度,求数组的有效数据个数,向下标为数据有效个数的位置插入数据(注意:这里是
否要判断数组是否满了,满了还能继续插入吗).....
假设数据量非常庞大,频繁的获取数组有效数据个数会影响程序执行效率。
结论:最基础的数据结构能够提供的操作已经不能完全满足复杂算法实现。
二、线性表
线性表(linear list)是n个具有相同特性的数据元素的有限序列。 线性表是一种在实际中广泛使
用的数据结构,常见的线性表:顺序表、链表、栈、队列、字符串...
线性表在逻辑上是线性结构,也就说是连续的一条直线。但是在物理结构上并不一定是连续的,
线性表在物理上存储时,通常以数组和链式结构的形式存储。
三、顺序表概念及结构
顺序表是用一段物理地址连续的存储单元依次存储数据元素的线性结构,一般情况下采用数组存
储。在数组上完成数据的增删查改。
-
顺序表和数组的区别
-
顺序表的底层结构是数组,对数组的封装,实现了常用的增删改查等接口
3.1顺序表一般可以分为:
-
静态顺序表:使用定长数组存储。
// 顺序表的静态存储
#define N 100
typedef int SLDataType;
typedef struct SeqList
{SLDataType array[N]; // 定长数组size_t size; // 有效数据的个数
}SeqList;
-
动态顺序表:使用动态开辟的数组存储。
// 顺序表的动态存储
typedef struct SeqList
2.2 接口实现:
静态顺序表只适用于确定知道需要存多少数据的场景。静态顺序表的定长数组导致N定大
了,空间开多了浪费,开少了不够用。所以现实中基本都是使用动态顺序表,根据需要动态
的分配空间大小,所以下面我们实现动态顺序表。
{SLDataType* array; // 指向动态开辟的数组size_t size ; // 有效数据个数size_t capicity ; // 容量空间的大小
}SeqList;
3.2 接口实现:
静态顺序表只适用于确定知道需要存多少数据的场景。静态顺序表的定长数组导致N定大
了,空间开多了浪费,开少了不够用。所以现实中基本都是使用动态顺序表,根据需要动态
的分配空间大小,所以下面我们实现动态顺序表。
先解释一下预处理指令
-
#pragma once:这是一个非标准的预处理指令,它告诉预处理器这个头文件只应该被包含一次。如果尝试多次包含,预处理器会忽略后续的包含。尽管它是非标准的,但许多现代编译器(如GCC和Clang)都支持它。
-
#ifndef SEQLIST_H:这是一个条件编译指令。它检查是否定义了一个名为SEQLIST_H的宏。如果没有定义(即这个头文件还没有被包含过),那么接下来的代码会被编译。
-
#define SEQLIST_H:这定义了一个名为SEQLIST_H的宏。当这个头文件首次被包含时,这个宏会被定义,从而标记这个头文件已经被包含过了。
-
#endif:这结束了之前的#ifndef条件编译块。
SeqList.h
//#pragma once
#ifndef _SEQLIST_H_
#define _SEQLIST_H_#include<stdio.h>
#include<string.h>
#include<stdlib.h>#include<assert.h>//增强程序的可维护性
#define MAX_SIZE 10
typedef int SQDataType;
//静态顺序表
//问题:给少了不够用,给多了用不完浪费,不能灵活控制//typedef struct SeqList
//{
// SQDataType a[MAX_SIZE];
// int size;
//}SL;typedef struct SeqList
{SQDataType *a;// 指向动态开辟的数组int size; //有效的数据的个数int capacity;//容量
}SL;//typedef struct SeqList SL;//定义为简写// 基本增删查改接口
// 顺序表初始化//增删查改等接口函数
//void SeqListInit(struct SeqList s);//顺序表初始化
void SeqListInint(SL* ps);
// 检查空间,如果满了,进行增容
void CheckCapacity(SeqList * psl);
//顺序表打印
void SeqListPrint(SL* ps);
// 顺序表销毁
void SeqListDestory(SL* ps);
//顺序表尾插
void SeqListPushBack(SL* ps, SQDataType x);
//顺序表头插
void SeqListPushFront(SL* ps, SQDataType x);
//顺序表头删
void SeqListPopBack(SL* ps);
//顺序表尾删
void SeqListPopFront(SL* ps);// 顺序表在pos位置插入x
void SeqListInsert(SL* ps, int pos, SQDataType x);// 顺序表删除pos位置的值
void SeqListErase(SL* ps, int pos);#endif
四、基本操作实现
4.1顺序表初始化
void SeqListInit(SL* ps)
{ps->a = NULL;ps->size = 0;ps->capacity = 0;
}
4.2检查空间,如果满了,进行增容
这个函数的主要目的是在顺序列表满时自动扩容,以便能够继续添加元素。它首先检查列表是否已满,然后计算新的容量,并使用realloc函数尝试调整数组的大小。如果realloc失败(返回NULL),则打印错误信息并退出程序。如果成功,就更新列表的数组指针和容量。
// 函数定义,传入一个指向顺序列表(SeqList)的指针
void SeqListCheckCapacity(SL* ps)
{ // 检查顺序列表是否已满,即当前大小(size)是否等于容量(capacity) if (ps->size == ps->capacity) { // 如果满了,计算新的容量。如果当前容量为0,则新容量为4;否则,新容量为当前容量的2倍 int newcapacity = ps->capacity == 0 ? 4 : ps->capacity * 2; // 使用realloc函数尝试调整顺序列表的数组大小 // realloc可能会改变原有内存块的位置,因此需要使用一个临时指针来接收结果 SQDataType* tmp = (SQDataType*)realloc(ps->a, newcapacity * sizeof(SQDataType)); // 检查realloc是否成功 if (tmp == NULL) { // 如果失败,打印错误信息并退出程序 printf("realloc fail\n"); exit(-1); } else { // 如果成功,更新顺序列表的数组指针和容量 ps->a = tmp; ps->capacity = newcapacity; } }
}
4.3顺序表打印
这个函数的主要目的是遍历顺序列表,并打印出其中的每一个元素。通过循环,它会依次访问列表中的每个元素,并将其打印。
// 打印顺序列表中的所有元素
void SeqListPrint(SL* ps)
{ // 通过循环遍历顺序列表中的每一个元素 for (int i = 0; i < ps->size; i++) { printf("%d ", ps->a[i]); } // 打印一个换行符,使得每次打印列表后都会换行,输出更清晰 printf("\n");
}
4.4顺序表销毁
SeqListDestroy函数主要目的是释放顺序列表所占用的内存空间
// 销毁顺序列表的函数
void SeqListDestroy(SL* ps)
{ // 断言:确保传入的顺序列表指针ps不为空 assert(ps); // 判断顺序列表的数组指针a是否不为空 if (ps->a != NULL) { // 释放数组指针a所指向的内存空间 free(ps->a); // 将数组指针a设置为NULL,避免野指针 ps->a = NULL; // 将顺序列表的大小设置为0,表示列表已空 ps->size = 0; // 将顺序列表的容量设置为0,表示已没有分配内存空间 ps->capacity = 0; }
}
4.5顺序表尾插
在插入新元素之前,它们都首先检查当前的容量是否足够,如果不够则调用 SeqListCheckCapacity 函数进行扩容。尾插函数SeqListPushBack直接在末尾添加新元素
// 尾插法:在顺序列表的末尾插入一个新元素
void SeqListPushBack(SL* ps, SQDataType x)
{ // 检查当前顺序列表的容量是否足够,如果不够则进行扩容 SeqListCheckCapacity(ps); // 在顺序列表的当前末尾位置插入新元素 ps->a[ps->size] = x; // 更新顺序列表的大小(元素数量) ps->size++;
}
4.6顺序表头插
在插入新元素之前,它们都首先检查当前的容量是否足够,如果不够则调用 SeqListCheckCapacity
函数进行扩容。头插函数SeqListPushFront将现有元素向后移动以腾出空间。
// 头插法:在顺序列表的开头插入一个新元素
void SeqListPushFront(SL* ps, SQDataType x)
{ // 检查当前顺序列表的容量是否足够,如果不够则进行扩容 SeqListCheckCapacity(ps); // 初始化:设定一个变量来追踪当前需要移动的元素的位置 // 结束条件:当所有元素都已移动到它们的新位置时停止 // 迭代过程:从列表的末尾开始,将每个元素向后移动一个位置以腾出空间 int end = ps->size - 1; // 从列表的最后一个元素开始 while (end >= 0) // 当还有元素需要移动时继续循环 { // 将当前位置的元素向后移动一个位置 ps->a[end + 1] = ps->a[end]; --end; // 移动到前一个元素 } // 在顺序列表的开头(现在为空)插入新元素 ps->a[0] = x; // 更新顺序列表的大小(元素数量) ps->size++;
}
4.7顺序表头删
SeqListPopFront`函数用于删除顺序列表的第一个元素。它首先通过断言确保列表不为空,然后通过一个循环将第一个位置之后的所有元素都向前移动一个位置,从而覆盖掉第一个位置的元素,并更新列表的大小。
// 头删:删除顺序列表的第一个元素
void SeqListPopFront(SL* ps)
{ // 断言,确保顺序列表不为空,即其大小大于0 // 如果ps->size <= 0,则触发断言错误,终止程序 assert(ps->size > 0); // 初始化一个变量start,用于从第二个元素开始遍历 int start = 1; // 当start小于列表大小时,执行循环 // 这个循环用于将第一个位置之后的元素都向前移动一个位置,从而覆盖掉第一个位置的元素 while (start < ps->size) { // 将下一个位置的元素移动到当前位置 ps->a[start - 1] = ps->a[start]; // start向后移动一个位置,继续处理下一个元素 start++; } // 因为第一个元素已经被覆盖,所以不需要额外处理 // 更新顺序列表的大小(元素数量),因为删除了一个元素,所以大小减1 ps->size--;
}
4.8顺序表尾删
SeqListPopBack函数用于删除顺序列表的最后一个元素。它首先通过断言确保列表不为空,然后直接更新列表的大小。
// 尾删:删除顺序列表的最后一个元素
void SeqListPopBack(SL* ps)
{ // 断言,确保顺序列表不为空,即其大小大于0 // 如果ps->size <= 0,则触发断言错误,终止程序 assert(ps->size > 0); // 可以选择将最后一个元素的值设置为0或其他默认值,以确保不留下未定义的值 // 但这取决于具体的应用需求,有时可能不需要这样做 //ps->a[ps->size - 1] = 0; // 更新顺序列表的大小(元素数量),因为删除了一个元素,所以大小减1 ps->size--;
}
4.9顺序表在pos位置插入x
SeqListInsert函数的主要作用是在顺序列表的指定位置pos插入一个新元素x。为了达到这个目的,它首先确保插入的位置是有效的(不会超出当前列表的大小),然后检查是否需要扩容。接着,它通过一个循环将pos位置及其之后的元素都向后移动一个位置,以便为新元素腾出空间。最后,它在pos位置插入新元素,并更新列表的大小。
// 在顺序列表的指定位置插入一个元素
void SeqListInsert(SL* ps, int pos, SQDataType x)
{ // 断言,确保插入的位置不会超出当前列表的大小 // 如果pos >= ps->size,则触发断言错误,终止程序 assert(pos < ps->size); // 检查当前顺序列表的容量是否足够,如果不够则进行扩容 SeqListCheckCapacity(ps); // 初始化一个变量end,用于从列表的末尾开始遍历 int end = ps->size - 1; // 当end位置大于或等于要插入的位置pos时,执行循环 // 这个循环用于将pos位置及其之后的元素都向后移动一个位置,为插入新元素腾出空间 while (end >= pos) { // 将当前位置的元素向后移动一个位置 ps->a[end + 1] = ps->a[end]; // end向前移动一个位置,继续处理前一个元素 end--; } // 在腾出的位置pos处插入新元素x ps->a[pos] = x; // 更新顺序列表的大小(元素数量) ps->size++;
}
4.10顺序表删除pos位置的值
SeqListErase函数用于删除顺序列表中指定位置的元素。它首先通过断言确保要删除的位置是有效的,然后通过一个循环将指定位置之后的所有元素都向前移动一个位置,从而覆盖掉指定位置的元素。最后,它更新列表的大小。
// 删除顺序列表中指定位置的元素
void SeqListErase(SL* ps, int pos)
{ // 断言,确保要删除的位置不会超出当前列表的大小 // 如果pos >= ps->size,则触发断言错误,终止程序 assert(pos < ps->size); // 初始化一个变量start,用于从要删除的位置的下一个元素开始遍历 int start = pos + 1; // 当start小于列表大小时,执行循环 // 这个循环用于将pos位置之后的元素都向前移动一个位置,覆盖掉pos位置的元素 while (start < ps->size) { // 将下一个位置的元素移动到当前位置 ps->a[start - 1] = ps->a[start]; // start向后移动一个位置,继续处理下一个元素 start++; } // 更新顺序列表的大小(元素数量),因为删除了一个元素,所以大小减1 ps->size--;
}
今天就先到这了!!!
看到这里了还不给博主扣个:
⛳️ 点赞☀️收藏 ⭐️ 关注!
你们的点赞就是博主更新最大的动力!
有问题可以评论或者私信呢秒回哦。
相关文章:

顺序表的实现
目录 一. 数据结构相关概念 二、线性表 三、顺序表概念及结构 3.1顺序表一般可以分为: 3.2 接口实现: 四、基本操作实现 4.1顺序表初始化 4.2检查空间,如果满了,进行增容编辑 4.3顺序表打印 4.4顺序表销毁 4.5顺…...

深度学习中的池化
1 深度学习池化概述 1.1 什么是池化 池化层是卷积神经网络中常用的一个组件,池化层经常用在卷积层后边,通过池化来降低卷积层输出的特征向量,避免出现过拟合的情况。池化的基本思想就是对不同位置的特征进行聚合统计。池化层主要是模仿人的…...
Java面试整理-Java设计模式
Java中的设计模式通常是从更广泛的面向对象设计模式中借鉴而来的,这些模式旨在解决特定的设计问题和改善代码的可维护性、灵活性和可扩展性。设计模式大致可以分为三类:创建型、结构型和行为型。以下是这三类中一些常见的设计模式: 创建型模式 单例模式(Singleton):确保一…...

用CHAT了解更多知识点
问CHAT:什么是硅基生命和碳基生命? CHAT回复:硅基生命和碳基生命是两种理论性的生物体类型,这些生物体主要是由硅或碳元素以及其他元素构成的。 碳基生命是我们当前所熟知的生命形式。碳元素能够形成稳定且复杂的分子,…...

一个利用摸鱼时间背单词的软件
大家好,我是 Java陈序员。 最近进入了考试季,各种考试,英语四六级、考研、期末考等。不知道大家的英语四六级成绩怎么样呢? 记得大学时,英语四级都是靠高中学习积累的老本才勉强过关。 而六级则是考了多次ÿ…...

Matlab/Simulink的一些功能用法笔记(3)
01--引言 最近加入到一个项目组,有一些测试需要去支持,通过了解原先团队的测试方法后,自己作了如下改善,大大提高了工作效率。这也许就是软件开发的意义吧,能够去除一些重复的机械的人工操作并且结果还非常不可靠。 …...

Wafer晶圆封装工艺介绍
芯片封装的目的(The purpose of chip packaging): 芯片上的IC管芯被切割以进行管芯间连接,通过引线键合连接外部引脚,然后进行成型,以保护电子封装器件免受环境污染(水分、温度、污染物等)&…...

Mac OS 13+,Apple Silicon,删除OBS虚拟摄像头(virtual camera),
原文链接: https://www.reddit.com/r/MacOS/comments/142cv OBS为了捕获摄像头视频,将虚拟摄像头插件内置为系统插件了.如下 直接删除没有权限的,要删除他,在mac os 13以后,需要关闭先关闭苹果系统的完整性保护(SIP) Apple 芯片(M1,....)的恢复模式分为两种,回退恢复模式,和…...
精解 ES6 Promise 用法
🐱 个人主页:SHOW科技,公众号:SHOW科技 🙋♂️ 作者简介:2020参加工作,专注于前端各领域技术,共同学习共同进步,一起加油呀! 💫优质专栏&#x…...

Linux之基础I/O
目录 一、C语言中的文件操作 二、系统文件操作I/O 三、文件描述符fd 1、文件描述符的引入 2、对fd的理解 3、文件描述符的分配规则 四、重定向 1、重定向的原理 2、重定向的系统调用dup2 五、Linux下一切皆文件 一、C语言中的文件操作 1、打开和关闭 在C语言的文…...

Linux开发工具——gcc篇
gcc的使用 文章目录 gcc的使用 历史遗留问题(普通用户sudo) gcc编译过程 预处理(进行宏替换) 编译(生成汇编) 汇编(生成机器可识别代码) 链接(生成可执行文件或库文件&a…...
C#通讯——关于Winform中的简单的Http服务器与客户端
C#通讯——关于Winform中的简单的Http服务器与客户端 前言一、Http是什么?二、简单的Http服务器三、简单的Http客户端四、实际调用五、Winform中Http服务器和WebApi的区别? 前言 在实际项目中通讯的交互的过程中,遇见数据传输时同事和我说用…...
Mendelson AS2 介绍下载和配置
最近与一家国外公司做EDI对接,并且EDI通讯工具是基于AS2协议的。目前开源的as2的开源项目有openas2,Mendelson AS2,和国人写的freeas2但是,现在freeas2已经被从开源中国不能下载了,变为收费的版本了。 如果你需要使用基于AS2协议…...

旅游海报图怎么做二维码展示?扫码即可查看图片
现在旅游攻略的海报可以做成二维码印刷在宣传单单页或者分享给用户来了解目的地的实际情况,出行路线、宣传海报等。用户只需要扫描二维码就可以查看内容,更加的方便省劲,那么旅游海报的图片二维码制作的技巧有哪些呢?使用图片二维…...
常用git指令
初始化Git仓库:git init 添加文件到暂存区:git add <file> 提交更改到本地仓库:git commit -m "commit message" 查看本地仓库的提交历史:git log 创建分支:git branch <branch_name> 切换分支:git checkout <branch_name> 查看所有分支:git…...

【FPGA】分享一些FPGA协同MATLAB开发的书籍
在做FPGA工程师的这些年,买过好多书,也看过好多书,分享一下。 后续会慢慢的补充书评。 【FPGA】分享一些FPGA入门学习的书籍【FPGA】分享一些FPGA协同MATLAB开发的书籍 【FPGA】分享一些FPGA视频图像处理相关的书籍 【FPGA】分享一些FPGA高速…...

幺模矩阵-线性规划的整数解特性
百度百科:幺模矩阵 在线性规划问题中,如果A为幺模矩阵,那么该问题具有最优整数解特性。也就是说使用单纯形法进行求解,得到的解即为整数解。无需再特定使用整数规划方法。 m i n c T x s . t . { A x ≥ b x ≥ 0 \begin{align*} min \quad…...
数据分析思维
Why&What 数据分析是为了驱动决策赋能业务。在数据分析过程中需要对目标进行拆解量化,如何拆解量化目标便是数据分析思维。 在任务拆解过程中使用的软件、统计模型、分析方法等为分析工具和手段,如何在恰当的场景合理的使用这些工具、模型、方法、手…...

C++ boost planner_cond_.wait(lock) 报错1225
1.如下程序段 boost unique_lock doesn’t own the mutex: Operation not permitted 问题: 其中makePlan是一个线程。这里的unlock导致错误这个报错 boost unique_lock doesn’t own the mutex: Operation not permitted bool navigation::makePlan(){ //cv::named…...

LeetCode刷题--- 字母大小写全排列
个人主页:元清加油_【C】,【C语言】,【数据结构与算法】-CSDN博客 个人专栏 力扣递归算法题 http://t.csdnimg.cn/yUl2I 【C】 http://t.csdnimg.cn/6AbpV 数据结构与算法 http://t.csdnimg.cn/hKh2l 前言:这个专栏主要讲述递归递归、搜索与回…...
R语言AI模型部署方案:精准离线运行详解
R语言AI模型部署方案:精准离线运行详解 一、项目概述 本文将构建一个完整的R语言AI部署解决方案,实现鸢尾花分类模型的训练、保存、离线部署和预测功能。核心特点: 100%离线运行能力自包含环境依赖生产级错误处理跨平台兼容性模型版本管理# 文件结构说明 Iris_AI_Deployme…...
五年级数学知识边界总结思考-下册
目录 一、背景二、过程1.观察物体小学五年级下册“观察物体”知识点详解:由来、作用与意义**一、知识点核心内容****二、知识点的由来:从生活实践到数学抽象****三、知识的作用:解决实际问题的工具****四、学习的意义:培养核心素养…...
ip子接口配置及删除
配置永久生效的子接口,2个IP 都可以登录你这一台服务器。重启不失效。 永久的 [应用] vi /etc/sysconfig/network-scripts/ifcfg-eth0修改文件内内容 TYPE"Ethernet" BOOTPROTO"none" NAME"eth0" DEVICE"eth0" ONBOOT&q…...

C# 求圆面积的程序(Program to find area of a circle)
给定半径r,求圆的面积。圆的面积应精确到小数点后5位。 例子: 输入:r 5 输出:78.53982 解释:由于面积 PI * r * r 3.14159265358979323846 * 5 * 5 78.53982,因为我们只保留小数点后 5 位数字。 输…...
rnn判断string中第一次出现a的下标
# coding:utf8 import torch import torch.nn as nn import numpy as np import random import json""" 基于pytorch的网络编写 实现一个RNN网络完成多分类任务 判断字符 a 第一次出现在字符串中的位置 """class TorchModel(nn.Module):def __in…...

Docker 本地安装 mysql 数据库
Docker: Accelerated Container Application Development 下载对应操作系统版本的 docker ;并安装。 基础操作不再赘述。 打开 macOS 终端,开始 docker 安装mysql之旅 第一步 docker search mysql 》〉docker search mysql NAME DE…...

【 java 虚拟机知识 第一篇 】
目录 1.内存模型 1.1.JVM内存模型的介绍 1.2.堆和栈的区别 1.3.栈的存储细节 1.4.堆的部分 1.5.程序计数器的作用 1.6.方法区的内容 1.7.字符串池 1.8.引用类型 1.9.内存泄漏与内存溢出 1.10.会出现内存溢出的结构 1.内存模型 1.1.JVM内存模型的介绍 内存模型主要分…...
python爬虫——气象数据爬取
一、导入库与全局配置 python 运行 import json import datetime import time import requests from sqlalchemy import create_engine import csv import pandas as pd作用: 引入数据解析、网络请求、时间处理、数据库操作等所需库。requests:发送 …...

若依登录用户名和密码加密
/*** 获取公钥:前端用来密码加密* return*/GetMapping("/getPublicKey")public RSAUtil.RSAKeyPair getPublicKey() {return RSAUtil.rsaKeyPair();}新建RSAUti.Java package com.ruoyi.common.utils;import org.apache.commons.codec.binary.Base64; im…...

yaml读取写入常见错误 (‘cannot represent an object‘, 117)
错误一:yaml.representer.RepresenterError: (‘cannot represent an object’, 117) 出现这个问题一直没找到原因,后面把yaml.safe_dump直接替换成yaml.dump,确实能保存,但出现乱码: 放弃yaml.dump,又切…...