【数据结构】详细剖析线性表
顺序表与链表的比较
- 导言
- 一、线性表
- 二、线性表的存储结构
- 三、顺序表和链表的相同点
- 四、顺序表与链表之间的差异
- 五、存储结构的选择
- 六、静态顺序表的基本操作
- 七、无头结点单链表的基本操作
- 结语

导言
大家好,很高兴又和大家见面啦!!!
经过这段时间的学习与分享,想必大家跟我一样都已经对线性表的相关内容比较熟悉了。为了更好的巩固线性表相关的知识点,下面我们一起将线性表这个章节的内容梳理一遍吧。
一、线性表
线性表的相关概念
线性表时具有相同数据类型的 n ( n > = 0 ) n(n>=0) n(n>=0)个数据元素的有限序列,其中 n n n为表长,当 n = 0 n=0 n=0时线性表是一个空表。
如果我们以 a i ( 1 < = i < = n ) a_i(1<=i<=n) ai(1<=i<=n)作为线性表的各个元素时,元素 a 1 a_1 a1为线性表唯一的第一个元素,称为表头元素;元素 a n a_n an为线性表唯一的最后一个元素,称为表尾元素。
线性表的逻辑特性是:
- 除了表头元素外,每个元素有且仅有一个直接前驱;
- 除了表尾元素外,每个元素有且仅有一个直接后继。
线性表的特点是:
- 表中元素的个数是有限的;
- 表中元素具有逻辑上的顺序性,表中元素有其先后次序;
- 表中元素都是数据元素,每个元素都是单个元素;
- 表中元素的数据类型都相同,这意味着每个元素所占空间大小相同;
- 表中元素具有抽象性,即仅讨论元素间的逻辑关系,而不考虑元素的内容;
线性表的基本操作:
- 创建与销毁
InitList(&L):初始化表。构造一个空的线性表;DestroyList(&L):销毁操作。销毁线性表,并释放线性表L所占用的内存空间。
- 插入与删除
ListInSERT(&L,i,e):插入操作。在表L中第i个位置插入指定元素e;ListDelete(&L,i,&e):删除操作。删除表L中第i个位置的元素,并用e返回删除元素的值;
- 查找
LocateElem(L,e):按值查找操作。在表L中查找具有给定关键字值的元素;GetElem(L,i):按位查找操作。获取表L中第i个位置的元素的值;
- 其它操作
Length(L):求表长。返回线性表L的长度,即L中数据元素的个数;PrintList(L):输出操作。按前后顺序输出线性表L的所有元素值;Empty(L):判空操作。若L为空表,则返回true,否则返回false;
复习完了线性表的相关知识点,下面我们来看一下线性表的两种存储结构;
二、线性表的存储结构
线性表的各元素在内存中存储时满足在逻辑上相邻,也在物理位置上相邻,这样的存储结构称为顺序存储,又称为顺序表。通常用高级程序设计语言中的数组来表示顺序存储结构。
线性表中的各个元素在内存中存储时满足在逻辑上相邻,在物理位置上不一定相邻,元素与元素之间通过“链”建立起来的逻辑关系,这样的存储结构称为链式存储,又称为链表。
对于顺序表和链表它们又有哪些异同点呢?
三、顺序表和链表的相同点
顺序表和链表的相同点都是建立在它们的本质上面的,下面我们就来看看它们具有哪些相同点:
- 顺序表和链表的元素个数都是有限的;
- 顺序表和链表的元素类型都是相同的;
- 顺序表和链表的元素都满足在逻辑上相邻;
- 顺序表和链表的元素都是数据元素,且每个元素都是单一元素;
- 顺序表和链表的元素都满足只有一个唯一的表头元素和一个唯一的表尾元素;
- 顺序表和链表的逻辑特性都是:
- 除了表头元素外,每个元素都有且仅有一个直接前驱;
- 除了表尾元素外,每个元素都有且仅有一个直接后继;
- 循序表和链表都能进行创建、销毁、增删改查等基本操作;
- 顺序表和链表在金泰
因此,我们可以得到结论:
- 顺序表和链表的本质都是线性表,只不过线性表强调的数据元素在内存上的逻辑结构,而顺序表与链表强调的是数据元素在内存上的存储结构;
介绍完了顺序表与链表的相同点,接下来我们继续来看一看它们的不同点;
四、顺序表与链表之间的差异
- 存取方式不同
- 顺序表是顺序存取结构,同时也是随机存取结构;
- 链表是链式存取结构,同时也是非随机存取结构;
因此,我们想要访问顺序表的各个元素时,只需要知道元素的下标就可以直接查找到,此时的时间复杂度是O(1);而链表想要访问第i个元素时,需要从表头开始进行遍历,此时的时间复杂度是O(n);
- 物理结构不同
- 顺序表的各个元素在物理位置上也是相邻的;
- 链表的各个元素在物理位置上不一定相邻;
因此顺序表在存储时可以做到密集存储,但是需要在内存中消耗一块连续的存储空间;而链表在存储时是离散存储的,但是需要消耗额外的空间来存放指向下一个结点的指针;
- 创建方式不同
- 顺序表在创建时需要明确最大表长、当前表长、数据存放的空间;
- 链表在创建时需要明确数据域和指针域;
- 顺序表在初始化时可以只初始化当前表长;
- 链表在初始化时需要对头结点进行初始化,链表的表长需要通过额外的计数器来确定;
因此顺序表在创建后表的大小是固定的,虽然可以通过malloc、calloc和realloc来申请新的空间达到修改表长的目的,但是在申请完新的空间后还伴随着大量的复制操作,此时的时间复杂度是O(n);而链表在创建时链表的大小是可以随时进行修改的,只需要在插入新结点时修改对应结点的指针域就行,此时的时间复杂度是O(1);
- 查找方式不同
- 顺序表在进行按位查找时,可以直接通过位序查找到对应的元素;
- 链表在进行按位查找时,需要通过从头结点往后进行遍历才能找到对应的元素;
- 顺序表在进行按值查找时,可以通过不同的查找方式进行快速查找;
- 链表在进行按值查找时,需要从头结点开始往后进行顺序查找;
因此顺序表在进行按位查找时的时间复杂度是O(1),在进行按值查找时的最坏时间复杂度为O(n);而链表在进行按位查找与按值查找的时间复杂度都是O(n);
- 插入与删除方式不同
- 顺序表在进行插入与删除时需要移动大量的元素;
- 链表在进行插入与删除时只需要修改对应的指针域;
因此顺序表的插入与删除操作的时间复杂度为O(n);而链表的插入与删除的时间复杂度为O(1);
- 空间分配不同
- 顺序表在进行动态分配时,需要申请一块连续的空间,且空间大小不能修改;
- 链表在进行动态分配时,需要申请对应的结点的空间,空间大小可以随时修改;
- 顺序表在修改表长时,需要移动大量的元素;
- 链表在修改表长时,只需要修改对应结点的指针域;
因此,顺序表在修改表长时对应的时间复杂度为O(n);而链表在修改表长时对应的时间复杂度为O(1);
在了解了顺序表与链表的异同点后,我们又应该如何进行选择呢?
五、存储结构的选择
我们在实际运用中要选择对应的存储结构,就需要结合具体的情况进行分析。从前面的介绍中我们可以看到,顺序表的优势是在查找元素的上面,而链表的优势是在增加、删除上面。因此我们在选择时需要考虑以下几点:
- 存储的考虑
在不确定线性表的长度与存储规模时,宜采用链表;
在确定线性表的表长,且需要密集存储时,宜采用顺序表;
- 运算的考虑
在表长固定的情况下需要经常对表中元素进行按序号访问时,宜采用顺序表;
在表长需要进行增加、删除的操作时,宜采用链表;
- 环境的考虑
在不支持指针的计算机语言中,虽然可以通过静态链表来实现链表,但是顺序表会更加简单一点;
在支持指针的计算机语言中,就需要从存储与运算这两个方面的角度去考虑了。
总之,两种存储结构各有长短,选择哪一种还是得由实际情况来决定。通常较稳定的线性表选择顺从存储;需要平方进行插入、删除操作的线性表选择链式存储。要想更加深刻的理解顺序存储与链式存储之间的优缺点,还是需要熟练的掌握它们才行。
六、静态顺序表的基本操作
在前面我们只介绍了动态顺序表的基本操作,今天我将补上静态顺序表基本操作,其对应的的基本格式如下所示:
//顺序表的静态创建
#define MaxSize 10//定义最大表长
typedef struct Sqlist {ElemType data[MaxSize];//存储数据元素的数组int length;//当前表长
}Sqlist;//重命名后的静态顺序表类型名
//顺序表的初始化
bool InitList(Sqlist* L){if (!L)return false;//指针L为空指针时返回falseL->length = 0;//初始化当前表长return true;
}
//顺序表的按位查找
ElemType GetElem(Sqlist L, int i){if (i<1 || i>L.length)//位序小于1,或者位序大于当前表长时表示位序不合理return -1;//位序不合理,返回-1return L.data[i - 1];//位序合理,返回下标为i-1的元素的值
}
//顺序表的按值查找
int LocateElem(Sqlist L, ElemType e) {for (int i = 0; i < L.length; i++){if (L.data[i] == e)return i + 1;//找到对应的值返回位序i+1}return -1;//没有对应的值返回-1
}
//顺序表的插入
bool ListInsert(Sqlist* L, int i, ElemType e) {if (i<1 || i>L->length + 1)//位序小于1,或者位序大于当前表长+1时表示位序不合理return false;//位序不合理返回falseif (L->length >= MaxSize)return false;//当前线性表已存满,返回falsefor (int j = L->length; j >= i; j--) {L->data[j] = L->data[j - 1];//元素往后移动}L->data[i - 1] = e;//将元素e插入位序i的位置L->length++;//当前表长+1return true;//插入成功返回true
}
//顺序表的删除
bool ListDelete(Sqlist* L, int i, ElemType e) {if (i<1 || i>L->length)//位序小于1,或者位序大于当前表长时位序不合理return false;//位序不合理返回falsee = L->data[i - 1];for (int j = i - 1; j < L->length; j++) {L->data[j] = L->data[j + 1];//元素往前移}L->length--;//当前表长-1return true;//删除成功返回true
}
七、无头结点单链表的基本操作
前面的介绍中,我只介绍了有头结点的单链表与双链表的基本操作,这里给大家补上无头结点的单链表的基本操作,其对应的格式如下所示:
//无头结点单链表的基本操作
//单链表类型的声明
typedef struct LNode {ElemType data;//数据域struct LNode* next;//指针域
}LNode, * LinkList;//重命名后的结点类型与单链表类型名
//单链表的初始化
bool InistList(LinkList* L) {if (!L)return false;//L为空指针时返回falseL= NULL;//头指针初始化为空指针return true;//初始化完返回true
}
//单链表的创建——头插法
LinkList List_HeadInsert(LinkList* L){if (!L)return NULL;//当L为空指针时返回NULLLNode* s = NULL;//指向表头结点的指针ElemType x = 0;//存放数据元素的变量……;//获取数据元素while (x != EOF)//为创建过程设置一个终点{//头插操作if (!(*L))//单链表为空表时{*L = (LNode*)calloc(1, sizeof(LNode));//创建表头结点assert(*L);//创建失败报错(*L)->data = x;//将数据元素放入数据域中(*L)->next = NULL;//表头结点指针域指向空指针}else {s = (LNode*)calloc(1, sizeof(LNode));//创建新结点assert(s);//创建失败报错s->data = x;//数据元素存放进数据域中s->next = (*L)->next;//新结点指针域指向表头结点(*L)->next = s;//头指针指向新结点}……;//获取新的数据元素}return *L;//返回创建好的单链表
}
//单链表的创建——尾插法
LinkList List_TailInsert(LinkList* L) {if (!L)return NULL;//当L为空指针时返回NULLLNode* r = NULL;//指向表尾结点的指针LNode* s = NULL;//指向新结点的指针ElemType x = 0;//存放数据元素的变量……;//获取数据元素while (x != EOF)//为创建过程设置一个终点{//尾插操作if (!(*L))//单链表为空表时{*L = (LNode*)calloc(1, sizeof(LNode));//创建表头结点assert(*L);//创建失败报错(*L)->data = x;//将数据元素放入数据域中(*L)->next = NULL;//表头结点指针域指向空指针r = (*L);//表尾指针指向表头结点,此时的表头结点也是表尾结点}else {s = (LNode*)calloc(1, sizeof(LNode));//创建新结点assert(s);//创建失败报错s->data = x;//数据元素存放进数据域中s->next = r->next;//新结点指针域指向表尾结点r->next = s;//表尾结点的指针域指向新结点r = s;//表尾指针指向新结点}……;//获取新的数据元素}return *L;//返回创建好的单链表
}
//单链表的按位查找
LNode* GetElem(LinkList L, int i) {if (!L)return NULL;//单链表为空表时返回NULLif (i < 1)return NULL;//位序不合理时返回NULLint j = 1;//单链表结点的位序LNode* s = L->next;//指向查找结点的指针while (j < i && s)//当位序相等时,结束查找;当s为空指针时,结束查找{s = s->next;//向后遍历}return s;//查找结束,返回当前结点
}
//单链表的按值查找
LNode* LocateElem(LinkList L, ElemType e) {if (!L)return NULL;//当表为空表时返回NULLLNode* s = L->next;//指向查找结点的指针while (s->data == e && s)//当元素相等时,结束查找,当s为空指针时,结束查找{s = s->next;//向后遍历}return s;//查找结束,返回当前结点
}
//单链表的前插操作——指定结点
bool InsertPriorNode(LNode* p, ElemType e) {if (!p)return false;//p为空指针,返回falseLNode* s = (LNode*)calloc(1, sizeof(LNode));//创建新结点assert(s);//创建失败,报错s->data = p->data;//p结点的数据元素放入新结点的数据域中p->data = e;//插入的数据元素放入p结点的数据域中s->next = p->next;//新结点的指针域指向p结点的后继结点p->next = s;//p结点的指针域指向新结点,完成插入操作return true;//插入成功,返回true
}
//单链表的前插操作——指定位序
bool InsertPriorNode(LinkList* L, int i, ElemType e) {if (!L)return false;//L为空指针时返回falseif (!(*L))return false;//单链表为空表时返回falseif (i < 1)return false;//位序不合理时,返回falseLNode* p = GetElem(*L, i - 1);//指向前驱结点的指针LNode* s = (LNode*)calloc(1, sizeof(LNode));//创建新结点assert(s);//创建失败,报错s->data = e;//数据元素放入新结点的数据域中s->next = p->next;//新结点的指针域指向p结点的后继结点p->next = s;//p结点的指针域指向新结点,完成插入操作return true;//插入成功,返回true
}
//单链表的后插操作——指定结点
bool InsertNextNode(LNode* p, ElemType e) {if (!p)return false;//p为空指针,返回falseLNode* s = (LNode*)calloc(1, sizeof(LNode));//创建新结点assert(s);//创建失败,报错s->data = e;//数据元素放入新结点的数据域中s->next = p->next;//新结点的指针域指向p结点的后继结点p->next = s;//p结点的指针域指向新结点,完成插入操作return true;//插入成功,返回true
}
//单链表的后插操作——指点位序
bool InsertNextNode(LinkList* L, int i, ElemType e) {if (!L)return false;//L为空指针时返回falseif (!(*L))return false;//单链表为空表时返回falseif (i < 1)return false;//位序不合理时,返回falseLNode* p = GetElem(*L, i);//指向位序i结点的指针if (!p)return false;//结点p为空指针时,返回falseLNode* s = (LNode*)calloc(1, sizeof(LNode));//创建新结点assert(s);//创建失败,报错s->data = e;//数据元素放入新结点的数据域中s->next = p->next;//新结点的指针域指向p结点的后继结点p->next = s;//p结点的指针域指向新结点,完成插入操作return true;//插入成功,返回true
}
//单链表的删除操作——指定位序
bool ListDelete(LinkList* L, int i, ElemType e) {if (!L)return false;//L为空指针时返回falseif (!(*L))return false;//单链表为空表时返回falseif (i < 1)return false;//位序不合理时返回falseLNode* p = GetElem(*L, i - 1);//位序i的前驱结点if (!p)return false;//结点p为空指针时,返回falseLNode* q = p->next;//需要删除的结点if (!q)return false;//结点q为空指针时,返回falsee = q->data;//需要删除的元素存放在变量e中p->next = q->next;//前驱结点的指针域指向删除结点的后继结点free(q);//释放被删除的结点空间return true;//删除完成,返回true
}
//单链表的删除操作——指定结点
bool ListDelete(LinkList* L,LNode* p, ElemType e) {if (!L)return false;//L为空指针时返回falseif (!(*L))return false;//单链表为空表时返回falseif (!p)return false;//p为空指针时,返回falseLNode* q = (*L)->next;//指向前驱结点的指针while (q->next != p)//判断q是否为p的前驱结点{q = q->next;//向后遍历}q->next = p->next;//前驱结点指向删除结点的后继结点free(p);//释放删除结点的空间return true;//删除完成,返回true
}
结语
到这里咱们今天的内容就全部介绍完了,线性表的相关知识点也全部介绍完了,希望这些内容能帮助大家更好的学习线性表。
接下来我们将开始进入数据结构——栈、队列和数组的学习,大家记得关注哦!最后,感谢各位的翻阅,咱们下一篇再见!!!
相关文章:
【数据结构】详细剖析线性表
顺序表与链表的比较 导言一、线性表二、线性表的存储结构三、顺序表和链表的相同点四、顺序表与链表之间的差异五、存储结构的选择六、静态顺序表的基本操作七、无头结点单链表的基本操作结语 导言 大家好,很高兴又和大家见面啦!!࿰…...
通过数字证书对PDF电子文件进行数字签名/盖章
以下代码详细说明如何使用数字证书对PDF电子文件进行数字签名/盖章。PDF文件签署主要传递PDF文件,数字证书信息,签章图片3个信息。代码中需要的文件、数字证书、签章图片可访问开放签电子签章开源系统详细了解系统的实现与效果。也可通过gitee开源社区下…...
2007~2016 年税调经纬度及其所处的省市区县乡镇数据
之前给大家分享过一份税调企业经纬度及其所处的省市区县数据: 2007~2016 年税调企业地理信息数据(含经纬度及其所处的省市区县):https://rstata.duanshu.com/#/course/76d38022cd004b09b2aa09647936beb0 最近有培训班的小伙伴提出是否能根据税调企业经纬度来判断其所属的乡…...
SLAM学习入门--编程语言
文章目录 编程语言一、C/C++C 与 C++ 的区别(面向对象的特点)C++ 与 Python的区别判断struct的字节数static 作用Const 作用extern "C"的作用多态如何实现多态?虚函数虚函数怎么实现的?析构函数虚析构函数的作用virtual函数能不能用在构造函数中&#...
Go语言程序设计-第6章--方法
Go语言程序设计-第6章–方法 对象就是简单的一个值或者变量,并且拥有其方法,而方法是某种特定类型的函数。 6.1 方法的声明 方法的声明和普通函数的声明类似,只是在函数名字前面多了一个参数。这个参数把这个方法绑定到这个参数对应的类型…...
AI按理说应该最擅长理工,为啥先冲击文艺行业?
介绍 本人数据AI工程师,我的观点对全行业都有冲击,当AI大模型持续进化之时,没有一家公司能独善其身。 本文从产业架构上、论文体量、基础Pass能力、通用大模型、AI开源社区、业务属性大模型、内容消费工具、创作工具赛道、企业服务这些板块…...
蓝牙物联网移动硬件数据传输系统解决方案
随着传感器技术、网络技术和数据传输技术的不断发展,人们对智能设备的需求日渐增强,利用传感器技术可以对周围环境进行准确和全面的感知,获取到实时信息,从而在网络中进行传输和共享,再通过服务器对各种数据进行保存、分析和挖掘等…...
Linux下Web服务器工作模型及Nginx工作原理详解
文章目录 1. 工作模型概述1.1 阻塞、非阻塞、同步、异步浅析1.2 Web服务器处理并发请求的方式 2. Linux下的I/O模型2.1 常用I/O模型2.2 对比以上模型 3. Nginx工作原理3.1 Nginx基本架构3.2 Nginx代码结构3.3 Nginx工作流程3.4 Nginx缓存机制3.5 Nginx缓存工具:Memc…...
AJAX: 整理2:学习原生的AJAX,这边借助express框架
1. npm install express 终端直接安装 2. 测试案例:Hello World! 新建一个express.js的文件,写入下方的内容 // 1. 引入express const express require(express)// 2. 创建服务器 const app express()// 3.创建路由规则 // request 是对请…...
二、计算机软件及其使用-文字处理软件 Word 2016
Word 2016 的功能;Word 2016 的启动方法和工作窗口 Word 2016 的功能 编辑功能、排版功能、表格处理功能、图形与公式处理功能、文档管理功能 Word 2016 的启动方法 桌面有就单击、任务栏有就单击、开始菜单中单击 Word 2016 的工作窗口 标题栏、功能区、工作区、状…...
Linux LVM逻辑卷
一、LVM的定义 LVM 是 Logical Volume Manager 的简称,译为中文就是逻辑卷管理。它是 Linux 下对硬盘分区的一种管理机制。LVM 适合于管理大存储设备,并允许用户动态调整文件系统的大小。此外,LVM 的快照功能可以帮助我们快速备份数据。LVM 为…...
Hive生产调优介绍
1.Fetch抓取 Fetch抓取是指,Hive中对某些情况的查询可以不必使用MapReduce计算。例如:SELECT * FROM employees;在这种情况下,Hive可以简单地读取employee对应的存储目录下的文件,然后输出查询结果到控制台。 在hive-default.xml…...
如何理解鼠标点击事件在程序中的处理
在计算机用户界面中,鼠标点击是一个常见的交互动作。那么,当你按下鼠标时,程序是如何知道这个点击是否针对它自己的按钮的呢?本文将探讨鼠标点击事件在操作系统和应用程序之间的传递过程。 鼠标点击事件的捕获 当你按下鼠标按钮…...
基于JWT的用户token验证
1. 基于session的用户验证 2. 基于token的用户身份验证 3. jwt jwt代码实现方式 1. 导包 <dependency><groupId>com.auth0</groupId><artifactId>java-jwt</artifactId><version>3.18.2</version> </dependency> 2. 在登录…...
通过 conda 安装 的 detectron2
从 detectron2官网 发现预编译的版本最高支持 pytorch1.10、cuda11.3。(2023-12-26) 1、安装 conda 环境。 conda create --name detectron2 python3.8 2、安装 pytorch1.10 和 cuda11.3。 pip3 install torch1.10.0cu113 torchvision0.11.1cu113 torc…...
嵌入式开发——SPI OLED屏幕案例
学习目标 掌握移植方法掌握调试方式学习内容 需求 官方测试示例 选择对应的平台 测试示例中,找到芯片对应平台,我们选择的是STM32F407 修改例程 已知错误修改:...
ibm上电时序(视频内容)
...
如何在Vue.js中使用$emit进行组件通信
Vue.js是一个渐进式JavaScript框架,它以其简洁的数据绑定和组件系统而闻名。在构建具有多个组件层次的Vue应用时,组件间的通信成为一个关键的话题。Vue提供了一种名为$emit的方法,允许子组件向父组件发送消息。本文将详细介绍如何在Vue中使用…...
SPSS相关统计学知识精要回顾-大家都来做做
很多学生问我,学SPSS如果想深入学,那么统计学原理应该掌握到什么样的水准,我想说的是,如果真的想融会贯通,而不是短暂过关,那么应该具备一定的统计学基础,但是统计学知识也不是面面俱到都要去学…...
React Native 从类组件到函数组件
1. 发展趋势 React Native社区中的趋势是朝向使用函数组件(Functional Components)和Hooks的方向发展,而不是使用类组件(Class Components)。 React Native自推出Hooks API以来,函数组件和Hooks的使用变得…...
Leetcode 3576. Transform Array to All Equal Elements
Leetcode 3576. Transform Array to All Equal Elements 1. 解题思路2. 代码实现 题目链接:3576. Transform Array to All Equal Elements 1. 解题思路 这一题思路上就是分别考察一下是否能将其转化为全1或者全-1数组即可。 至于每一种情况是否可以达到…...
黑马Mybatis
Mybatis 表现层:页面展示 业务层:逻辑处理 持久层:持久数据化保存 在这里插入图片描述 Mybatis快速入门 。漏洞扫描服务市场行业预计将从 2024 年的 3.48(十亿美元)增长到 2032 年的 9.54(十亿美元)。预测期内漏洞扫描服务市场 CAGR(增长率&…...
【项目实战】通过多模态+LangGraph实现PPT生成助手
PPT自动生成系统 基于LangGraph的PPT自动生成系统,可以将Markdown文档自动转换为PPT演示文稿。 功能特点 Markdown解析:自动解析Markdown文档结构PPT模板分析:分析PPT模板的布局和风格智能布局决策:匹配内容与合适的PPT布局自动…...
vue3+vite项目中使用.env文件环境变量方法
vue3vite项目中使用.env文件环境变量方法 .env文件作用命名规则常用的配置项示例使用方法注意事项在vite.config.js文件中读取环境变量方法 .env文件作用 .env 文件用于定义环境变量,这些变量可以在项目中通过 import.meta.env 进行访问。Vite 会自动加载这些环境变…...
【HarmonyOS 5 开发速记】如何获取用户信息(头像/昵称/手机号)
1.获取 authorizationCode: 2.利用 authorizationCode 获取 accessToken:文档中心 3.获取手机:文档中心 4.获取昵称头像:文档中心 首先创建 request 若要获取手机号,scope必填 phone,permissions 必填 …...
蓝桥杯 冶炼金属
原题目链接 🔧 冶炼金属转换率推测题解 📜 原题描述 小蓝有一个神奇的炉子用于将普通金属 O O O 冶炼成为一种特殊金属 X X X。这个炉子有一个属性叫转换率 V V V,是一个正整数,表示每 V V V 个普通金属 O O O 可以冶炼出 …...
HarmonyOS运动开发:如何用mpchart绘制运动配速图表
##鸿蒙核心技术##运动开发##Sensor Service Kit(传感器服务)# 前言 在运动类应用中,运动数据的可视化是提升用户体验的重要环节。通过直观的图表展示运动过程中的关键数据,如配速、距离、卡路里消耗等,用户可以更清晰…...
Spring是如何解决Bean的循环依赖:三级缓存机制
1、什么是 Bean 的循环依赖 在 Spring框架中,Bean 的循环依赖是指多个 Bean 之间互相持有对方引用,形成闭环依赖关系的现象。 多个 Bean 的依赖关系构成环形链路,例如: 双向依赖:Bean A 依赖 Bean B,同时 Bean B 也依赖 Bean A(A↔B)。链条循环: Bean A → Bean…...
AirSim/Cosys-AirSim 游戏开发(四)外部固定位置监控相机
这个博客介绍了如何通过 settings.json 文件添加一个无人机外的 固定位置监控相机,因为在使用过程中发现 Airsim 对外部监控相机的描述模糊,而 Cosys-Airsim 在官方文档中没有提供外部监控相机设置,最后在源码示例中找到了,所以感…...
