【数据结构】顺序表实现

0. 前言

小伙伴们大家好,从今天开始,我们就开始学习《数据结构》这门课程~

首先想给大家讲讲什么是数据结构?

0.1 数据结构是什么?

数据结构是由“数据”“结构”两词组合⽽来。

什么是数据?

比如常⻅的数值1、2、3、4..... ;平时我们学校教务系统⾥保存的用户信息(姓名、性别、年龄、学历等等)凡是我们在网页在肉眼可以看到的信息(⽂字、图⽚、视频等等),这些都是数据。

那何为结构呢?

当我们想要使⽤⼤量使⽤同⼀类型的数据时,通过⼿动定义⼤量的独⽴的变量对于程序来说,可读性⾮常差,我们可以借助数组这样的数据结构将⼤量的数据组织在⼀起,结构也可以理解为组织数据的⽅式。

就好像:

在草原上,想找到名叫“咩咩”的⽺很难,

但是如果我们从⽺圈⾥找到1号⽺就很简单,⽺圈这样的结构有效将⽺群组织起来。

概念:

数据结构是计算机存储、组织数据的⽅式。数据结构是指相互之间存在⼀种或多种特定关系的数据元素的集合。数据结构反映数据的内部构成,即数据由那部分构成,以什么⽅式构成,以及数据元素之间呈现的结构。

总结:

1)能够存储数据(如顺序表、链表等结构)

2)存储的数据能够⽅便查找

0.2 为什么需要数据结构? 

如图中所⽰,我们生活中无论去公共场所,或者在火车站买票等等场景,我们都需要排队。

如果不借助排队的⽅式来管理客户,会导致客户感受差、等待时间⻓等情况。

同理,程序中如果不对数据进⾏管理,可能会导致数据丢失、操作数据困难、野指针等情况。

通过数据结构,能够有效将数据组织和管理在⼀起。按照我们的⽅式任意对数据进⾏

增删改查等操作。

最基础的数据结构:数组。

我们思考一下,有了数组,为什么还要我们学习其他的数据结构呢?

比如你遇到这样一个问题:

假定数组有10个空间,已经使⽤了5个,向数组中插⼊数据步骤:

求数组的⻓度,求数组的有效数据个数,向下标为数据有效个数的位置插⼊数据(注意:这⾥是否要判断数组是否满了,满了还能继续插⼊吗).....

假设数据量⾮常庞⼤,频繁的获取数组有效数据个数会影响程序执⾏效率。

结论:最基础的数据结构能够提供的操作已经不能完全满⾜复杂算法实现。

🌟🌟有什么办法可以完成数组完不成的任务呢?

这就是我们要学习的第一个数据结构——顺序表 

1、顺序表的概念及结构

1.1 线性表

线性表(linear list)n个具有相同特性的数据元素的有限序列

线性表是⼀种在实际中⼴泛使⽤的数据结构,常⻅的线性表:顺序表、链表、栈、队列、字符串...

线性表在逻辑上是线性结构,也就说是连续的⼀条直线但是在物理结构上并不⼀定是连续的,

线性表在物理上存储时,通常以数组和链式结构的形式存储。

2、顺序表分类

2.1 顺序表和数组的区别:

顺序表实质上就是对数组的封装,完成了对数组的增删改查的操作。

下面有一张图,可以帮助大家理解他俩的关系哦:

我们可以把数组和顺序表想象成两家餐厅,

一家是苍蝇馆子这样的普通餐厅,一家是米其林餐厅这样高档的五星级餐厅。

在普通餐厅能吃到炒西蓝花、玉米羹等等这样的菜,在高档的五星级餐厅也能吃到。

只不过五星级餐厅的厨师会把同样的菜做的更加细致,无论从食材的选择,料汁的调配,加上好看的摆盘,配上好听的名字,让这些菜变得更加档次。

所以简单来说,数组经过增加数据、删除数据、修改数据、查找数据等等的操作,摇身一变,就变成了顺序表。

2.2 顺序表分类:

顺序表分为静态顺序表动态顺序表

2.2.1 静态顺序表

概念:使⽤定⻓数组存储元素

静态顺序表缺陷:空间给少了不够⽤,给多了造成空间浪费

2.2.2 动态顺序表 

3. 接口实现

静态顺序表只适用于确定知道需要存多少数据的场景。静态顺序表的定长数组导致N定大了,空间开多了浪费,开少了不够用。所以现实中基本都是使用动态顺序表,根据需要动态的分配空间大小,所以下面我们实现动态顺序表。

基本增删查改接口

//对数据管理 --- 增删查改
void SLInit(SL* ps);			//初始化
void SLDestory(SL* ps);			//释放
void SLPrint(SL* ps);        	//打印
void SLCheakCapacity(SL* ps);	//检查容量 -- 扩容//头插头删 尾插尾删
void SLPushBack(SL* ps, SLDateType x); //尾插
void SLPopBack(SL* ps);				   //尾删
void SLPushFront(SL* ps, SLDateType x);//头插
void SLPopFront(SL* ps);			   //头删//返回下标,没找到返回-1
int SLFind(SL* ps, SLDateType);		   //查找元素,返回下标//在pos位置插入x
void SLInsert(SL* ps, int pos, SLDateType x);	//任意位置插入
//在pos位置删除x
void SLErase(SL* ps, int pos);					//任意位置删除void SLModify(SL* ps, int pos, SLDateType x);//修改

3.1 创建项目

由于在实际工程中,项目的实现都是采用模块化进行实现的。

所以在此处我也采用了模块化的方式进行实现。

3.2 定义动态顺序表结构 

#pragma once#include <stdio.h>
#include <assert.h>
#include <stdlib.h>动态顺序表
typedef int SLDataType;typedef struct SeqList
{SLDataType* arr;//存储数据的底层结构 int capacity;//记录顺序表的空间大小 int size;//记录顺序表当前有效的数据个数 
}SL;

为了后续好修改类型数据,我们可以使用typedef将结构体类型struct SeqList 重新命名为SL
在后续对顺序表操作中,为了用户更好的输入数据,一般我们会将输入数据的数据类型重命名为SLDataType
采用typedef将其数据类型int重命名为SLDataType 

3.3 初始化与销毁

函数声明:

//初始化和销毁
void SLInit(SL* ps);
void SLDestroy(SL* ps);

函数实现: 

//初始化顺序表
void SLInit((SL* ps)//传入链表地址便于修改
{ps->arr= NULL;ps->size = ps->capacity = 0;
}

动态顺序表是动态开辟的空间,结束时需要进行释放,避免造成内存泄漏

void SLDestroy(SL* ps)
{assert(ps);if (ps->arr) {free(ps->arr);}ps->arr = NULL;ps->capacity = ps->size = 0;
}

 代码解读:

assert(ps):这是一个断言语句,用于检查 ps 是否为非空指针。如果ps为空,
程序会在运行时中断并报错。 
if (ps->arr):检查 ps 结构体中的 arr 成员是否不为空。
free(ps->arr)`:如果 arr 不为空,使用 free 函数释放其占用的内存空间。 
ps->arr = NULL:将 arr 成员指针设置为空,以避免悬空指针。 
ps->capacity = ps->size = 0:将 capacity 和 size 成员都设置为 0。

3.4 顺序表容量检查

注意:

  1. 每当要增加数据时,都需要考虑空间是否使用完毕
  2. 如果使用完毕则需要考虑增容,增容为原来的两倍(避免频繁扩容)
  3. 增容后更新记录容量大小

注:这里我们考虑到有许多地方要检查是否增容,为了方便将它封装成一个函数 

函数声明:

//扩容
void SLCheckCapacity(SL* ps); 

函数实现: 

void SLCheckCapacity(SL* ps) 
{if (ps->size == ps->capacity){int newCapacity = ps->capacity == 0 ? 4 : 2 * ps->capacity;SLDataType* tmp = (SLDataType*)realloc(ps->arr, newCapacity * 
sizeof(SLDataType));if (tmp == NULL) {perror("realloc fail!");exit(1);}//扩容成功ps->arr = tmp;ps->capacity = newCapacity;}
}

 代码解读:

判断结构体中的当前元素数量 size 是否等于容量 capacity 。如果相等,说明需要进行扩容操作。计算新的容量。如果当前容量为 0 ,则新容量设置为 4 ;否则新容量设置为当前容量的 2 倍。使用 realloc 函数尝试为数组重新分配内存,新的内存大小为新的容量乘以每个元素的大小。检查 realloc 是否成功。如果 realloc 失败(返回 NULL ),则:
打印错误信息。退出程序。如果扩容成功:更新结构体中的数组指针,使其指向新分配的内存。更新结构体中的容量值。

 3.5 打印

函数声明:

//顺序表打印
void SLPrint(SL* ps);

 上述函数定义完成后,我们通常需要测试打印以下相关数据,来判断相关函数定义是否成功.

代码实现:

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

3.6 尾插

函数声明:

//顺序表的尾部插入
void SLPushBack(SL* ps, SLDataType x);

我们来分析一下:

尾插是在尾部插入一个数据。

但是在数据的尾部插入一个数据时,

我们需要考虑一个问题:原有空间是否可以容纳新的数据,是否需要扩容。
所以我们在插入数据时,要先调用 SLCheakCapacity函数来检查是否需要扩容。

代码实现:

//顺序表的尾部插入
void SLPushBack(SL* ps, SLDataType x)
{//对于顺序表为空,可以有两种判断方式//①断言--粗暴的解决方式//assert(ps != NULL);assert(ps);//②if判断--温柔的解决方式//if (ps == NULL)//{//	return;//}//空间不够,扩容SLCheckCapacity(ps);//空间足够,直接插入ps->arr[ps->size++] = x;
}

3.7尾删

函数声明:

//顺序表的尾部删除
void SLPopBack(SL* ps);

我们来分析一下:

尾删:删除尾部最后的一个元素。

但尾删同样也要考虑一个问题,空间中是否还有数据给我们删除。
所以在进行尾删时,我们可以采用assert函数断言空间中还有数据。

代码实现:

void SLPopBack(SL* ps)
{assert(ps);assert(ps->size >= 0);//断言空间中还有元素ps->size--;//下标减1
}

在删除数据时,我们不用将原有数据删除。只需要下标减1即可。
原因在于我们时根据下标来使用数据的,当下标减1后,尾部最后一个数据便无法进行访问。

 3.8 头插

函数声明:

//顺序表头部插⼊
void SLPushFront(SL* ps, SLDataType x);

我们来分析一下:

头插:在数据最开始地方插入数据。

比如,在0前面插入100

我们可以这样做: 

同样,头插也要调用 SLCheakCapacity函数来检查空间是否足够,是否需要扩容。

 

代码实现:

void SLPushFront(SL* ps, SLDataType x)
{assert(ps);//判断是否扩容 SLCheckCapacity(ps);//旧数据往后挪动一位for (int i = ps->size; i > 0 ; i--){ps->arr[i] = ps->arr[i - 1];//ps->arr[1] = ps->arr[0]}ps->arr[0] = x;ps->size++;
}

3.9 头删

函数声明:

//顺序表的头部删除
void SLPopFront(SL* ps);

我们来分析一下:

头删:删除数据最开始的元素。

思路和头插类似,只要下标从1开始,所有数据依次向前移动1位,再把有限个数减1即可。
同时头删也需要使用assert函数断言原有空间中还有数据可以删除。 

 代码实现:

void SLPopFront(SL* ps)
{assert(ps);assert(ps->size);//空间中还有数据可以删除//后面的数据往前挪动一位for (int i = 0; i < ps->size; i++){ps->arr[i-1] = ps->arr[i];//ps->arr[1] = ps->arr[0]}ps->size--;
}

3.10 指定位置之前插入数据

函数声明:

//指定位置之前插⼊
void SLInsert(SL* ps, int pos, SLDataType x);

我们分析一下:

看到插入两个字,我们就要考虑是否需要扩容。这一点很重要。还有我们要多pos这个参数进行判断,看是否在顺序表指定的范围中,因为顺序表是连续的,我们任意位置插入要合理,所以要对参数进行合理性判断:

assert(pos >= 0 && pos <= ps->size); 

先给大家来画个图分析:

代码实现:

void SLInsert(SL* ps, int pos, SLDataType x)
{//顺序表为空assert(ps);assert(pos >= 0 && pos <= ps->size);// 空间够不够?是否扩容?SLCheckCapacity(ps);//pos及之后的数据往后挪动一位for (int i = ps->size; i> pos; i--){ps->arr[i] = ps->arr[i - 1];}ps->arr[pos] = x;ps->size++;
}

代码解读:

assert(ps) :确保 ps 指针非空。
assert(pos >= 0 && pos <= ps->size) :确保指定的插入位置 pos 是有效的,即在 0 到当前元素数量 ps->size 的范围内。
SLCheckCapacity(ps) :在插入元素之前,检查并可能进行容量的扩展,以确保有足够的空间来插入新元素。
循环部分:
通过 for 循环方式,将位置 pos 及之后的元素向后移动一位,为新元素腾出位置。

ps->arr[pos] = x :将新元素 x 插入到指定位置 pos 。
ps->size++:增加元素数量,表示成功插入了一个新元素。 

3.11 删除任意位置数据

函数声明:

//删除指定位置数据 
void SLErase(SL* ps, int pos);

【代码思路】:和插入任何位置数据思想类似。首先我们要检查输入下标pos是否合法。之后从输入下标开始,后一个元素拷贝到前一个元素空间。

代码实现:

void SLErase(SL* ps, int pos)
{assert(ps);assert(pos >= 0 && pos < ps->size);//pos以后的数据往前挪动一位for (int i = pos; i < ps->size-1; i++){ps->arr[i] = ps->arr[i + 1];//ps->arr[i-2] = ps->arr[i-1];}ps->size--;
}

3.12 查找

函数声明:

//在顺序表中查找x
int SLFind(SL* ps, SLDataType x);

【代码思路】:要查找某个元素。由于这里只是最简单的查找,我们直接暴力查找,遍历整个数组返回下标即可。更为复杂的数据查找,会有更高阶的数据结构来实现。

代码实现:

int SLFind(SL* ps, SLDateType x)
{assert(ps);for (int i = 0; i < ps->size; i++){if (x == ps->a[i])return i;}return -1;
}

4. 所有代码 

SeqList.h

#pragma once
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>//静态顺序表
//#define N 100
//typedef int SLDataType;
//
struct SeqList
{SLDataType a[N];int size;
};//动态顺序表
typedef int SLDataType;typedef struct SeqList
{SLDataType* arr;//存储数据的底层结构 int capacity;//记录顺序表的空间大小 int size;//记录顺序表当前有效的数据个数 
}SL;//初始化和销毁
void SLInit(SL* ps);
void SLDestroy(SL* ps);
void SLPrint(SL* ps);//保证接口的一致性//顺序表头部 尾部插⼊
void SLPushBack(SL* ps, SLDataType x);
void SLPushFront(SL* ps, SLDataType x);//顺序表的头部 尾部删除
void SLPopBack(SL* ps);
void SLPopFront(SL* ps);//指定位置之前插入数据
//删除指定位置数据 
void SLInsert(SL* ps, int pos, SLDataType x);
void SLErase(SL* ps, int pos);//在顺序表中查找x
int SLFind(SL* ps, SLDataType x);

SeqList.c

#define _CRT_SECURE_NO_WARNINGS 1#include "SeqList.h"void SLInit(SL* ps)
{ps->arr = NULL;ps->size = ps->capacity = 0;
}void SLDestroy(SL* ps)
{assert(ps);if (ps->arr) {free(ps->arr);}ps->arr = NULL;ps->capacity = ps->size = 0;
}void SLCheckCapacity(SL* ps) 
{if (ps->size == ps->capacity){int newCapacity = ps->capacity == 0 ? 4 : 2 * ps->capacity;SLDataType* tmp = (SLDataType*)realloc(ps->arr, newCapacity * sizeof(SLDataType));if (tmp == NULL) {perror("realloc fail!");exit(1);}//扩容成功ps->arr = tmp;ps->capacity = newCapacity;}
}//顺序表的头部/尾部插入
void SLPushBack(SL* ps, SLDataType x) {//断言--粗暴的解决方式//assert(ps != NULL);assert(ps);//if判断--温柔的解决方式//if (ps == NULL) {//	return;//}//空间不够,扩容SLCheckCapacity(ps);//空间足够,直接插入ps->arr[ps->size++] = x;//ps->size++;
}void SLPushFront(SL* ps, SLDataType x)
{assert(ps);//判断是否扩容 SLCheckCapacity(ps);//旧数据往后挪动一位for (int i = ps->size; i > 0 ; i--){ps->arr[i] = ps->arr[i - 1];//ps->arr[1] = ps->arr[0]}ps->arr[0] = x;ps->size++;
}//顺序表的头部 尾部删除
void SLPopBack(SL* ps)
{assert(ps);assert(ps->size);ps->size--;
}
void SLPopFront(SL* ps)
{assert(ps);assert(ps->size);//后面的数据往前挪动一位for (int i = 0; i < ps->size; i++){ps->arr[i-1] = ps->arr[i];//ps->arr[1] = ps->arr[0]}ps->size--;
}void SLPrint(SL* ps)
{for (int i = 0; i < ps->size; i++){printf("%d ", ps->arr[i]);}printf("\n");
}//指定位置之前插入数据
//删除指定位置数据 void SLInsert(SL* ps, int pos, SLDataType x)
{assert(ps);assert(pos >= 0 && pos <= ps->size);SLCheckCapacity(ps);//pos及之后的数据往后挪动一位for (int i = ps->size; i> pos; i--){ps->arr[i] = ps->arr[i - 1];}ps->arr[pos] = x;ps->size++;
}void SLErase(SL* ps, int pos)
{assert(ps);assert(pos >= 0 && pos < ps->size);//pos以后的数据往前挪动一位for (int i = pos; i < ps->size-1; i++){ps->arr[i] = ps->arr[i + 1];//ps->arr[i-2] = ps->arr[i-1];}ps->size--;
}//在顺序表中查找xint SLFind(SL* ps, SLDataType x)
{//加上断言健壮性更好 assert(ps);for (int i = 0; i < ps->size; i++){if (x == ps->arr[i])return i;}return -1;
}

测试代码:Test.c

#define _CRT_SECURE_NO_WARNINGS 1#include "SeqList.h"void SLTest01()
{SL sl;SLInit(&sl);//测试尾插SLPushBack(&sl, 1);SLPushBack(&sl, 2);SLPushBack(&sl, 3);SLPushBack(&sl, 4);// 1 2 3 4SLPrint(&sl);//SLPushBack(&sl, 5);//SLPrint(&sl);//头插/*SLPushFront(&sl, 5);SLPushFront(&sl, 6);SLPushFront(&sl, 7);*///7 6 5 1 2 3 4//SLPrint(&sl);//尾删//SLPopBack(&sl);//SLPopBack(&sl);//SLPopBack(&sl);//SLPopBack(&sl);//SLPopBack(&sl);/*SLPopFront(&sl);SLPopFront(&sl);SLPrint(&sl);SLPopFront(&sl);SLPrint(&sl);*///指定位置插入//SLInsert(&sl, 0, 100);//SLPrint(&sl);//100 1 2 3 4//SLInsert(&sl, sl.size, 200);//SLPrint(&sl);//100 1 2 3 4 200//SLInsert(&sl, 100, 300);//SLPrint(&sl);//100 1 2 3 4 200//SLErase(&sl, 0);//SLPrint(&sl);//SLErase(&sl, sl.size-1);//SLPrint(&sl);SLErase(&sl, 1);SLPrint(&sl);}void SLTest02()
{SL sl;SLInit(&sl);//测试尾插SLPushBack(&sl, 1);SLPushBack(&sl, 2);SLPushBack(&sl, 3);SLPushBack(&sl, 4);// 1 2 3 4SLPrint(&sl);//测试查找 int ret = SLFind(&sl, 30);if (ret < 0) {printf("数据不存在,查找失败!\n");}else{printf("数据找到了, 在下标为%d位置\n", ret);}
}void SLTest03()
{SL sl;SLInit(&sl);//测试尾插SLPushBack(&sl, 1);SLPushBack(&sl, 2);SLPushBack(&sl, 3);SLPushBack(&sl, 4);// 1 2 3 4SLPrint(&sl);//测试销毁SLDestroy(&sl);SLPrint(&sl);}int main()
{//SLTest01();//SLTest02();SLTest03();return 0;
}

 大家可以根据上述思路和提供的源码,自己练习哦~

后续数据结构的学习,大家需要多画图,多练习代码,这样在实现中能够得心应手~

那么本期博客就讲到这里,如果对你有所帮助~ 别忘了收藏点赞哦

有疑问的,可以随时在评论区骚扰我哟~

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【Material-UI】Button 中的点击事件处理(Handling clicks)详解

文章目录 一、点击事件处理基础1. 基本用法2. 事件处理器的传递 二、实际应用中的注意事项1. 事件处理逻辑的优化2. 避免过多的状态更新3. 使用合适的事件类型 三、关于文档中未提及的原生属性四、最佳实践1. 无障碍性2. 视觉反馈3. 防止重复点击 五、总结 在现代前端开发中&am…

【竞品分析】竞品分析的步骤

在产品经理的工作实际中,对产品的设计离不开竞品分析。 竞品分析可以辅助我们进行可行性评估、制定产品战略、优化产品迭代等。 可以说,竞品分析是贯穿产品生命周期的,是产品经理的必备专业技能。 个人认为&#xff0c;做自己家的产品是单一的视角&#xff0c;多做竞品分析会…

【微信小程序开发】——奶茶点餐小程序的制作(二)

&#x1f468;‍&#x1f4bb;个人主页&#xff1a;开发者-曼亿点 &#x1f468;‍&#x1f4bb; hallo 欢迎 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! &#x1f468;‍&#x1f4bb; 本文由 曼亿点 原创 &#x1f468;‍&#x1f4bb; 收录于专栏&#xff1a…

HTML 元素提供的附加信息--属性 ——WEB开发系列03

HTML 属性是指用于描述 HTML 元素的额外信息&#xff0c;它们提供了元素的特定配置或行为&#xff0c;属性通常包含在 HTML 元素的开始标签中。 元素也可以拥有属性&#xff0c;属性看起来像这样&#xff1a; 属性是元素的附加信息&#xff0c;它们不会显示在实际内容中。在前述…

Hack The Box-Resource

总体思路 phar反序列化->SSH CA私钥泄露->SSH CA私钥滥用->SSH脚本滥用 信息收集&端口利用 nmap -sSVC itrc.ssg.htb目标开放了两个ssh端口和一个80端口&#xff0c;先查看80端口 网站是一个SSG IT资源中心&#xff0c;主要用于解决网站问题、管理 SSH 访问、清…

【学习总结】MySQL篇

MySQL MySQL索引 B树 B树和作为索引&#xff0c;有两个明显特点 一是、他的层级非常低&#xff0c;我们都知道传统的平衡二叉树。它们的阶为2&#xff0c;如果数据量很大&#xff0c;AVL树&#xff08;传统的平衡二叉树&#xff09;的层级就非常深。但是B树&#xff0c;它是…

基于STM32F407+NBIOT+华为云IOT平台设计的环境检测系统

基于STM32F407NBIOT华为云IOT平台设计的环境检测系统实现的功能&#xff1a; 【1】能够采集本地环境的温度、湿度、烟雾浓度&#xff0c;火光信息&#xff0c;在OLED显示屏上显示。 如果检测到烟雾、温度、火光超过阀值会触发蜂鸣器报警。 【2】能够通过NBIOT将本地设备采集的信…

在 Django 表单中传递自定义表单值到视图

在Django中&#xff0c;我们可以通过表单的初始化参数initial来传递自定义的初始值给表单字段。如果我们想要在视图中设置表单的初始值&#xff0c;可以在视图中创建表单的实例时&#xff0c;传递一个字典给initial参数。 1、问题背景 我们遇到了这样一个问题&#xff1a;在使…

解决 MacOS 连接公司 VPN 成功但是不能网络的问题

目录 解决办法2024 Mac mini 爆料 解决办法 操作比较简单&#xff0c;修改配置文件即可&#xff08;如果没有则需要手动创建&#xff09;。 sudo vim /etc/ppp/options在此文件下&#xff0c;加入 plugin L2TP.ppp&#xff1a; plugin L2TP.ppp如果文件里有l2tpnoipsec&…

【SpringBoot系列】接口参数的默认值与必要性

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…

结构化输出及其使用方法

在 LLM 应用程序中构建稳健性和确定性 图片来自作者 欢迎来到雲闪世界。OpenAI最近宣布其最新的gpt-4o-2024–08–06模型支持结构化输出。与大型语言模型 (LLM) 相关的结构化输出并不是什么新鲜事——开发人员要么使用各种快速工程技术&#xff0c;要么使用第三方工具。 在本文…

[ACP云计算]组件介绍

一、IaaS、PaaS、SaaS 二、交换机 三、VPC 四、ECS 云服务器ECS&#xff08;Elastic Compute Service&#xff09;是阿里云提供的性能卓越、稳定可靠、弹性扩展的IaaS&#xff08;Infrastructure as a Service&#xff09;级别云计算服务。云服务器ECS免去了您采购IT硬件的前期…

vue项目名修改、webstorm和idea创建的项目重命名、重构项目、修改项目名称

一、需求 就是创建了一个项目&#xff0c;后期需要重命名&#xff0c;怎么办&#xff1f;----> 直接修改&#xff1f;肯定不行&#xff0c;因为里面有些配置也需要修改&#xff0c;假如你只改文件夹名称的话&#xff0c;里面配置都没修改&#xff0c;后期可能会出问题。 二…

完美解决浏览器的输入框自动填入时,黄色背景问题,以及图标被遮住问题(最新)

用图说话↓↓↓ 首先用代码解决黄色背景问题&#xff0c;box-shadow颜色设置透明即可&#xff0c;延时渲染时间可修改为更久 :deep(input:-webkit-autofill) {box-shadow: 0 0 0 1000px transparent !important;/* 浏览器记住密码的底色的颜色 */-webkit-text-fill-color: #f…

C++:多态及虚函数

多态&#xff1a;面向对象的多态性可以分为4类:重载多态、强制多态、包含多态和参数多态。 多态从实现的角度来讲可以划分为两类:编泽时的多态和运行时的多态 运算符重载&#xff1a; foo(i)相当于i的一个别名 前置和后置重载&#xff08;后置参数必须加一个int&#xff09; …

Ubuntu 22.04 Docker安装笔记

1、准备一台虚机 可以根据《VMware Workstation安装Ubuntu 22.04笔记》来准备虚拟机。完成后&#xff0c;根据需求安装必要的软件&#xff0c;并设置root权限进行登录。 sudo apt update sudo apt install iputils-ping -y sudo apt install vim -y允许root ssh登录&#xff1…

邀请函 I 松下信息和望繁信科技邀您参加「数智时代下大数据应用的“道”与“术”」闭门会议

在数字化浪潮席卷全球的今天&#xff0c;大数据与智能化的结合成为企业成功的关键。为了深入探讨这一重要议题&#xff0c;松下信息系统&#xff08;上海&#xff09;有限公司&#xff08;简称“松下信息”&#xff09;与上海望繁信科技有限公司&#xff08;简称“望繁信科技”…

11.面试题——消息队列RabbitMQ

1.RabbitMQ是什么&#xff1f;特点是什么&#xff1f; RabbitMQ是一种开源的消息队列中间件&#xff0c;用于在应用程序之间进行可靠的消息传递。它实现了AMQP&#xff08;Advanced Message Queuing Protocol&#xff09;协议&#xff0c;提供了强大的消息处理能力。RabbitMQ的…

【数据结构与算法】二叉树

二叉树 一.二叉树的结构二.二叉树的插入1.根的插入2.其他的插入 三.二叉树的删除1.找到删除节点2.删除节点的子节点只有一个或没有3.删除节点的子节点有两个 四.完整代码 一.二叉树的结构 树的形式多种多样,但是我们最常用的还是二叉树.在二叉树中最长用的又数二叉搜索树. 这…

云原生的候选应用

前言&#xff0c;到底哪些应用适合云原生&#xff1f; 云原生应用适合于多种场景&#xff0c;‌包括高并发、‌高负载的Web应用、‌大数据处理、‌容器化应用程序、‌微服务架构、‌DevOps、‌智能物联网、‌云原生区块链应用以及大数据和机器学习。‌ 高并发、‌高负载的Web…