数据结构---单链表
专栏:数据结构
个人主页:HaiFan.
专栏简介:从零开始,数据结构!!
单链表
- 前言
- 顺序表的缺陷
- 链表的概念以及结构
- 链表接口实现
- 打印链表中的元素SLTPrint
- phead->next!=NULL和phead!=NULL的区别
- 开辟空间SLTNewNode
- 尾插SLTPushBack和尾删SLTPopBack
- 头插SLTPushFront和头删SLTPopFront
- 查找SLTFind
- 在查找元素的后面插入SLTInsertAfter
- 在查找元素的后面删除SLTEraseAfter
- 销毁开辟的空间SLTDestory
- 各个接口测试
- 源代码
- 链表和顺序表的区别
前言
顺序表的缺陷
顺序表每一次扩容,都是连续的空间,支持通过下标去访问数据。
但是顺序表的头插,头删,中间删元素,需要把后面的数据覆盖前面的元素,也就是挪动元素,这就导致效率非常的低
并且,顺序表在扩容之后,可能会有一部分空间没有用,这就导致了空间浪费。
链表的概念以及结构
链表是一种物理存储结构上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的 。
链表的结点一般是在堆上申请出来的,从堆上申请的空间,是按照一定策略来分配的,两次申请的空间可能连续,也可能不连续。
链表是每用一块空间,便开辟一块空间,因此,不会造成空间浪费。
这个图什么意思呢?
把开辟的空间当作2个合在一起的小方块,一个小方块用来存元素的值,一个方块用来存放下一个空间的地址。
当这个1就是最后一个元素的时候,这个下一块空间的地址就是NULL,因为1后面没有元素了,不能让这个地址乱指向其他的空间。
链表接口实现
这里,在结构体中要用结构体指针,指针就是地址,这个地址就是用来存放下一个空间的地址的。
typedef int SLTDataType;typedef struct SLTNode
{SLTDataType val;struct SLTNode* next;
}SLT;void SLTPrint(SLT* phead);//打印单链表中的数据SLT* SLTNewNode(SLTDataType x);//每要插入数据,就需要开一一块空间void SLTPushBack(SLT** pphead, SLTDataType x);//尾插
void SLTPopBack(SLT** pphead);//尾删void SLTPushFront(SLT** pphead, SLTDataType x);//头插
void SLTPopFront(SLT** pphead);//头删SLT* SLTFind(SLT** pphead, SLTDataType x);//查找
//单链表在pos位置之后插入x
void SLTInsertAfter(SLT* pos, SLTDataType x);//插入
//单链表在pos位置之后删除元素
void SLTEraseAfter(SLT* pos);//删除void SLTDestory(SLT** pphead);//销毁空间
打印链表中的元素SLTPrint
打印链表中的元素是最容易实现的一个接口。
void SLTPrint(SLT* phead)
{while (phead != NULL){cout << phead->val << "->";phead = phead->next;}cout << "NULL" << endl;
}
这里用一级指针,因为打印链表不会更改链表中的一些东西。
每打印出一个元素,都让phead指向下一块空间,直到走到为NULL的时候为止
phead->next!=NULL和phead!=NULL的区别
假如现在phead是在3这块空间,那么phead->next就是指向下一块空间,因为下一块空间是NULL,所以,当你写出phead->next != NULL的时候,就会在3这里停止后面的打印。
phead !=NULL是当phead走到NULL的时候才会执行。
开辟空间SLTNewNode
链表是每用一块空间就开辟一块空间。这样不会造成空间浪费。
SLT* SLTNewNode(SLTDataType x)
{SLT* newnode = (SLT*)malloc(sizeof(SLT));newnode->next = NULL;newnode->val = x;return newnode;
}
开辟了空间之后,不要忘记把newnode->next置为NULL,不然就成为野指针了。最后把这块空间返回即可。
尾插SLTPushBack和尾删SLTPopBack
尾插的时候,先调用一下开辟空间的函数,再把开辟的空间返回,用一个结构体指针变量接收。
- 当链表为空的时候,newnode就可以当作链表中的第一块空间。
- 当链表不为空的时候,就需要先找到链表的尾部,然后把newnode链接在链表中即可
void SLTPushBack(SLT** pphead, SLTDataType x)
{SLT* newnode = SLTNewNode(x);if (*pphead == NULL){*pphead = newnode;}else{SLT* tail = *pphead;while (tail->next != NULL){tail = tail->next;}tail->next = newnode;}
}
要用一个临时变量走向链表最后一个元素的位置,如果不用临时变量,直接用头元素走到最后一个位置,那么,在打印元素的时候,也是从最后一个元素的位置开始打印的,前面的元素不会打印,因为我们是用指针接收的头元素的位置,通过指针直接去访问内容,指针走到最后就会导致,原本应该指向头元素的指针,就指向了最后的元素。
所以在这里用 tail->next != NULL
尾删分两种情况,当链表中只有一个元素的时候和链表中有n个元素的时候。
第一种情况好说,直接把第一个元素的空间给free掉,在置为空即可。
第二种情况就是先找到尾,但是,在找到尾部之后,不能直接把尾部free掉,而是要先知道倒数第二个元素的位置。
void SLTPopBack(SLT** pphead)
{assert(*pphead);if ((*pphead)->next == NULL){free(*pphead);*pphead = NULL;}else{SLT* tail = *pphead;while (tail->next->next != NULL){ tail = tail->next;}free(tail->next);tail->next = NULL;}
}/*SLTNode* prev = NULL;SLTNode* tail = phead;while (tail->next){prev = tail;tail = tail->next;}free(tail);prev->next = NULL;*/
这两种方法都可以。
头插SLTPushFront和头删SLTPopFront
头插特别容易,先开辟一块空间,然后把这块空间指向头元素空间。在把头元素空间指向新开辟的空间即可。
void SLTPushFront(SLT** pphead, SLTDataType x)
{SLT* newnode = SLTNewNode(x);newnode->next = *pphead;*pphead = newnode;
}
头删之前,要先判断链表中有没有元素,没有元素直接断言。
有一个元素,直接free。
多个元素,先用一个临时变量记录一下头元素指向的下一个元素的地址,然后把头元素给free掉,再让头元素=临时变量。
void SLTPopFront(SLT** pphead)
{assert(*pphead);if ((*pphead)->next == NULL){free(*pphead);*pphead = NULL;}else{SLT* head = (*pphead)->next;free(*pphead);*pphead = NULL;*pphead = head;}
}
查找SLTFind
查找元素的时候,把该空间的地址给返回即可,遍历一遍链表即可实现。
SLT* SLTFind(SLT** pphead, SLTDataType x)
{SLT* tail = *pphead;while (tail != NULL){if (tail->val == x){return tail;}tail = tail->next;}return NULL;//没有找到
}
在查找元素的后面插入SLTInsertAfter
先通过SLTFind,找到要插入的位置,然后通过断言来判断这个位置是否合法。
比如要把3插入到1和2之间,把3->next = 1->next,再把1->next = 3就能完成插入。
void SLTInsertAfter(SLT* pos, SLTDataType x)
{assert(pos);SLT* newnode = SLTNewNode(x);newnode->next = pos->next;pos->next = newnode;}
在查找元素的后面删除SLTEraseAfter
还是先断言,判断位置是否合法。
电脑上的画图实在是用不来,原谅我------。。。
void SLTEraseAfter(SLT* pos)
{assert(pos);if (pos->next == NULL){return;}SLT* newnode = pos->next;pos->next = newnode->next;free(newnode);newnode = NULL;
}
销毁开辟的空间SLTDestory
因为空间不一定是连续的,所以需要遍历链表,一个一个的释放
void SLTDestory(SLT** pphead)
{SLT* cur = *pphead;while (cur){SLT* hh = cur->next;free(cur);cur = hh;}
}
各个接口测试
void TestSLTNode()
{SLT* plist = NULL;cout << "尾插尾删" << endl;SLTPushBack(&plist, 1);SLTPushBack(&plist, 2);SLTPushBack(&plist, 3);SLTPushBack(&plist, 4);SLTPushBack(&plist, 4);SLTPopBack(&plist);SLTPopBack(&plist);SLTPopBack(&plist);SLTPopBack(&plist);SLTPrint(plist);
}void TestSLTNode1()
{SLT* plist = NULL;cout << "头插头删" << endl;SLTPushFront(&plist, 1);SLTPushFront(&plist, 2);SLTPushFront(&plist, 3);SLTPushFront(&plist, 4);SLTPopFront(&plist);SLTPopFront(&plist);SLTPopFront(&plist);SLTPrint(plist);
}void TestSLTNode2()
{SLT* plist = NULL;cout << "查找,删除,插入" << endl;SLTPushFront(&plist, -1);SLTPushBack(&plist, 1);SLTPushFront(&plist, -2);SLTPushBack(&plist, 2);SLTPushFront(&plist, -3);SLTPushBack(&plist, 3);SLTPushFront(&plist, -4);SLTPushBack(&plist, 4);SLT* ret = SLTFind(&plist, 3);if (ret){cout << ret << endl;}SLTPrint(plist);SLTInsertAfter(ret, 100);SLTInsertAfter(ret, 100);SLTInsertAfter(ret, 100);SLTPrint(plist);SLTEraseAfter(ret);SLTEraseAfter(ret);SLTPrint(plist);SLTDestory(&plist);
}int main()
{TestSLTNode();TestSLTNode1();TestSLTNode2();return 0;
}
源代码
.h文件
#pragma once#include <iostream>
#include <stdlib.h>
#include <assert.h>using namespace std;typedef int SLTDataType;typedef struct SLTNode
{SLTDataType val;struct SLTNode* next;
}SLT;void SLTPrint(SLT* phead);//打印单链表中的数据SLT* SLTNewNode(SLTDataType x);//每要插入数据,就需要开一一块空间void SLTPushBack(SLT** pphead, SLTDataType x);//尾插
void SLTPopBack(SLT** pphead);//尾删void SLTPushFront(SLT** pphead, SLTDataType x);//头插
void SLTPopFront(SLT** pphead);//头删SLT* SLTFind(SLT** pphead, SLTDataType x);//查找
//单链表在pos位置之后插入x
void SLTInsertAfter(SLT* pos, SLTDataType x);//插入
//单链表在pos位置之后删除元素
void SLTEraseAfter(SLT* pos);//删除void SLTDestory(SLT** pphead);//销毁空间
.cpp文件
#define _CRT_SECURE_NO_WARNINGS 1#include "SList.h"void SLTPrint(SLT* phead)
{while (phead){cout << phead->val << "->";phead = phead->next;}cout << "NULL" << endl;
}SLT* SLTNewNode(SLTDataType x)
{SLT* newnode = (SLT*)malloc(sizeof(SLT));newnode->next = NULL;newnode->val = x;return newnode;
}void SLTPushBack(SLT** pphead, SLTDataType x)
{SLT* newnode = SLTNewNode(x);if (*pphead == NULL){*pphead = newnode;}else{SLT* tail = *pphead;while (tail->next != NULL){tail = tail->next;}tail->next = newnode;}
}void SLTPopBack(SLT** pphead)
{assert(*pphead);if ((*pphead)->next == NULL){free(*pphead);*pphead = NULL;}else{SLT* tail = *pphead;while (tail->next->next != NULL){ tail = tail->next;}free(tail->next);tail->next = NULL;}
}void SLTPushFront(SLT** pphead, SLTDataType x)
{SLT* newnode = SLTNewNode(x);newnode->next = *pphead;*pphead = newnode;
}void SLTPopFront(SLT** pphead)
{assert(*pphead);if ((*pphead)->next == NULL){free(*pphead);*pphead = NULL;}else{SLT* head = (*pphead)->next;free(*pphead);*pphead = NULL;*pphead = head;}
}SLT* SLTFind(SLT** pphead, SLTDataType x)
{SLT* tail = *pphead;while (tail != NULL){if (tail->val == x){return tail;}tail = tail->next;}return NULL;//没有找到
}void SLTInsertAfter(SLT* pos, SLTDataType x)
{assert(pos);SLT* newnode = SLTNewNode(x);newnode->next = pos->next;pos->next = newnode;}void SLTEraseAfter(SLT* pos)
{assert(pos);if (pos->next == NULL){return;}SLT* newnode = pos->next;pos->next = newnode->next;free(newnode);newnode = NULL;
}void SLTDestory(SLT** pphead)
{SLT* cur = *pphead;while (cur){SLT* hh = cur->next;free(cur);cur = hh;}
}
test.cpp文件
#define _CRT_SECURE_NO_WARNINGS 1#include "SList.h"void TestSLTNode()
{SLT* plist = NULL;cout << "尾插尾删" << endl;SLTPushBack(&plist, 1);SLTPushBack(&plist, 2);SLTPushBack(&plist, 3);SLTPushBack(&plist, 4);SLTPushBack(&plist, 4);SLTPopBack(&plist);SLTPopBack(&plist);SLTPopBack(&plist);SLTPopBack(&plist);SLTPrint(plist);
}void TestSLTNode1()
{SLT* plist = NULL;cout << "头插头删" << endl;SLTPushFront(&plist, 1);SLTPushFront(&plist, 2);SLTPushFront(&plist, 3);SLTPushFront(&plist, 4);SLTPopFront(&plist);SLTPopFront(&plist);SLTPopFront(&plist);SLTPrint(plist);
}void TestSLTNode2()
{SLT* plist = NULL;cout << "查找,删除,插入" << endl;SLTPushFront(&plist, -1);SLTPushBack(&plist, 1);SLTPushFront(&plist, -2);SLTPushBack(&plist, 2);SLTPushFront(&plist, -3);SLTPushBack(&plist, 3);SLTPushFront(&plist, -4);SLTPushBack(&plist, 4);SLT* ret = SLTFind(&plist, 3);if (ret){cout << ret << endl;}SLTPrint(plist);SLTInsertAfter(ret, 100);SLTInsertAfter(ret, 100);SLTInsertAfter(ret, 100);SLTPrint(plist);SLTEraseAfter(ret);SLTEraseAfter(ret);SLTPrint(plist);SLTDestory(&plist);
}int main()
{TestSLTNode();TestSLTNode1();TestSLTNode2();return 0;
}
链表和顺序表的区别
不同点 | 顺序表 | 链表 |
---|---|---|
存储空间上 | 物理上一定连续 | 逻辑上连续,但物理上不一定 连续 |
随机访问 | 支持O(1) | 不支持:O(N) |
任意位置插入或者删除 元素 | 可能需要搬移元素,效率低 O(N) | 只需修改指针指向 |
插入 | 动态顺序表,空间不够时需要 扩容 | 没有容量的概念 |
应用场景 | 元素高效存储+频繁访问 | 任意位置插入和删除频繁 |
缓存利用率 | 高 | 低 |
相关文章:

数据结构---单链表
专栏:数据结构 个人主页:HaiFan. 专栏简介:从零开始,数据结构!! 单链表前言顺序表的缺陷链表的概念以及结构链表接口实现打印链表中的元素SLTPrintphead->next!NULL和phead!NULL的区别开辟空间SLTNewNod…...

redis数据结构的底层实现
文章目录一.引言二.redis的特点三.Redis的数据结构a.字符串b.hashc.listd.sete.zset(有序集合)一.引言 redis是一个开源的使用C语言编写、支持网络、可基于内存亦可持久化的日志型、key-value的NoSQL数据库。 通常使用redis作为缓存中间件来降低数据库的压力,除此…...

【JavaSE】复习(进阶)
文章目录1.final关键字2.常量3.抽象类3.1概括3.2 抽象方法4. 接口4.1 接口在开发中的作用4.2类型和类型之间的关系4.3抽象类和接口的区别5.包机制和import5.1 包机制5.2 import6.访问控制权限7.Object7.1 toString()7.2 equals()7.3 String类重写了toString和equals8.内部类8.1…...

Java 主流日志工具库
日志系统 java.util.logging (JUL) JDK1.4 开始,通过 java.util.logging 提供日志功能。虽然是官方自带的log lib,JUL的使用确不广泛。 JUL从JDK1.4 才开始加入(2002年),当时各种第三方log lib已经被广泛使用了JUL早期存在性能问题&#x…...

产品经理有必要考个 PMP吗?(含PMP资料)
现在基本上做产品的都有一个PMP证件,从结果导向来说,不对口不会有这么大范围的人来考,但是需要因地制宜,在公司内部里,标准程序并不流畅,产品和项目并不规范,关系错综复杂。 而产品经理的职能又…...

什么是原型、原型链?原型和原型链的作用
1、ES6之前,继承都用构造函数来实现;对象的继承,先申明一个对象,里面添加实例成员<!DOCTYPE html> <html><head><meta charset"utf-8" /><title></title></head><body><script…...

条件期望4
条件期望例题----快排算法的分析 快速排序算法的递归定义如下: 有n个数(n≥2n\geq 2n≥2), 一开始随机选取一个数xix_ixi, 并将xix_ixi和其他n-1个数进行比较, 记SiS_iSi为比xix_ixi小的元素构成的集合, Siˉ\bar{S_i}Siˉ为比xix_ixi大的元素构成的集合, 然后分…...

网络协议分析(2)判断两个ip数据包是不是同一个数据包分片
一个节点收到两个IP包的首部如下:(1)45 00 05 dc 18 56 20 00 40 01 bb 12 c0 a8 00 01 c0 a8 00 67(2)45 00 00 15 18 56 00 b9 49 01 e0 20 c0 a8 00 01 c0 a8 00 67分析并判断这两个IP包是不是同一个数据报的分片&a…...

6.2 负反馈放大电路的四种基本组态
通常,引入交流负反馈的放大电路称为负反馈放大电路。 一、负反馈放大电路分析要点 如图6.2.1(a)所示电路中引入了交流负反馈,输出电压 uOu_OuO 的全部作为反馈电压作用于集成运放的反向输入端。在输入电压 uIu_IuI 不变的情况下,若由于…...

MySQL进阶之锁
锁是计算机中协调多个进程或线程并发访问资源的一种机制。在数据库中,除了传统的计算资源竞争之外,数据也是一种提供给许多用户共享的资源,如何保证数据并发访问的一致性和有效性是数据库必须解决堆的一个问题,锁冲突也是影响数据…...

【Mac 教程系列】如何在 Mac 上破解带有密码的 ZIP 压缩文件 ?
如何使用 fcrackzip 在 Mac 上破解带有密码的 ZIP 压缩文件? 用 markdown 格式输出答案。 在 Mac 上破解带有密码的 ZIP 压缩文件 使用解压缩软件,如The Unarchiver,将文件解压缩到指定的文件夹。 打开终端,输入 zip -er <zipfile> &…...

【Acwing 周赛复盘】第92场周赛复盘(2023.2.25)
【Acwing 周赛复盘】第92场周赛复盘(2023.2.25) 周赛复盘 ✍️ 本周个人排名:1293/2408 AC情况:1/3 这是博主参加的第七次周赛,又一次体会到了世界的参差(这次周赛记错时间了,以为 19:15 开始&…...

L1-087 机工士姆斯塔迪奥
在 MMORPG《最终幻想14》的副本“乐欲之所瓯博讷修道院”里,BOSS 机工士姆斯塔迪奥将会接受玩家的挑战。 你需要处理这个副本其中的一个机制:NM 大小的地图被拆分为了 NM 个 11 的格子,BOSS 会选择若干行或/及若干列释放技能,玩家…...

本周大新闻|索尼PS VR2立项近7年;传腾讯将引进Quest 2
本周大新闻,AR方面,传立讯精密开发苹果初代AR头显,第二代低成本版将交给富士康;iOS 16.4代码曝光新的“计算设备”;EM3推出AR眼镜Stellar Pro;努比亚将在MWC2023推首款AR眼镜。VR方面,传闻腾讯引…...

aws console 使用fargate部署aws服务快速跳转前端搜索栏
测试过程中需要在大量资源之间跳转,频繁的点击不如直接搜索来的快,于是写了一个搜索框方便跳转。 前端的静态页面可以通过s3静态网站托管实现,但是由于中国区需要备案的原因,可以使用ecs fargate部署 步骤如下: 编写…...

Redis实战之Redisson使用技巧详解
一、摘要什么是 Redisson?来自于官网上的描述内容如下!Redisson 是一个在 Redis 的基础上实现的 Java 驻内存数据网格客户端(In-Memory Data Grid)。它不仅提供了一系列的 redis 常用数据结构命令服务,还提供了许多分布…...

SQLAlchemy
文章目录SQLAlchemy介绍SQLAlchemy入门使用原生sql使用orm外键关系一对多关系多对多关系基于scoped_session实现线程安全简单表操作实现方案CRUDFlask 集成 sqlalchemySQLAlchemy 介绍 SQLAlchemy是一个基于Python实现的ORM框架。该框架建立在 DB API之上,使用关系…...

【Linux学习笔记】8.Linux yum 命令和apt 命令
前言 本章介绍Linux的yum命令和apt命令。 Linux yum 命令 yum( Yellow dog Updater, Modified)是一个在 Fedora 和 RedHat 以及 SUSE 中的 Shell 前端软件包管理器。 基于 RPM 包管理,能够从指定的服务器自动下载 RPM 包并且安装…...

windows服务器实用(4)——使用IIS部署网站
windows服务器实用——IIS部署网站 如果把windows服务器作为web服务器使用,那么在这个服务器上部署网站是必须要做的事。在windows服务器上,我们一般使用IIS部署。 假设此时前端给你一个已经完成的网站让你部署在服务器上,别人可以在浏览器…...

Random(二)什么是伪共享?@sun.misc.Contended注解
目录1.背景简介2.伪共享问题3.问题解决4.JDK使用示例1.背景简介 我们知道,CPU 是不能直接访问内存的,数据都是从高速缓存中加载到寄存器的,高速缓存又有 L1,L2,L3 等层级。在这里,我们先简化这些复杂的层级…...

Linux解压压缩
打包tar首先我们得提一下专门用于打包文件的命令——tartar用于备份文件,打包多个文件或者目录,也可以用于还原被打包的文件假设打包目录test下的文件 tar -cvf test.tar ./test 假设打包目录test下的文件,并用gzip命令将包压缩 tar -zcvf test.tar ./te…...

JavaSe第3次笔记
1.String str "hello";字符串类型。 2.两个字符串类型相加意思是拼接,类似于c语言里面的strcat函数。 3.整型变成字符串类型: int a 10; String str String. valueOf(a); 4.当字符串和其他类型进行相加的时候,结果就是字符串。(不完全…...

非人工智能专业怎样从零开始学人工智能?
人工智能(Artificial Intelligence,AI)是指让机器具有类似人类智能的能力,包括感知、理解、推理、学习、规划、决策、创造等多个方面。人工智能研究涉及到计算机科学、数学、物理学、心理学、哲学等多个领域,旨在模拟和…...

MyBatis之增、删、查、改
目录 前言 一、配置MyBatis开发环境 1.1 创建数据库和表 1.2 添加框架支持 1.3 创建目录结构 1.4 配置数据库连接 1.5 配置MyBatis中的XML文件路径 二、添加业务代码 2.1 查询数据库操作 2.1.1 添加实体类 2.1.2 添加mapper接口 2.1.3 在xml中实现mapper接口 2.1.…...

死磕Spring,什么是SPI机制,对SpringBoot自动装配有什么帮助
文章目录如果没时间看的话,在这里直接看总结一、Java SPI的概念和术语二、看看Java SPI是如何诞生的三、Java SPI应该如何应用四、从0开始,手撸一个SPI的应用实例五、SpringBoot自动装配六、Spring SPI机制与Spring Factories机制做对比七、这里是给我自…...

因果推断10--一种大规模预算约束因果森林算法(LBCF)
论文:A large Budget-Constrained Causal Forest Algorithm 论文:http://export.arxiv.org/pdf/2201.12585v2.pdf 目录 0 摘要 1 介绍 2 问题的制定 3策略评价 4 方法 4.1现有方法的局限性。 4.2提出的LBCF算法 5验证 5.1合成数据 5.2离线生…...

Linux基础命令-df显示磁盘的使用情况
文章目录 文章目录 df 命令介绍 语法格式 基本参数 参考实例 1)以人类可读形式显示磁盘空间的使用情况 2)显示磁盘的inode信息 3)显示磁盘和文件系统类型 4)指定显示文件系统 5)显示所有磁盘空间中的内容 …...

如何使用goquery进行HTML解析以及它的源码分析和实现原理
目录 goquery 是什么 goquery 能用来干什么 goquery quick start 玩转goquery.Find() 查找多个标签 Id 选择器 Class 选择器 属性选择器 子节点选择器 内容过滤器 goquery 源码分析 图解源码 总结 goquery 简介 goquery是一款基于Go语言的HTML解析库,…...

【Java 数组和集合 区别及使用案例】
Java中数组和集合都是用来存储一组数据的容器,但是在实际使用中,它们有一些区别和不同的使用场景。 数组 vs 集合:存储方式 数组是一个固定长度的容器,它的长度一旦被初始化之后,就无法再改变了。而集合是一个动态长…...

使用pynimate制作动态排序图
大家好,数据可视化动画使用Python包就可以完成,效果如下:想要使用Pynimate,直接import一下就行:import pynimate as nim输入数据后,Pynimate将使用函数Barplot()来创建条形数据动画。…...