数据结构顺序表和链表(超详细)
线性表:

顺序表
概念及结构
静态顺序表:使用定长数组存储元素。
动态顺序表:使用动态开辟的数组存储。
如果将一开始动态开辟的内存填满,则会进行扩容,
扩容分两种情况:
原地扩容:在已开辟的动态内存后进行判断,如果后方内存大小足够扩容到新定义的大小,则在之前开辟的内存后面加上一段,以达到新定义内存大小;
异地扩容:如果在已开辟的动态内存后进行判断,后方的大小不足以扩容到新定义的大小,则会在内存中寻找一块新的足够容纳新定义大小的空间,并将之前的数据拷贝到新空间,再释放之前定义的动态内存空间;
接口实现
typedef int SLDateType;
typedef struct SeqList
{
SLDateType* a;//动态开辟的数组
int size; //数据个数
int capacity;//容量空间大小
}SL;
//初始化
void SLInit(SL* ps);//释放或销毁
void SLDestroy(SL* ps);//显示或打印
void SLPrintf(SL* ps);//尾插
void SLPushBack(SL* ps, SLDateType x);
//尾删
void SLPopBack(SL* ps);
//头插
void SLPushFront(SL* ps, SLDateType x);
//头删
void SLPopFront(SL* ps);//扩容
void SLCheckDestroy(SL* ps);//顺序表查找
int SLFind(SL* ps,int n);// 顺序表在pos位置插入x
void SLInsert(SL* ps, int pos, SLDateType x);// 顺序表删除pos位置的值
void SLErase(SL* ps, int pos);//顺序表修改
void SLModify(SL* ps,int pos,SLDateType x);
#define _CRT_SECURE_NO_WARNINGS 1
#include "Sequence.h"
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
//初始化
void SLInit(SL* ps)
{
ps->a = (SLDateType*)malloc(sizeof(SLDateType*)*4);
if (ps->a == NULL)
{
perror("malloc failed");
exit(-1);
}
ps->size = 0;
ps->capacity = 4;
}
//释放或销毁
void SLDestroy(SL* ps)
{
free(ps->a);
ps->a = NULL;
ps->capacity = ps->size = 0;
}
//显示或打印
void SLPrintf(SL* ps)
{
int i = 0;
for (i = 0; i < ps->size; i++)
{
printf("%d ", ps->a[i]);
}
printf("\n");
}//扩容
void SLCheckDestroy(SL* ps)
{
if (ps->size == ps->capacity)
{
SLDateType* tmp = (SLDateType*)realloc(ps->a, sizeof(SLDateType) * 2 * ps->capacity);
if (tmp == NULL)
{
perror("realloc failed");
exit(-1);
}
ps->a = tmp;
ps->capacity *= 2;
}
}
//尾插void SLPushBack(SL* ps, SLDateType x)
{
SLCheckDestroy(ps);//ps->a[ps->size] = x;
//ps->size++;SLInsert(ps,ps->size,x);
}//尾删
void SLPopBack(SL* ps)
{
assert(ps);
//温柔型
//if (ps->size == 0)
//{
// return;
//}
//暴力型
//assert(ps->size > 0);//ps->size--;
SLErase(ps, ps->size - 1);
}
//头插void SLPushFront(SL* ps, SLDateType x)
{
assert(ps);
SLCheckDestroy(ps);
//int i = 0;
//for (i = 0; i < ps->size ; i++)
//{
// ps->a[ps->size-i] = ps->a[ps->size - i -1];
//}
//ps->a[0] = x;
//ps->size++;
SLInsert(ps, 0, x);
}//头删
void SLPopFront(SL* ps)
{
//防止越界
assert(ps->size > 0);//int i = 0;
//for (i = 0; i < ps->size - 1; i++)
//{
// ps->a[i] = ps->a[i+1];
//}
//ps->size--;SLErase(ps, 0);
}//查找
int SLFind(SL* ps, int n)
{
int i = 0;
for (i = 0; i < ps->size; i++)
{
if (ps->a[i] == n)
{
return i;
}
}
return -1;
}
// 顺序表在pos位置插入xvoid SLInsert(SL* ps, int pos, SLDateType x)
{
assert(ps);
//=0相当于头插,=size等于尾插
assert(pos >= 0 && pos <= ps->size);SLCheckDestroy(ps);
int start = ps->size - 1 ;
while (start >= pos)
{
ps->a[start + 1] = ps->a[start];
start--;
}
ps->a[pos] = x;
ps->size++;
}
// 顺序表删除pos位置的值void SLErase(SL* ps, int pos)
{
assert(ps);assert(pos >= 0 && pos < ps->size);
int begin = pos + 1;
while (begin < ps->size)
{
ps->a[begin - 1] = ps->a[begin];
begin++;
}
ps->size--;
}//顺序表修改
void SLModify(SL* ps, int pos, SLDateType x)
{
assert(ps);
assert(pos >= 0 && pos < ps->size);ps->a[pos];
}
值得注意的是:
如果没有使用温柔型或者暴力型判断,可能会发生数组越界,但是一般情况下,编译器不会报错,因为编译器只在数组两天的特定位置放置了越界标记,需要触发才会报错,触发一般是在编译结束时到数组越界标记访问,此时越界了,但没有在此处赋值,也不会报错。
顺序表总结:
缺点:
1.头部和中部插入和删除效率不高O(n);
2.空间不足时,扩容有一定的消耗(尤其是异地扩容)如:开辟空间,拷贝,释放旧空间;
3.扩容逻辑,可能存在空间浪费(200个,但是只用110个)。
优点:
1.尾插尾删足够快;
2.下标的随机访问和修改。
链表
链表的概念及结构:
特点:按需申请释放
逻辑上分析链表如图:
值得注意:
1.上图,链式结构在逻辑上是连续的,在物理上不一定是连续的;
2.现实中的结点一般是在堆上申请;
3.堆上申请的空间,可能连续,也可能不连续。
物理上分析链表如下:
1.单向链表的实现:
// 1 、无头 + 单向 + 非循环链表增删查改实现typedef int SLTDateType ;typedef struct SListNode{SLTDateType data ;struct SListNode * next ;} SListNode ;// 动态申请一个结点SListNode * BuySListNode ( SLTDateType x );// 单链表打印void SListPrint ( SListNode * plist );// 单链表尾插void SListPushBack ( SListNode ** pplist , SLTDateType x );// 单链表的头插void SListPushFront ( SListNode ** pplist , SLTDateType x );// 单链表的尾删void SListPopBack ( SListNode ** pplist );// 单链表头删void SListPopFront ( SListNode ** pplist );// 单链表查找SListNode * SListFind ( SListNode * plist , SLTDateType x );// 单链表在 pos 位置之后插入 x// 分析思考为什么不在 pos位置之前插入?void SListInsertAfter ( SListNode * pos , SLTDateType x );// 单链表删除 pos 位置之后的值// 分析思考为什么不删除 pos 位置?void SListEraseAfter ( SListNode * pos );//销毁
void SListDestory ( SListNode** phead );
// 动态申请一个结点
SListNode* BuySListNode(SLDataType x)
{SListNode* newnode = (SListNode*)malloc(sizeof(SListNode));if (newnode == NULL){perror("malloc fail");exit(-1);}newnode->data = x;newnode->next = NULL;return newnode;
}
// 单链表打印
void SListPrint(SListNode* phead)
{SListNode* cur = phead;while (cur != NULL){printf("%d->", cur->data);cur = cur->next;}printf("NULL\n");
}
特别需要注意的是
上面两张图中,图一说明改变成员,要用成员的指针,
图二说明改变成员的指针,要用成员的指针的指针(二级指针)
// 单链表尾插
void SListPushBack(SListNode** phead, SLDataType x)
{assert(phead);SListNode* newnode = BuySListNode(x);if (*phead == NULL){// 改变的结构体的指针,所以要用二级指针*phead = newnode;}else{SListNode* tail = *phead;while (tail->next != NULL){tail = tail->next;}// 改变的结构体,用结构体的指针即可tail->next = newnode;}}
// 单链表的头插
void SListPushFront(SListNode** phead, SLDataType x)
{assert(phead);SListNode* newnode = BuySListNode(x);newnode->next = *phead;*phead = newnode;
}
// 单链表的尾删
void SListPopBack(SListNode** phead)
{assert(phead);//0个assert(*phead);//1个或以上if ((*phead)->next == NULL){free(*phead);*phead = NULL;}else{SListNode* tail = *phead;while (tail->next->next){tail = tail->next;}free(tail->next);tail->next = NULL;}
}
// 单链表头删
void SListPopFront(SListNode** phead)
{assert(phead);assert(*phead);SListNode* newnode = (*phead)->next;free(*phead);*phead = newnode;
}
//查找
SListNode* SListFind(SListNode* phead, SLDataType x)
{SListNode* newnode = phead;while (newnode){if (newnode->data == x){return newnode;}newnode = newnode->next;}return NULL;
}
//在pos之后插入x
void SListInsertAfter(SListNode* pos, SLDataType x)
{assert(pos);SListNode* newnode = BuySListNode(x);newnode->next = pos->next;pos->next = newnode;}
//在pos之前插x
void SLTInsert(SListNode** phead, SListNode* pos, SLDataType x)
{assert(pos);//方法一if (pos == *phead){SListPushFront(phead, x);}else{SListNode* tail = *phead;while (tail->next != pos){tail = tail->next;}SListNode* newnode = BuySListNode(x);tail->next = newnode;newnode->next = pos;}//方法二//SListNode* tail = *phead;//while (newnode->next == NULL)//{ // if (*phead == pos)// {// newnode->next = tail;// *phead = newnode;// }// if (tail->next == pos)// {// newnode->next = tail->next;// tail->next = newnode;// }// else// {// tail = tail->next;// }//}
}
// 删除pos位置
void SLTErase(SListNode** phead, SListNode* pos)
{assert(phead);assert(pos);SListNode* tail = *phead;if (*phead == pos){SListPopFront(phead);//*phead = pos->next;//return;}while (tail->next != pos->next){if (tail->next == pos){tail->next = tail->next->next;}else{tail = tail->next;}}free(pos);//pos = NULL;//形参不改变实参,在调用外面置空
}
// 删除pos的后一个位置
void SLTEraseAfter(SListNode* pos)
{assert(pos);assert(pos->next);//如果pos没有下一个,报错SListNode* postNext = pos->next;pos->next = pos->next->next;free(postNext);postNext = NULL;
}
//销毁
void SListDestory(SListNode** phead)
{assert(phead);SListNode* cur = *phead;while (cur){SListNode* node = cur->next;free(cur);cur = node;}*phead = NULL;
}
替换发删除:
将下一个节点的值给pos,然后删除pos->next的节点。
2.双向链表的实现:
// 2 、带头 + 双向 + 循环链表增删查改实现typedef int LTDataType ;typedef struct ListNode{LTDataType _data ;struct ListNode * next ;struct ListNode * prev ;} ListNode ;// 创建返回链表的头结点 .ListNode * ListCreate ();// 双向链表销毁void ListDestory ( ListNode * plist );// 双向链表打印void ListPrint ( ListNode * plist );// 双向链表尾插void ListPushBack ( ListNode * plist , LTDataType x );// 双向链表尾删void ListPopBack ( ListNode * plist );// 双向链表头插void ListPushFront ( ListNode * plist , LTDataType x );// 双向链表头删void ListPopFront ( ListNode * plist );// 双向链表查找ListNode * ListFind ( ListNode * plist , LTDataType x );// 双向链表在 pos 的前面进行插入void ListInsert ( ListNode * pos , LTDataType x );// 双向链表删除 pos 位置的结点void ListErase ( ListNode * pos );
// 创建返回链表的头结点
ListNode* BuyLTNode(LTDataType x)
{ListNode* node = (ListNode*)malloc(sizeof(ListNode));if (node == NULL){perror("malloc fail");exit(-1);}node->data = x;node->next = NULL;node->prev = NULL;return node;
}// 创建返回链表的头结点.
ListNode* ListCreate()
{ListNode* head = BuyLTNode(0);head->next = head;head->prev = head;return head;
}
// 双向链表打印
// 双向链表打印
void ListPrint(ListNode* pHead)
{assert(pHead);ListNode* node = pHead->next;while (node != pHead){printf("%d->",node->data);node = node->next;}printf("NULL\n");
}
// 双向链表在pos的前面进行插入
// 双向链表在pos的前面进行插入
void ListInsert(ListNode* pos, LTDataType x)
{assert(pos);ListNode* newnode = BuyLTNode(x);ListNode* oldnode = pos->prev;newnode->prev = oldnode;oldnode->next = newnode;newnode->next = pos;pos->prev = newnode;}
// 双向链表删除pos位置的节点
// 双向链表删除pos位置的节点
void ListErase(ListNode* pos)
{assert(pos);ListNode* oldnode = pos->prev;oldnode->next = pos->next;pos->next->prev = oldnode;free(pos);
}
// 双向链表尾插
// 双向链表尾插
void ListPushBack(ListNode* pHead, LTDataType x)
{assert(pHead);ListInsert(pHead,x);
}
// 双向链表头插
// 双向链表头插
void ListPushFront(ListNode* pHead, LTDataType x)
{assert(pHead);ListInsert(pHead->next,x);
}
// 双向链表尾删
// 双向链表尾删
void ListPopBack(ListNode* pHead)
{assert(pHead);//assert(pHead->next != pHead);ListErase(pHead->prev);
}
// 双向链表头删
// 双向链表头删
void ListPopFront(ListNode* pHead)
{assert(pHead);//assert(pHead->next != pHead);ListErase(pHead->next);
}
// 双向链表查找
// 双向链表查找
ListNode* ListFind(ListNode* pHead, LTDataType x)
{assert(pHead);ListNode* node = pHead->next;while(node != pHead){if (node->data == x){return node;}node = node->next;}return NULL;
}
// 双向链表销毁
// 双向链表销毁
void ListDestory(ListNode* pHead)
{assert(pHead);ListNode* oldnode = pHead->next;while (oldnode != pHead){ListNode* oldnode1 = oldnode->next;free(oldnode);oldnode = oldnode1;}free(pHead);printf("销毁完成!\n");
}
链表和顺序表的区别:
缓存利用率:
以上就是个人学习线性表的个人见解和学习的解析,欢迎各位大佬在评论区探讨!
感谢大佬们的一键三连! 感谢大佬们的一键三连! 感谢大佬们的一键三连!
相关文章:

数据结构顺序表和链表(超详细)
线性表: 线性表 ( linear list ) 是 n 个具有相同特性的数据元素的有限序列。 线性表是一种在实际中广泛使 用的数据结构,常见的线性表:顺序表、链表、栈、队列、字符串 ... 线性表在逻辑上是线性结构,也就…...
free 查看 buff/cache 很大,处理方法
如果 free 命令输出中的 buff/cache 很大,这意味着系统将一部分内存用于缓存文件系统的数据。这是正常的行为,因为缓存可以提高文件访问的速度。然而,如果需要释放缓存来腾出内存空间,可以尝试以下方法: 清理 PageCach…...

【Quarkus技术系列】「云原生架构体系」在云原生时代下的Java“拯救者”是Quarkus,那云原生是什么呢?
云原生时代下的Java"拯救者" 在云原生时代,其实Java程序是有很大的劣势的,以最流行的spring boot/spring cloud微服务框架为例,启动一个已经优化好,很多bean需要lazy load的application至少需要3-4秒时间,内…...
DHCP的工作原理
DHCP是一种网络管理协议,全称为动态主机配置协议(Dynamic Host Configuration Protocol)。它是一种基于TCP/IP协议的网络服务,允许网络管理员集中管理和分配IP地址和其他网络配置参数,以便客户端设备能够使用这些参数与…...
display:flex;兼容浏览器写法
通过在 display 属性中使用这些不同的值,可以确保在各种浏览器中都能正确显示 flex 布局。 需要注意的是,这只是一个示例,实际使用时可能还需要考虑其他兼容性问题,并根据具体情况进行调整。如果你需要更全面的兼容性解决方案&am…...
三、python Django ORM postgresql[数据定时备份、数据恢复]
一、数据定时备份 解释:备份指定数据库,能有效在发生错误时,预防错误,进行恢复 1.基本备份 #!/bin/bash sudo -u postgres pg_dump -U postgres -d dbname -Fc > /home/postgres/backup/backup.dump # sudo -u postgres&…...

c++字符串函数
在 C 中有大量用于操作 C-style 字符串的函数,它们集成在头文件 <cstring> 中。其常见的函 函数作用strcpy(s1,s2) 复制字符串 s2 到 s1strcat(s1,s2) 将字符串 s2 连接到 s1 末尾strlen(s) 计算字符串 s 长度strcmp(s1,s2) 比较字符串 s1 和 s2 …...
使用OkHttp发送POST请求的几种方式
使用OkHttp发送POST请求的几种方式 介绍pom依赖基本的POST请求带授权的POST请求POST方式发送JSON数据Multipart POST 请求 介绍 本文将介绍 OkHttp 客户端的基本用法。 主要介绍 OkHttp 3.x 版本中发送Post请求的几种方式。 pom依赖 <dependency><groupId>com.sq…...

时序预测 | MATLAB实现EEMD-GRU、GRU集合经验模态分解结合门控循环单元时间序列预测对比
时序预测 | MATLAB实现EEMD-GRU、GRU集合经验模态分解结合门控循环单元时间序列预测对比 目录 时序预测 | MATLAB实现EEMD-GRU、GRU集合经验模态分解结合门控循环单元时间序列预测对比效果一览基本介绍模型搭建程序设计参考资料 效果一览 基本介绍 1.MATLAB实现EEMD-GRU、GRU时…...

学习笔记整理-JS-04-流程控制语句
文章目录 一、条件语句1. if语句的基本使用2. if else if多条件分支3. if语句算法题4. switch语句5. 三元运算符 二、循环语句1. for循环语句2. for循环算法题3. while循环语句4. break和continue5. do while语句 三、初识算法1. 什么是算法2. 累加器和累乘器3. 穷举法4. 综合算…...

stable-diffusion-webui 界面汉化
本教程通过安装 sd-webui-bilingual-localization 插件来达到汉化目的, 项目地址为:https://github.com/journey-ad/sd-webui-bilingual-localization 一、安装插件 先进入插件安装界面 在搜索栏搜索 zh_CN Localization 中文语言包, 项目地址: https://github.com/dtlnor/st…...

问道管理:信创概念走势活跃,恒银科技斩获四连板
信创概念9日盘中走势活泼,截至发稿,新晨科技、竞业达、恒银科技等涨停,宇信科技涨近10%,中孚信息涨近9%,华是科技、神州数码涨超7%。 新晨科技今天“20cm”涨停,公司昨日晚间公告,近来收到投标代…...

centos 7镜像(iso)下载图文教程(超详细)
声明:本教程为本人学习笔记,仅供参考 文章目录 前言一、阿里云镜像站下载centos 7 二、清华源下载centos 7小结 前言 声明:本教程为本人学习笔记,仅供参考 本教程将提供两种方式下载centos 7 系统镜像 1、阿里巴巴开源镜像站 2、…...
使用Druid,以jdbc方式配置多数据源
文章目录 背景示例代码(结合实际进行配置)总结 背景 当使用Spring Boot项目并需要多数据源时,你可以使用Druid连接池来配置和管理多个数据源。以下是一个示例的配置和代码,以说明如何实现多数据源: 示例代码…...

RabbitMQ基础(2)——发布订阅/fanout模式 topic模式 rabbitmq回调确认 延迟队列(死信)设计
目录 引出点对点(simple)Work queues 一对多发布订阅/fanout模式以登陆验证码为例pom文件导包application.yml文件rabbitmq的配置生产者生成验证码,发送给交换机消费者消费验证码 topic模式配置类增加配置生产者发送信息进行发送控制台查看 rabbitmq回调确认配置类验…...
2. VisionOS平台概述
Unity 对VisionOS的支持将 Unity 编辑器和运行时引擎的全部功能与RealityKit提供的渲染功能结合起来。Unity 的核心功能(包括脚本、物理、动画混合、AI、场景管理等)无需修改即可支持。这允许游戏和应用程序逻辑像任何其他 Unity 支持的平台一样在Vision…...

MySql存储过程详解
文章目录 存储过程1 介绍 基本语法创建:调用查看删除演示: 变量相关系统变量演示: 用户自定义变量局部变量 if语法参数介绍casewhilerepeatloop游标条件处理程序存储函数 存储过程 1 介绍 存储过程是事先经过编译并存储在数据库中的一段 SQL 语句的集合,调用存储过…...
CRM 系统实施风险分析
企业实施 CRM 系统将引起各个方面的巨大变化, CRM 系统实施项目中,有不 少成功的案例,也存在相当的风险,企业只有增强风险意识并积极防范,才有可能提高 CRM 实施成功的概率。 1.企业内部环境带来的风险 (…...

保持城市天际线(力扣)贪心 JAVA
给你一座由 n x n 个街区组成的城市,每个街区都包含一座立方体建筑。给你一个下标从 0 开始的 n x n 整数矩阵 grid ,其中 grid[r][c] 表示坐落于 r 行 c 列的建筑物的 高度 。 城市的 天际线 是从远处观察城市时,所有建筑物形成的外部轮廓。…...

电路综合原理与实践---T衰减与PI衰减的详细计算理论与设计仿真
电路综合原理与实践—T衰减与PI衰减的详细计算理论与设计仿真 最近要找工作在刷笔试题目,会刷到关于T衰减的理论计算问题,一直搞不明白怎么算的,搞明白之后给大家伙来分享一下。 基础理论可以参考:电阻衰减网络计算(P…...

Vue3 + Element Plus + TypeScript中el-transfer穿梭框组件使用详解及示例
使用详解 Element Plus 的 el-transfer 组件是一个强大的穿梭框组件,常用于在两个集合之间进行数据转移,如权限分配、数据选择等场景。下面我将详细介绍其用法并提供一个完整示例。 核心特性与用法 基本属性 v-model:绑定右侧列表的值&…...

8k长序列建模,蛋白质语言模型Prot42仅利用目标蛋白序列即可生成高亲和力结合剂
蛋白质结合剂(如抗体、抑制肽)在疾病诊断、成像分析及靶向药物递送等关键场景中发挥着不可替代的作用。传统上,高特异性蛋白质结合剂的开发高度依赖噬菌体展示、定向进化等实验技术,但这类方法普遍面临资源消耗巨大、研发周期冗长…...
java 实现excel文件转pdf | 无水印 | 无限制
文章目录 目录 文章目录 前言 1.项目远程仓库配置 2.pom文件引入相关依赖 3.代码破解 二、Excel转PDF 1.代码实现 2.Aspose.License.xml 授权文件 总结 前言 java处理excel转pdf一直没找到什么好用的免费jar包工具,自己手写的难度,恐怕高级程序员花费一年的事件,也…...

使用分级同态加密防御梯度泄漏
抽象 联邦学习 (FL) 支持跨分布式客户端进行协作模型训练,而无需共享原始数据,这使其成为在互联和自动驾驶汽车 (CAV) 等领域保护隐私的机器学习的一种很有前途的方法。然而,最近的研究表明&…...
linux 下常用变更-8
1、删除普通用户 查询用户初始UID和GIDls -l /home/ ###家目录中查看UID cat /etc/group ###此文件查看GID删除用户1.编辑文件 /etc/passwd 找到对应的行,YW343:x:0:0::/home/YW343:/bin/bash 2.将标红的位置修改为用户对应初始UID和GID: YW3…...
【HarmonyOS 5 开发速记】如何获取用户信息(头像/昵称/手机号)
1.获取 authorizationCode: 2.利用 authorizationCode 获取 accessToken:文档中心 3.获取手机:文档中心 4.获取昵称头像:文档中心 首先创建 request 若要获取手机号,scope必填 phone,permissions 必填 …...
力扣-35.搜索插入位置
题目描述 给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。 请必须使用时间复杂度为 O(log n) 的算法。 class Solution {public int searchInsert(int[] nums, …...
BLEU评分:机器翻译质量评估的黄金标准
BLEU评分:机器翻译质量评估的黄金标准 1. 引言 在自然语言处理(NLP)领域,衡量一个机器翻译模型的性能至关重要。BLEU (Bilingual Evaluation Understudy) 作为一种自动化评估指标,自2002年由IBM的Kishore Papineni等人提出以来,…...
Bean 作用域有哪些?如何答出技术深度?
导语: Spring 面试绕不开 Bean 的作用域问题,这是面试官考察候选人对 Spring 框架理解深度的常见方式。本文将围绕“Spring 中的 Bean 作用域”展开,结合典型面试题及实战场景,帮你厘清重点,打破模板式回答,…...
在树莓派上添加音频输入设备的几种方法
在树莓派上添加音频输入设备可以通过以下步骤完成,具体方法取决于设备类型(如USB麦克风、3.5mm接口麦克风或HDMI音频输入)。以下是详细指南: 1. 连接音频输入设备 USB麦克风/声卡:直接插入树莓派的USB接口。3.5mm麦克…...