数据结构入门指南:顺序表

news2024/11/17 3:40:44

目录

文章目录

前言

顺序表

静态顺序表

动态顺序表

总结


前言

        今天我们正式进入对数据结构的学习,顺序表是数据结构中最简单的一种线性数据结构,也是数据结构入门的试金石,如果对于顺序表中内容理解过难,可以先填补一下C语言中结构体、动态内存管理及指针部分的知识。这也是步入数据结构学习的基础。接下来我将向大家一一介绍顺序表以及实现。


顺序表

 概念及定义

        顺序表是用一段物理地址连续的存储单元依次存储数据元素的线性结构,一般情况下采用数组存储。在数组上完成数据的增删查改。

 顺序表一般可以分为:

  • 静态顺序表:使用定长数组存储元素
  • 动态顺序表:使用动态开辟的数组存储。

        顺序表的主要功能就是对数组数据进行管理,例如我想要增加、删除、修改数组中的数据时如果每次都手动输入就会很麻烦,于是就进阶到了顺序表,对数组数据进行管理操作。

静态顺序表

静态顺序表:使用定长数组存储元素

 定义一个顺序表:

#define N 100
typedef struct SeqList
{
	int data[N]
	int sz;//有效数据个数
}SL;

         这里使用typedef将我们自定义的结构体类型进行重命名,重命名为SL,所以在创建结构体变量时就可以使用SL来替代struct SeqList。

但是在大多数情况下我们都不会选择静态的顺序表,它是非常不实用的。静态顺序表存在的问题就在于它的静态:

  • 存储的容量是固定的
  • 当容量开辟过大,而仅仅使用了一小部分,就会造成空间的浪费。

 静态顺序表的实现相对简单,不需要动态开辟空间,扩容,初始化操作也比较简单,所以说我们今天主要对动态顺序表进行讲解介绍。

动态顺序表

         顺序表的动态存储就相对静态麻烦一点,不同点在于初始化,额外增加检查是否满添加一个扩容操作。如果是动态的顺序表,再使用静态定义的顺序表就不合适,因为需要判断顺序表是否满,所以这里再定义一个变量来记录顺序表的容量。

定义顺序表:

typedef int Datatype;//重定义数据类型,便于后续修改存储的数据类型
typedef struct SeqList
{
	Datatype* data;//Datatype*等价于 int*
	int sz;//有效数据个数
	int len;//容量
}SL;

         如果使用的是VS之类的这种集成式开发环境的编译器,本人推荐分装多文件进行编写程序,这样可以使代码更加清晰,最后我也会把多文件分装的代码附上。

        回到正题,已经创建好了顺序表,接下来就是顺序表的初始化。在进行该部分讲解之前,这里需要提到一个知识点,就是结构体传参,为什么要传结构体的地址,传值还是传址?早在C语言初阶就有提到,传值调用在函数内是数据的临时拷贝,出了函数机会被销毁,对原本的数据并不会有影响,对顺序表进行数据管理都是对表内数据进行修改,所以顺序表是使用传址调用。

         初始化需要将结构体的地址传过去,那要怎么传呢?很多初学者会搞混。认为定义的结构体就是顺序表,其实并不是,定义的结构体只是我们自己定义的顺序表类型,而顺序表我们还并没有创建。

int main()
{
	SL s;
    InitSeqList(&s);
    return 0;
}

        在主函数内创建一个结构体变量,这个结构体变量才是真正实质上的顺序表。在初始化时我们需要将顺序表的地址传过去,参数直接&s即可。

        我们传过去的是顺序表的地址,在函数定义时需要与之对应的形参进行接收,传过去的类型是结构体变量的地址(指针),所以这里需要一个结构类型的指针变量去接收。

void InitSeqList(SL* ps)

 接下来就是初始部分的实现:

void InitSeqList(SL* ps) {
	ps->data = (Datatype*)malloc(sizeof(Datatype) * N);//N为默认开辟的个数,这里N设置的值为3,便于测试增容
	if (ps->data == NULL)
	{
		perror("malloc");//输出错误原因
		exit(-1);//退出程序
	}
	ps->len = N;
	ps->sz = 0;
}

        初始化部分没有什么难点,主要需要大家注意:动态开辟时使用了malloc函数,可以参考一下博客:动态内存管理函数的使用与优化技巧。在动态内存分配时,可能开辟失败,开辟失败就会返回一个空指针(NULL),所以需要对返回值进行判断,如果为空就直接退出程序。sz有效的数据个数为0,len容量大小为N(3)。当然使用了malloc开辟空间就需要将空间释放,还给操作系统。

这里我们接着写一个函数对空间进行释放:

void DestorySL(SL* ps)
{
	free(ps->data);
	ps->len = 0;
	ps->sz = 0;
}

         顺序表的涉及的基础已经理解,那后续的操作就简单了我们接着继续对顺序表进行操作接口的实现,尾插:

void PushBackSL(SL* ps, Datatype x)
{
	SLCheck(ps);
	ps->data[ps->sz] = x;
	ps->sz++;
}

         从末尾插入是很简单的,但这里需要额外考虑的一点是,容量问题,容量是否够用,这里就需要进行扩容,在其他增加节点的操作时也需要扩容,为了便于使用,我们可以封装成一个函数检查容量是否满。

        检查函数都是在其他函数中调用的,所以就不能单纯&s,但是&s的值已经传给了ps(指针),所以我们可以将ps传过去。代码如下:

void SLCheck(SL* ps)
{
	if (ps->sz == ps->len)
	{
		Datatype* pc = (Datatype*)realloc(ps->data, sizeof(Datatype) * 2 * ps->len);
		if (pc == NULL)
		{
			perror("realloc");
			exit(-1);
		}
		ps->data = pc;
		ps->len *= 2;
	}

}

        从C语言转到对数据结构的学习,需要大家改变一下敲代码的习惯,C语言中的程序都相对较短,写完进行运行测试,但数据结构不同,一个程序可能存在多个接口,这就是需要我们写一部分测试一部分,这样避免在最后测试时发现几十个错误再改错高效的多。为了便于测试,我们继续封装一个打印数据的函数。

void printfSL(SL* ps)
{
	for (int i = 0; i < ps->sz; i++)
	{
		printf("%d ", ps->data[i]);
	}
	printf("\n");
}

测试时我们就朴实一点,直接传给它多个值:

int main()
{
	SL s;
	InitSeqList(&s);
	PushBackSL(&s, 6);
	PushBackSL(&s, 6);
	PushBackSL(&s, 6);
	PushBackSL(&s, 3);
	PushBackSL(&s, 3);
	PushBackSL(&s, 4);
	printfSL(&s);
	
	return 0;
}

 这样直接插入数据观察扩容和插入功能是否完善。接着继续尾插接口实现:

void PopBlackSL(SL* ps) {
	if (ps->sz == 0)
	{
		printf("顺序表为空\n");
		return;
	}
	ps->sz--;
}

        尾插也是很简单的,我们并不需要将原先的数据置为某个数字,只需要将sz也就是有效数据减一,这样下次插入数据时,就会将原先的数据自动覆盖。但是需要注意一点是,如果顺序表已经为空就不可以再减了(再减就会越界),所以增加一个判断顺序表的数据是否为空。后边的测试我就不再演示,可以在每个接口实现以后自主测试。

头插:

void PushFrontSL(SL* ps, Datatype x)
{
	SLCheck(ps);
	int end = ps->sz - 1;
	while (end >= 0)
	{
		ps->data[end + 1] = ps->data[end];
		end--;
	}
	ps->data[0] = x;
	ps->sz++;
}

         头插时我们需要将原先的数据向后移动一个位置,在第一个位置插入数据,在挪动数据的时候不能从头开始往后挪,那样会造成数据的覆盖,所以只能从后边开始一个一个的挪动。这里我们就能感受到,头插的效率是不高的。

 头删:

void SListPopFront(SL* ps) {
	for (int i = 0; i < ps->sz - 1; i++)
	{
		ps->data[i] = ps->data[i + 1];
	}
	assert(ps->sz > 0);//断言,判断有效数据个数是否大于0,小于0就直接报错
	ps->sz--;
}

         头删的实现就是将后一位的数据向前挪动,覆盖前一个数据,但这里需要注意数据被覆盖的问题,头删需要从下标为1的位置开始向前挪动,此外还需要注意sz的大小。

 位置插入:

void SLInsert(SL* ps, int pos, Datatype x) {
	assert(pos >= 0 && pos <= ps->sz);
	int end = ps->sz - 1;
	SLCheck(ps);
	while(end>=pos)
	{
		ps->data[end + 1] = ps->data[end];
		end--;
	}
	ps->data[pos] = x;
	ps->sz++;
}

         位置插入的原理和头插的思路相似,不同点在于停止的位置,数据插入位置,数据停止挪动的位置在下标为pos处,把下标为pos的数据修改为要插入的数据,此外还增加了一个判断,pos >= 0 和 pos <= ps->sz,pos=0就相当于头插,pos=sz就相当于尾插。

位置删除:

void SLErase(SL* ps, int pos)
{
	assert(pos >= 0 && pos < ps->sz);
	for (int i = pos; i < ps->sz-1; i++)
	{
		ps->data[i] = ps->data[i + 1];
	}
	ps->sz--;
}

         位置删除的原理就是将要删除位置后边的数据向前挪动,将该位置数据覆盖。挪动数据的部分操作,用for循环和while循环都是可以的,但是需要注意访问越界的问题,断言时pos是否合法问题,在插入删除操作中一定要注意。

查找:

int SqLFind(SL* ps, Datatype x) {
	
	for (int i = 0; i < ps->sz; i++)
	{
		if (x == ps->data[i])
			return i;
	}
	return -1;
}

        查找操作也是比较简单的,遍历这个顺序表,如果值相同就返回下标,否则返回-1。

修改:

void SLModify(SL* ps, int pos,Datatype x)
{
	assert(pos >= 0 && pos < ps->sz);
	ps->data[pos] = x;

}

        修改操作也是很简单的,唯一需要注意的点是断言的条件,注意是否越界访问,位置是否合法。全部的接口完成实现,完整代码附下:

#include<stdio.h>
#include<stdlib.h>
#include<assert.h>

#define N 3
typedef int Datatype;
typedef struct SeqList
{
	Datatype* data;
	int sz;//有效数据个数
	int len;//容量
}SL;
void InitSeqList(SL* ps) {
	ps->data = (Datatype*)malloc(sizeof(Datatype) * N);
	if (ps->data == NULL)
	{
		perror("malloc");
		exit(-1);
	}
	ps->len = N;
	ps->sz = 0;
}
void DestorySL(SL* ps)
{
	free(ps->data);
	ps->len = 0;
	ps->sz = 0;
}
void SLCheck(SL* ps)
{
	if (ps->sz == ps->len)
	{
		Datatype* pc = (Datatype*)realloc(ps->data, sizeof(Datatype) * 2 * ps->len);
		if (pc == NULL)
		{
			perror("realloc");
			exit(-1);
		}
		ps->data = pc;
		ps->len *= 2;
	}

}
void PushBackSL(SL* ps, Datatype x)
{
	SLCheck(ps);
	ps->data[ps->sz] = x;
	ps->sz++;
}
void printfSL(SL* ps)
{
	for (int i = 0; i < ps->sz; i++)
	{
		printf("%d ", ps->data[i]);
	}
	printf("\n");
}
void PopBlackSL(SL* ps) {
	if (ps->sz == 0)
	{
		printf("顺序表为空\n");
		return;
	}
	ps->sz--;
}

void PushFrontSL(SL* ps, Datatype x)
{
	SLCheck(ps);
	int end = ps->sz - 1;
	while (end >= 0)
	{
		ps->data[end + 1] = ps->data[end];
		end--;
	}
	ps->data[0] = x;
	ps->sz++;
}
void SListPopFront(SL* ps) {
	for (int i = 0; i < ps->sz - 1; i++)
	{
		ps->data[i] = ps->data[i + 1];
	}
	assert(ps->sz > 0);
	ps->sz--;
}
int SqLFind(SL* ps, Datatype x) {
	for (int i = 0; i < ps->sz; i++)
	{
		if (x == ps->data[i])
			return i;
	}
	return -1;
}
void SLInsert(SL* ps, int pos, Datatype x) {
	assert(pos >= 0 && pos <= ps->sz);
	int end = ps->sz - 1;
	SLCheck(ps);
	while(end>=pos)
	{
		ps->data[end + 1] = ps->data[end];
		end--;
	}
	ps->data[pos] = x;
	ps->sz++;
}
void SLErase(SL* ps, int pos)
{
	assert(pos >= 0 && pos <= ps->sz);
	for (int i = pos; i < ps->sz-1; i++)
	{
		ps->data[i] = ps->data[i + 1];
	}
	ps->sz--;
}
void SLModify(SL* ps, int pos,Datatype x)
{
	assert(pos >= 0 && pos < ps->sz);
	ps->data[pos] = x;

}
int main()
{
	SL s;
	InitSeqList(&s);
	PushBackSL(&s, 1);
	PushBackSL(&s, 2);
	PushBackSL(&s, 3);
	PushBackSL(&s, 4);
	PushBackSL(&s, 5);
	PushBackSL(&s, 6);
	printfSL(&s);        //输出:1 2 3 4 5 6
	SLInsert(&s, 1, 20);
	printf("首次出现的位置下标是%d\n", SqLFind(&s, 6));//6
	printfSL(&s);        //输出:1 20 2 3 4 5 6
	PushFrontSL(&s, 10);
	printfSL(&s);        //输出:10 1 20 2 3 4 5 6
	SListPopFront(&s);
	printfSL(&s);        //输出:1 20 2 3 4 5 6
	SLErase(&s, 1);
	printfSL(&s);        //输出:1 2 3 4 5 6
	return 0;
}

文件分装代码如下:

文件创建:

 SeqList.c

#include"SeqList.h"
void InitSeqList(SL* ps) {
	ps->data = (Datatype*)malloc(sizeof(Datatype) * N);
	if (ps->data == NULL)
	{
		perror("malloc");
		exit(-1);
	}
	ps->len = N;
	ps->sz = 0;
}
void DestorySL(SL* ps)
{
	free(ps->data);
	ps->len = 0;
	ps->sz = 0;
}
void SLCheck(SL* ps)
{
	if (ps->sz == ps->len)
	{
		Datatype* pc = (Datatype*)realloc(ps->data, sizeof(Datatype) * 2 * ps->len);
		if (pc == NULL)
		{
			perror("realloc");
			exit(-1);
		}
		ps->data = pc;
		ps->len *= 2;
	}

}
void PushBackSL(SL* ps, Datatype x)
{
	SLCheck(ps);
	ps->data[ps->sz] = x;
	ps->sz++;
}
void printfSL(SL* ps)
{
	for (int i = 0; i < ps->sz; i++)
	{
		printf("%d ", ps->data[i]);
	}
	printf("\n");
}
void PopBlackSL(SL* ps) {
	if (ps->sz == 0)
	{
		printf("顺序表为空\n");
		return;
	}
	ps->sz--;
}

void PushFrontSL(SL* ps, Datatype x)
{
	SLCheck(ps);
	int end = ps->sz - 1;
	while (end >= 0)
	{
		ps->data[end + 1] = ps->data[end];
		end--;
	}
	ps->data[0] = x;
	ps->sz++;
}
void SListPopFront(SL* ps) {
	for (int i = 0; i < ps->sz - 1; i++)
	{
		ps->data[i] = ps->data[i + 1];
	}
	assert(ps->sz > 0);
	ps->sz--;
}
int SqLFind(SL* ps, Datatype x) {
	for (int i = 0; i < ps->sz; i++)
	{
		if (x == ps->data[i])
			return i;
	}
	return -1;
}
void SLInsert(SL* ps, int pos, Datatype x) {
	assert(pos >= 0 && pos <= ps->sz);
	int end = ps->sz - 1;
	SLCheck(ps);
	while (end >= pos)
	{
		ps->data[end + 1] = ps->data[end];
		end--;
	}
	ps->data[pos] = x;
	ps->sz++;
}
void SLErase(SL* ps, int pos)
{
	assert(pos >= 0 && pos <= ps->sz);
	for (int i = pos; i < ps->sz - 1; i++)
	{
		ps->data[i] = ps->data[i + 1];
	}
	ps->sz--;
}
void SLModify(SL* ps, int pos, Datatype x)
{
	assert(pos >= 0 && pos < ps->sz);
	ps->data[pos] = x;

}

 test.c

#include"SeqList.h"
int main()
{
	SL s;
	InitSeqList(&s);
	PushBackSL(&s, 1);
	PushBackSL(&s, 2);
	PushBackSL(&s, 3);
	PushBackSL(&s, 4);
	PushBackSL(&s, 5);
	PushBackSL(&s, 6);
	printfSL(&s);        //输出:1 2 3 4 5 6
	SLInsert(&s, 1, 20);
	printf("首次出现的位置下标是%d\n", SqLFind(&s, 6));//6
	printfSL(&s);        //输出:1 20 2 3 4 5 6
	PushFrontSL(&s, 10);
	printfSL(&s);        //输出:10 1 20 2 3 4 5 6
	SListPopFront(&s);
	printfSL(&s);        //输出:1 20 2 3 4 5 6
	SLErase(&s, 1);
	printfSL(&s);        //输出:1 2 3 4 5 6
	return 0;
}

 SeqList.h

#include<stdio.h>
#include<stdlib.h>
#include<assert.h>

#define N 3
typedef int Datatype;
typedef struct SeqList
{
	Datatype* data;
	int sz;//有效数据个数
	int len;//容量
}SL;
void InitSeqList(SL* ps);
void DestorySL(SL* ps);
//尾插
void PushBackSL(SL* ps, Datatype x);
//尾删
void PopBlackSL(SL* ps);
void SLCheck(SL* ps);
//头插
void PushFrontSL(SL* ps,Datatype x);
//头删
void SListPopFront(SL* ps);
//位置插入
void SLInsert(SL* ps, int pos, Datatype x);
//位置删除
void SLErase(SL* ps, int pos);
//位置查找
int SqLFind(SL* ps, Datatype x);
//顺序表数据输出
void printfSL(SL* ps);
//数据修改
void SLModify(SL* ps, int pos, Datatype x);

 


总结

        通过深入学习顺序表,我们可以了解它的内部结构和操作,如创建、插入、删除、查找、修改等。这些基本概念为我们理解和学习其他更复杂的数据结构打下了坚实的基础。

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

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

相关文章

ROS前驱前转小车仿真(2D)项目

文章目录 一.官方网址1.ROS官网2.urdf-模型3.rviz-数据可视化4.gazebo-仿真环境5.gmapping-建图6.navigation-导航 二.文件框架三.启动顺序0.依赖包的安装1.手动控制的启动顺序2.建图的启动顺序3.导航的启动顺序 四.urdf-模型文件1.ackermann.xacro-轮子传动的配置2.common_pro…

生信学院|07月28日《企业制造研发一体化解决方案》

课程主题&#xff1a;企业制造研发一体化解决方案 课程时间&#xff1a;2023年07月28日 14:00-14:30 主讲人&#xff1a;周可 生信科技 售前技术顾问 1、企业面临的挑战与痛点 2、达索系统研发制造一体化解决方案 3、DELMIAworks&#xff08;DMW&#xff09;制造运营管理价…

h3c m-lag简单配置案例

#SWA配置 [SWA]m-lag system-mac a08e-80d2-0100 #相同&#xff0c;建议选主设备为系统MAC [SWA]m-lag system-number 1 #主设备为1&#xff0c;备设备为2 [SWA]m-lag system-priority 123 #相同优先级 [SWA]m-lag keepalive ip destination 1.1.1.2 source 1.1.1.1 [SWA]int …

vue echarts实现根据选择项年月时间切换数据显示柱状图,vue页面监听自适应

echarts配置文档参考:Documentation - Apache ECharts 功能:可进行月度、年度切换显示相应的收入和支出柱状图数据; 这里进行了柱状图的简化配置,X轴Y轴都有所改写,具体的简化配置下文会贴出代码,参照功能开发时按照自己的需要去处理; 这里也会提到在开发时会遇到的问题…

两数相加 II——力扣445

题目描述 法一 栈 本题旨在从后往前加&#xff0c;为了逆序处理所有数位&#xff0c;利用栈&#xff0c;把数字压入栈中&#xff0c;再依次取出相加&#xff0c;注意进位&#xff01;进位是/10&#xff0c;另外需要注意栈的常用函数&#xff0c;push()、pop()、top()&#xff0…

我的2023上半年总结

Hi~C站的小伙伴们好久不见哇&#xff01;釉色终于回到C站&#xff0c;开始要输出了&#xff01;这一篇文章是我的2023上半年的总结&#xff0c;以此&#xff0c;致敬那段迷茫但又不曾被辜负的时光。 文章目录 总括——你愿意花五分钟时间读读我的文章吗学习——制定目标&#…

【我们一起60天准备考研算法面试(大全)-第二十六天 26/60】

专注 效率 记忆 预习 笔记 复习 做题 欢迎观看我的博客&#xff0c;如有问题交流&#xff0c;欢迎评论区留言&#xff0c;一定尽快回复&#xff01;&#xff08;大家可以去看我的专栏&#xff0c;是所有文章的目录&#xff09;   文章字体风格&#xff1a; 红色文字表示&#…

图书馆荐书《乡村振兴战略下传统村落文化旅游设计》

图书馆荐书《乡村振兴战略下传统村落文化旅游设计》 书名&#xff1a;乡村振兴战略下传统村落文化旅游设计 索取号&#xff1a;F592.3/47 作者&#xff1a;许少辉 简介&#xff1a;我国传统村落具有宝贵的历史价值、农业价值和生态价值等价值特色&#xff0c;在生动开展基于…

普赛斯携集成电路产教融合解决方案亮相第七届集创赛颁奖典礼并作主旨演讲

第七届全国大学生集成电路创新创业大赛半导体测试分赛区信诺达杯七大赛区选拔赛于2023年7月22日落地武汉理工大学。大赛由工业和信息化部人才交流中心主办&#xff0c;武汉市科技局、武汉市经济和信息化局、武汉东湖高新区大学园科技园有限公司支持。“全国大学生集成电路创新创…

Linux知识点 -- 基础IO(二)

Linux知识点 – 基础IO&#xff08;二&#xff09; 文章目录 Linux知识点 -- 基础IO&#xff08;二&#xff09;一、重定向1.输出重定向2.输入重定向3.追加重定向4.重定向系统调用5.minishell支持重定向6.stdout和stderr的区别7.常规的重定向操作8.perror的实现 二、Linux下一切…

【福利活动】深度体验OpenHarmony对接华为云IoT

本文主要介绍基于OpenHarmony 3.0来接入IoTDA&#xff0c;以BearPi-HM_Nano开发板为例&#xff0c;使用huaweicloud_iot_link SDK对接华为云物联网平台的简单流程。文末为大家提供了的福利&#xff0c;最高可得HUAWEI WATCH FIT手表、华为手环7、HUAWEI FreeBuds SE 无线耳机、…

OSI七层模型——物理层

OSI模型的物理层位于协议栈的底部。它是 TCP/IP 模型的网络接入层的一部分。如果没有物理层&#xff0c;就没有网络。本模块详细介绍了连接到物理层的三种方法。 1 物理层的用途 1.1 物理连接 不管是在家连接本地打印机还是将其连接到另一国家/地区的网站上&#xff0c;在进…

vue 文件扩展名中 esm 、common 、global 以及 mini 、 dev 、prod 、runtime 的含义

vue 文件扩展名中 esm 、common 、global 以及 mini 、 dev 、prod 、runtime 的含义 vue.js 直接用在 script 标签中的完整版本&#xff08;同时包含编译器 compiler 和运行时 runtime&#xff09;&#xff0c;可以看到源码&#xff0c;适用于开发环境。 这个版本视图可以写在…

vue3+ts+elementui-plus二次封装树形表格实现不同层级展开收起的功能

一、TableTreeLevel组件 <template><div classmain><div class"btns"><el-button type"primary" click"expandLevel(1)">展开一级</el-button><el-button type"primary" click"expandLevel(2…

管理类联考——写作——素材篇——论说文——企业管理故事

文章目录 经典管理案例——武装经管知识&#xff0c;让考官刮目相看分槽喂马金蝉脱壳欲取先与窃符救赵尺蠖huo求伸声东击西借尸还魂以静制动釜底抽薪围师必阙撒豆成兵不入虎穴焉得虎子八坛七盖 经典管理案例 ——武装经管知识&#xff0c;让考官刮目相看 纵使是世界顶级的管理…

音视频入门之音频采集、编码、播放

作者&#xff1a;花海blog 今天我们学习音频的采集、编码、生成文件、转码等操作&#xff0c;我们生成三种格式的文件格式&#xff0c;pcm、wav、aac 三种格式&#xff0c;并且我们用 AudioStack 来播放音频&#xff0c;最后我们播放这个音频。 使用 AudioRecord 实现录音生成…

【Chat GPT】用 ChatGPT 运行 Python

前言 ChatGPT 是一个基于 GPT-2 模型的人工智能聊天机器人&#xff0c;它可以进行智能对话&#xff0c;同时还支持 Python 编程语言的运行&#xff0c;可以通过 API 接口进行调用。本文将介绍如何使用 ChatGPT 运行 Python 代码&#xff0c;并提供一个实际代码案例。 ChatGPT …

苹果mac电脑好用的pdf编辑工具PDF Expert 最新中文 v3.2.2

PDF Expert提供了丰富的PDF编辑功能&#xff0c;包括添加、删除、移动、旋转、缩放、裁剪等操作&#xff0c;以及文本、图像、链接、表格、注释等元素的添加和修改。 行云如水&#xff01;阅读PDF文档非常流畅&#xff0c;不管你的文件有多大。编辑PDF文档 以简单快速度编辑PD…

兴达易控 ETHERCAT转PROFIBUS从站网关配置方式

ETHERCAT转PROFIBUS&#xff08;XD-ECPBS20&#xff09;是一款PROFIBUS从站功能的通讯网关。ETHERCAT转PROFIBUS从站网关主要功能是将ETHERCAT设备接入到PROFIBUS网络中。 本网关连接到PROFIBUS总线中做为从站使用&#xff0c;连接到ETHERCAT总线中做为从站使用。 1、配置网关…

基于RWEQ模型的土壤风蚀模数估算及其变化归因分析教程

详情点击公众号链接&#xff1a;基于RWEQ模型的土壤风蚀模数估算及其变化归因分析 前沿 土壤风蚀是一个全球性的环境问题。中国是世界上受土壤风蚀危害最严重的国家之一&#xff0c;土壤风蚀是中国干旱、半干旱及部分湿润地区土地荒漠化的首要过程。中国风蚀荒漠化面积达160…