顺序表讲解

一.数据结构

在学习顺序表之前,我们先需要了解什么是数据结构。

1.什么是数据结构呢?

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

什么是数据呢?

你的游戏账号,身份信息,网页里的信息(文字,视频,图片),手机app存储的信息等等这些都是数据。

什么是结构呢?

在生活中,我们是有很多数据的,当我们想要使用大量的同一类型的数据的时候,通过手动定义大量的独立变量对于程序员的消耗是很大的,并且可读性非常的查,无法轻易的实现查找数据,排列数据等基本功能。可读性非常差,我们可以借助数组这样的数据结构将大量的数据组织在一起,结构也可以理解为组织这样结构的方式。

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

总结:1.能够存储数据(比如顺序表,链表等结构)2.存储的数据方便查找。

2.为什么需要数据结构?

假设在餐馆中,如果我们不使用排队的方式来管理客户点餐,会导致客户就餐感受差,等餐时间长,餐厅营业混乱等情况。同理在程序中,如果不对数据进行管理,可能会导致数据丢失,数据管理困难等问题。所以我们需要通过数据结构,能够将有效数据组织和管理在一起。按照我们的方式任意对数据进行增删改查等操作。

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

可是数组有一个极大的缺陷,就是在我们声明数组的时候,数组的大小需要固定,可是我们的数据的多少却是无法确定的,数组过大,会导致空间浪费,数组过小,会导致数据丢失。

也就是最基础的数据结构能够提供的操作已经不能完全满足复杂算法的实现了。
 

二.顺序表 

1.顺序表的概念以及结构

1.1线性表

线性表(linear list)是n个具有相同特性的数据元素的有限序列。线性表是一种在实际中广泛使用的数据结构,常见的线性表:顺序表,链表,栈,队列,字符串,数组......

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

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

案例:蔬菜分为绿叶类,瓜类,菌菇类。线性表指的是具有部分相同特性的一类数据结构的集合。

2.顺序表分类

2.1顺序表和数组的区别

顺序表的底层结构式数组,对数组的封装,实现了常用的增删改查等接口

2.2分类

1.静态顺序表

概念:使用定长数组存储元素

typedef int SLDataType;
#define N 7
struct SeqList {SLDataType arr[N];//定长数组int size;//存储的有效数据个数
};typedef struct SeqList SL;

这样的顺序表其实和数组类似:空间少了不够使用,多了会造成空间浪费

2.动态顺序表
struct SeqList {SLDataType *arr;//按需求申请空间int size;//存储的有效数据个数int capacity;//顺序表实际空间容量
};typedef struct SeqList SL;

什么是按需申请空间呢?

这时候就需要用到我们的malloc函数申请空间用于我们存储数据,如果空间不够了,我们再使用realloc函数对空间进行扩容。 

这样的顺序表就非常的方便了

3.顺序表的实现

#pragma once
#define INIT_CAPACITY 4
typedef int SLDataType;
// 动态顺序表 -- 按需申请
typedef struct SeqList
{SLDataType* a;int size; // 有效数据个数int capacity; // 空间容量
}SL;
//初始化和销毁
void SLInit(SL* ps);//初始化
void SLDestroy(SL* ps);//销毁
void SLPrint(SL* ps);//打印数据
//扩容
void SLCheckCapacity(SL* ps);
//头部插⼊删除 / 尾部插⼊删除
void SLPushBack(SL* ps, SLDataType x);//尾插
void SLPopBack(SL* ps);//尾删
void SLPushFront(SL* ps, SLDataType x);//头插
void SLPopFront(SL* ps);//头删
//指定位置之前插⼊/删除数据
void SLInsert(SL* ps, int pos, SLDataType x);//插入
void SLErase(SL* ps, int pos);//删除
int SLFind(SL* ps, SLDataType x);//查找

我们自己实现顺序表的基础就是完成以上所有函数 。

 1.首先我们先完成初始化函数。

void SLInit(SL* ps);//初始化SL ps;SLInit(&ps);

首先我们来思考一个问题:为什么在初始化函数中我们使用的是SL*类型的指针作为参数?

这是因为如果是使用SL作为参数的话,我们在函数中的任何操作并不会影响实参,形参只是实参的临时拷贝,改变形参并不会影响实参,所以为了改变实参,我们就需要使用一个指向实参的指针。这里我们为了改变这个结构体ps,我们就需要使用一个指向ps的指针。

然后我们再来思考这个初始化函数应该怎么写。

顺序表这个结构体有三个成员变量,对结构体进行初始化,无非就是对这个三个成员变量进行初始化。

顺序表开始是没有存储任何数据的,所以很明显这里的size就是0了.

观察上面的头文件,有着这样一句代码

typedef int SLDataType;

顺序表是可以储存不同种类的数据的,所以我们在使用的时候不能将数据的类型定死了,这是需要根据情况进行改变的,但是我们在实际开发中是不可能对每一个类型一个一个改变的,所以为了方便,我们将我们要存储的类型重命名为SLDataType这样如果我们需要存储其他类型的数据直接进行改变重命名的对象即可。

这也是为什么结构体的指针是SLDatatype*类型的原因了。

我们此时的顺序表是没有储存任何数据的,我们还需要为其开辟空间吗?如果要,那么开辟多大的空间合适呢?

实际上,开不开辟都可以,这个看自己即可,如果初始就开辟会更加方便,这样不用在后续使用的过程中判断空间是否为0了。

第二个问题开辟多大的空间合适呢?

这个是要看具体的实际情况的,这里我们是自己写,不会用到太多的数据,我们就开辟4个元素大小空间即可。

#define INIT_CAPACITY 4

如果觉得太小直接将4进行更改即可。

因为我们要开辟4个空间,所以此时顺序表的容量就是4了。这时候我们就完成了顺序表的初始化了.

void SLInit(SL* ps) {//初始化ps->a = (SLDataType*)malloc(sizeof(SLDataType) * 4);ps->size = 0;ps->capacity = 4;
};

2.完成插入数据函数 

 接下来就是如何插入元素了

这里解释一下头插尾插什么意思,因为顺序表的本质上是一个数组,只不过这个数组大小是可变的,头插就是在这个顺序表的最前面插入一个数据,尾插就是在顺序表的末尾插入一个数据.头删尾删同理就是删除数据了.

本质上这四种函数其实都是一样的,为了本文的简便性,我们先完成指定位置插入函数和指定位置删除函数,然后再使用这两个函数完成其他函数,也是为了方便大家理解.

void SLInsert(SL* ps, int pos, SLDataType x);

第一个参数就是顺序表结构体的指针了,第二个参数就是指定位置的下表了(position),第三个参数就是我们需要插入的元素.

但是我们需要考虑一个问题,如果顺序表容量不够了怎么办,此时我们是不能进行插入的,否则就造成了数据的丢失,这是非常重大的事故.

所以我们在完成插入函数之前我们需要判断容量是否够 .所以我们可单独再定义一个函数完成此功能.

void SLCheckCapacity(SL* ps) ;

 什么时候顺序表的空间不够了呢?

我们要存储的数据大于空间容量就不够了,也就是ps->size > ps->capacity的时候就空间不足了,但是我们存储数据的时候是一个一个进行存储的,也就是说其实两者相等的时候就已经不够了,因为此时我们已经没有办法存储数据了,所以需要realloc函数进行扩容处理.

此时我们又遇到了一个问题:这个空间扩大到多大合适呢?是加1还是加2呢?

如果我们扩容的空间较小,这时候我们就会反复调用这个函数,此时函数压栈会浪费很多性能和时间

程序效率就会低下,所以最好是扩大2倍或者3倍(这个是有数学推导出来的).

void SLCheckCapacity(SL* ps) {//检测空间大小assert(ps);if (ps->capacity == ps->size) {ps->a = realloc(ps->a,sizeof(SLDataType) * ps->capacity * 2);}
};

此时我们就完成了扩容操作.

但是

这样写对不对呢?

我们知道realloc函数,如果开辟失败是会返回NULL的,如果发生这样的情况,ps->a就变成了NULL,我们不仅开辟失败了,还丢失了访问原来开辟空间的权力,造成了内存泄漏的情况,同时我们也丢失了所有的数据.

所以我们需要定义一个临时变量,来储存realloc函数的返回值,如果返回值不为NULL,我们再把返回值传给ps->a.这样就避免了这样的情况.

以为这样就完了吗?

其实还有一个错误.我们进行了扩容,但是我们并没有改变容量大小,这样也会造成数据丢失的情况,所以容量也要*2.

完整版:

void SLCheckCapacity(SL* ps) {//检测空间大小assert(ps);if (ps->capacity == ps->size) {SLDataType* tmp = realloc(ps->a,sizeof(SLDataType) * ps->capacity * 2);if (tmp == NULL) {perror("realloc");exit(1);}ps->a = tmp;ps->capacity *= 2;}
};

完成了这些我们再来看插入函数.

假设这里有这样一个顺序表,储存着这样的数据1 2 3 4 5 ... 9

如果我们要在下标为6的位置之前插入一个数据10,也就是在数据6前面插入一个数据10,我们需要怎么完成呢?

首先我们需要对原有的数据进行移动,避免数据丢失了.依次将后面的数据向后移动一位.然后再在下标为5的位置写入数字10, 

 	for (int i = ps->size; i > pos; i--){ps->a[i] = ps->a[i - 1];}ps->a[pos] = x;

我们是从下标为size的位置开始的,所以i从ps->size开始,直到pos的后一位结束.

再移动完了后直接更改即可.

但是这里还有一个错误,也是一个很容易犯错的地方.

我们在插入一个数据后,有效数据的个数其实是变化了的,所以要加1,同理删除要减1,这个一定不能忘了.

完整版:

void SLInsert(SL* ps, int pos, SLDataType x) {//在指定位置之前插入assert(ps);assert(pos <= ps->size && pos >= 0);SLCheckCapacity(ps);for (int i = ps->size; i > pos; i--){ps->a[i] = ps->a[i - 1];}ps->a[pos] = x;ps->size++;
};

3.完成删除数据函数

 还是上图的顺序表,如果我们要删除下标为5位置上的数据,我们需要将后面的数据向前挪动一位.

void SLErase(SL* ps, int pos) {//删除指定位置的数据assert(ps);assert(ps->size > pos && pos >= 0);while (pos < ps->size) {ps->a[pos] = ps->a[pos + 1];pos++;}ps->size--;
};

这里之所以要断言是因为要删除的下标必须要小于有效数据的个数,并且大于等于0,不然我们删除的就不是有效数据,这是没有意义的,而且可能会非法访问,出现越界的情况.

不要忘了结束要size--;

4.查找函数

int SLFind(SL* ps, SLDataType x);

x就是我们需要查找的数据,如果找到了函数返回下标,否则返回-1;

我们只需要遍历一遍顺序表即可完成。非常简单。

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

5.头插/删,尾插/删 

这个是基于我们前面写的指定位置插入和删除函数写的,这里就不过多赘述。 

void SLPushBack(SL* ps, SLDataType x) {SLInsert(ps,ps->size,x);
};
void SLPopBack(SL* ps) {SLErase(ps,ps->size-1);
};
void SLPushFront(SL* ps, SLDataType x) {SLInsert(ps,0,x);
};
void SLPopFront(SL* ps) {SLErase(ps,0);
};

这样写其实是有好处的,更加便捷,而且不用考虑顺序表是否为空等其他情况。建议读者自行完成这四个函数,不使用指定位置的函数做跳板,可以更加理解顺序表。 

6.最后就是销毁顺序表

void SLDestroy(SL* ps) {//销毁顺序表assert(ps);free(ps->a);ps->a = NULL;ps->capacity = ps->size = 0;
};

ps->a是我们动态开辟的内存,所以最后需要释放掉,并且将指针置为NULL,避免非法访问的情况,最后再将有效数据个数和顺序表容量置为0即可。

4.通讯录

学完了顺序表,我们就可尝试使用顺序表完成一个简单的通讯录了,这个我并没有讲解,因为比较简单,会了顺序表的同学都可以看懂。 以下是代码实现:

//SeqList.h
#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include"contact.h"
#define INIT_CAPACITY 4
typedef PeoInfo SLDataType;
// 动态顺序表 -- 按需申请
typedef struct SeqList
{SLDataType* a;int size; // 有效数据个数int capacity; // 空间容量
}SL;
//初始化和销毁
void SLInit(SL* ps);
void SLDestroy(SL* ps);
//void SLPrint(SL* ps);
//扩容
void SLCheckCapacity(SL* ps);
//头部插⼊删除 / 尾部插⼊删除
void SLPushBack(SL* ps, SLDataType x);
void SLPopBack(SL* ps);
void SLPushFront(SL* ps, SLDataType x);
void SLPopFront(SL* ps);
//指定位置之前插⼊/删除数据
void SLInsert(SL* ps, int pos, SLDataType x);
void SLErase(SL* ps, int pos);
int SLFind(SL* ps, SLDataType x);
//SeqList.c#define _CRT_SECURE_NO_WARNINGS 
#include"SeqList.h"
//typedef struct SeqList
//{
//	SLDataType* a;
//	int size; // 有效数据个数
//	int capacity; // 空间容量
//}SL;
void SLInit(SL* ps) {//初始化ps->a = (SLDataType*)malloc(sizeof(SLDataType) * 4);ps->size = 0;ps->capacity = 4;
};
void SLDestroy(SL* ps) {//销毁顺序表assert(ps);free(ps->a);ps->a = NULL;ps->capacity = ps->size = 0;
};
//void SLPrint(SL* ps) {//打印顺序表
//	assert(ps);
//	int i = 0;
//	for (i = 0; i < ps->size; i++) {
//		printf("%d->",ps->a[i]);
//	}
//	printf("\n");
//};
void SLCheckCapacity(SL* ps) {//检测空间大小assert(ps);if (ps->capacity == ps->size) {SLDataType* tmp = realloc(ps->a,sizeof(SLDataType) * ps->capacity * 2);if (tmp == NULL) {perror("realloc");exit(1);}ps->a = tmp;ps->capacity *= 2;}
};
void SLInsert(SL* ps, int pos, SLDataType x) {//在指定位置之前插入assert(ps);assert(pos <= ps->size && pos >= 0);SLCheckCapacity(ps);for (int i = ps->size; i>pos; i--){ps->a[i] = ps->a[i - 1];}ps->a[pos] = x;ps->size++;
};void SLErase(SL* ps, int pos) {//删除指定位置的数据assert(ps);assert(ps->size > pos);while (pos < ps->size) {ps->a[pos] = ps->a[pos + 1];pos++;}ps->size--;
};
//int SLFind(SL* ps, SLDataType x) {//查找
//	assert(ps);
//	for (int i = 0; i < ps->size; i++) { 
//		if (ps->a->name == x.name) {
//			return i;
//		}
//	}
//};void SLPushBack(SL* ps, SLDataType x) {SLInsert(ps,ps->size,x);
};
void SLPopBack(SL* ps) {SLErase(ps,ps->size-1);
};
void SLPushFront(SL* ps, SLDataType x) {SLInsert(ps,0,x);
};
void SLPopFront(SL* ps) {SLErase(ps,0);
};

 

//contact.h#define _CRT_SECURE_NO_WARNINGS #pragma once
#define NAME_MAX 20
#define SEX_MAX 4
#define TEL_MAX 20
#define ADDR_MAX 100typedef struct SeqList contact;
typedef struct PersonInfo
{char name[NAME_MAX];char sex[SEX_MAX];int age;char tel[TEL_MAX];char addr[ADDR_MAX];
}PeoInfo;//初始化通讯录
void InitContact(contact* con);
//添加通讯录数据
void AddContact(contact* con);
//删除通讯录数据
void DelContact(contact* con);
//展⽰通讯录数据
void ShowContact(contact* con);
//查找通讯录数据
void FindContact(contact* con);
//修改通讯录数据
void ModifyContact(contact* con);
//销毁通讯录数据
void DestroyContact(contact* con);
//contact.c
#define _CRT_SECURE_NO_WARNINGS 
#include"SeqList.h"
#include<string.h>
//初始化通讯录
//typedef struct PersonInfo
//{
//	char name[NAME_MAX];
//	char sex[SEX_MAX];
//	int age;
//	char tel[TEL_MAX];
//	char addr[ADDR_MAX];
//}PeoInfo;
void loadContact(contact*con) {FILE* pf = fopen("contact.txt","rb");if (pf == NULL) {perror("fopen");return;}PeoInfo p;while (fread(&p, sizeof(p), 1, pf)) {SLPushBack(con,p);}
};void InitContact(contact* con) {//初始化通讯录SLInit(con);loadContact(con);
};
//添加通讯录数据
void AddContact(contact* con) {PeoInfo person;printf("请输入联系人的姓名:\n");scanf("%s", person.name);printf("请输入联系人的性别:\n");scanf("%s", person.sex);printf("请输入联系人的年龄:\n");scanf("%d",&(person.age));printf("请输入联系人的电话:\n");scanf("%s", person.tel);printf("请输入联系人的地址:\n");scanf("%s", person.addr);SLPushBack(con, person);printf("添加成功\n");
};//查找联系人是否存在
int findbyname(contact *con, char* name) {for (int i = 0; i < con->size; i++) {if (0 == strcmp(con->a[i].name, name)) {return i;}}return -1;
}//删除通讯录数据
void DelContact(contact* con) {char name[NAME_MAX];printf("请输入要删除的联系人的名字:\n");scanf("%s",name);int pos = findbyname(con, name);if (pos >= 0) {SLErase(con,pos);printf("删除成功!!!\n");}else {printf("要删除的联系人不存在!!!\n");return;}
};
//展⽰通讯录数据
void ShowContact(contact* con) {for (int i = 0; i < con->size; i++) {printf("%-20s %-4s %-3d %-20s %-100s\n",con->a[i].name,\con->a[i].sex,\con->a[i].age,\con->a[i].tel,\con->a[i].addr);\}
};
//查找通讯录数据
void FindContact(contact* con) {char name[NAME_MAX];printf("请输入要查找的联系人的名字:\n");scanf("%s", name);int pos = findbyname(con, name);if (pos >= 0) {printf("查找成功!!!\n");printf("%-20s %-4s %-3d %-20s %-100s\n", con->a[pos].name, \con->a[pos].sex, \con->a[pos].age, \con->a[pos].tel, \con->a[pos].addr); \}else {printf("该联系人不存在!!!\n");}
}
//修改通讯录数据
void ModifyContact(contact* con) {char name[NAME_MAX];printf("请输入要修改的联系人的名字:\n");scanf("%s", name);int pos = findbyname(con, name);if (pos >= 0) {printf("请输入联系人的姓名:\n");scanf("%s", con->a[pos].name);printf("请输入联系人的性别:\n");scanf("%s", con->a[pos].sex);printf("请输入联系人的年龄:\n");scanf("%d", &(con->a[pos].age));printf("请输入联系人的电话:\n");scanf("%s", con->a[pos].tel);printf("请输入联系人的地址:\n");scanf("%s", con->a[pos].addr);printf("修改成功!\n");}else {printf("该联系人不存在!!!,修改失败!!!\n");}
};void SaveContact(contact* con) {FILE* pf = fopen("contact.txt","wb");if (pf == NULL) {perror("fopen\n");return;}//可以一起性读取完fwrite(con->a, sizeof(PeoInfo), con->size, pf);//for (int i = 0; i < con->size; i++) {//	fwrite(con->a + i,sizeof(PeoInfo),1,pf);//}printf("数据保存成功!!!\n");
}//销毁通讯录数据
void DestroyContact(contact* con) {SaveContact(con);SLDestroy(con);
};

 

//test.c
#define _CRT_SECURE_NO_WARNINGS 
#include"SeqList.h"
#include<windows.h>
//void test1() {//测试
//	SL ps;
//	SLInit(&ps);
//	SLPushBack(&ps,1);
//	SLPushBack(&ps,2);
//	SLPushBack(&ps,3);
//
//
//	SLPushFront(&ps,4);
//	SLPushFront(&ps,5);
//	SLPushFront(&ps, 2); 
//	SLPrint(&ps);
//	int find = SLFind(&ps,2);
//	SLErase(&ps,find);
//	SLPrint(&ps);
//};
void menu()
{contact con;InitContact(&con);int choice = -1;do {printf("---------------------------------------------\n");printf("--------1.添加联系人 2.删除联系人------------\n");printf("--------3.查找联系人 4.修改联系人------------\n");printf("-----------5.展示所有联系人信息--------------\n");printf("----------------0.退出-----------------------\n");printf("---------------------------------------------\n");printf("输入选项:\n");scanf("%d",&choice);system("cls");switch(choice){case 1:AddContact(&con);break;case 2:DelContact(&con);break;case 3:FindContact(&con);break;case 4:ModifyContact(&con);break;case 5:ShowContact(&con);break;default:printf("输入有误,请重新输入!!!\n");break;};} while (choice);DestroyContact(&con);};int main()
{//test1();menu();return 0;
}

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

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

相关文章

构造析构理解与拷贝函数初识

1. 6个默认成员函数 ----初始化和清理{ 1.构造 2.析构 } -----拷贝复制{ 1.拷贝构造 2.赋值重载 } ------取地址重载{ 1.普通对象 2.const对象取地址 } 注&#xff1a;构造函数的目的是初始…

torchvision transforms 的二十二个方法

一、 裁剪Crop 1.随机裁剪&#xff1a;transforms.RandomCrop class torchvision.transforms.RandomCrop(size, paddingNone, pad_if_neededFalse, fill0, padding_modeconstant) 功能&#xff1a;依据给定的size随机裁剪 参数&#xff1a; size- (sequence or int)&#xff0…

珠海华发实业股份有限公司副总毛冰清莅临天府锋巢直播产业基地考察调研

3月19日&#xff0c;珠海华发实业股份有限公司副总毛冰清拜访天府锋巢直播产业基地&#xff08;以下简称天府锋巢&#xff09;&#xff0c;由产业招商总负责人姜国东进行接待。 基地建设情况 姜国东负责人介绍到&#xff0c;天府锋巢是由德商产投携手无锋科技于兴隆湖落地的成都…

Tmux 使用笔记

Tmux 是一个终端复用器&#xff08;terminal multiplexer&#xff09;&#xff0c;非常有用&#xff0c;属于常用的开发工具。 本文记录个人使用 Tmux的命令。 1. tmux简介 命令行的典型使用方式是&#xff0c;打开一个终端窗口&#xff0c;连接计算机&#xff0c;在里面输入…

Docker功能简单学习及使用

Docker是什么 Docker是一个快速构建&#xff0c;运行&#xff0c;管理应用的工具 传统基于linux安装程序较为复杂繁琐&#xff0c;使用docker可以快速的进行项目部署和管理 镜像与容器 Docker进行安装应用时&#xff0c;会自动搜索并下载应用镜像(image)。镜像不仅包含应用本…

每日一题 — 最大连续 1 的个数III

解法一&#xff1a;暴力枚举 先定义left和right双指针&#xff0c;left先固定在起始位置&#xff0c;遍历right当值等于1的时候&#xff0c;直接跳过&#xff0c;等于0的时候&#xff0c;zero计数器加一当zero等于k的时候&#xff0c;就开始记录此时最大长度是多少然后left加一…

Severt基本使用

severt是让我们自己写一些类,然后把这些类给加载Tomcat中&#xff0c;后续Tomcat收到HTTP请求(来自于浏览器)&#xff0c;就会执行到咱们上面写的代码.从而通过这些代码,完成一定的业务逻辑. 创建项目 此处创建的是一种新的项目的形式称为Maven项目,Maven是Java 中的一个的构建…

【Leetcode每日一题】模拟 - 数青蛙(难度⭐⭐)(51)

1. 题目解析 题目链接&#xff1a;1419. 数青蛙 这个问题的理解其实相当简单&#xff0c;只需看一下示例&#xff0c;基本就能明白其含义了。 2.算法原理 一、模拟青蛙叫声的基本逻辑 在模拟青蛙叫声的过程中&#xff0c;我们需要遵循一定的规则来判断何时青蛙会发出声音。…

每日一题(leetcode2529):正整数和负整数的最大计数--二分法

因为需要O&#xff08;logn&#xff09;的复杂度&#xff0c;所以考虑使用二分法&#xff0c;先找到负数里面的最大下标&#xff08;初始值定为-1&#xff09;&#xff0c;再找到第一个正数的下标&#xff08;初始值定为数组长度值&#xff09;。最后求出个数并进行比较即可。 …

题目:学习使用按位与 。

题目&#xff1a;学习使用按位与 & 。   There is no nutrition in the blog content. After reading it, you will not only suffer from malnutrition, but also impotence. The blog content is all parallel goods. Those who are worried about being cheated shoul…

Netty 入门应用之Http服务WebSocket

Netty实现Http服务 主要的变化是在初始化器中引入了新的编解码器 一些创建的类作用和Netty HelloWorld的小demo一样我这里就不再次重复了 1、Http服务端代码 public class HttpServer {public static void main(String[] args) {// 创建Reactor// 用来管理channel 监听事件 …

Hot100【十一】:最大子数组和

// 定义dp&#xff1a;以i结尾的最大子数组和 dp[i] max(dp[i-1] nums[i],nums[i]) class Solution {public int maxSubArray(int[] nums) {// 1. 不需要特殊处理// 2. 定义dpint[] dp new int[nums.length];dp[0] nums[0];int maxResult nums[0];// 3. dp递推for (int i …

微服务面试题一

1.SOA、分布式、微服务之间有什么关系和区别&#xff1f; 分布式架构是指将单体架构中的各个部分拆分&#xff0c;然后部署不同的机器或进程中去&#xff0c;SOA和微服务基 本上都是分布式架构的SOA是⼀种⾯向服务的架构&#xff0c;系统的所有服务都注册在总线上&#xff0c;…

【leetcode面试经典150题】21. 反转字符串中的单词(C++)

【leetcode面试经典150题】专栏系列将为准备暑期实习生以及秋招的同学们提高在面试时的经典面试算法题的思路和想法。本专栏将以一题多解和精简算法思路为主&#xff0c;题解使用C语言。&#xff08;若有使用其他语言的同学也可了解题解思路&#xff0c;本质上语法内容一致&…

TLF9471 - High-Speed CAN FD Transceiver

1 框图描述 2 功能描述 CAN收发器被设计用来承受汽车应用的恶劣条件&#xff0c;并支持12V应用。   SBC的控制器区域网络&#xff08;CAN&#xff09;收发器部分在汽车和工业应用中提供高速&#xff08;HS&#xff09;差分模式数据传输&#xff08;最高可达2Mbaud&#xff09…

【Java基础】BigDecimal使用避坑规范

BigDecimal使用 解决浮点型运算时&#xff0c;出现结果失真的问题&#xff0c;比如0.10.2 —示例— public class ErrorCase {public static void main(String[] args) {// 0.30000000000000004System.out.println(0.1 0.2);} }构造方法 把string转成BigDecimal把double转B…

备战蓝桥杯Day40 - 第11届python组真题 - C跑步锻炼

一、题目描述 二、思路 1、使用datetime库中的方法可以很好的解决这个问题。 2、定义起始时间和结束时间&#xff0c;判断是否是周一或者是1号&#xff0c;结果res加上相应的里程数。 3、最后输出 res 即为本题答案。 三、代码实现 import datetimestart datetime.date(2…

深度学习图像处理04:图像分类模型训练实战——动物分类

这篇博文不涉及理论知识&#xff0c;主要通过一个完整的深度学习模型训练流程&#xff0c;直观地了解深度学习图像分类任务。有关理论的部分&#xff0c;之前几篇博文已经涉及基础部分&#xff0c;之后也会对一些理论进行补充。 本文将结合代码&#xff0c;主要介绍三部分内容…

OpenHarmony应用编译 - 如何在源码中编译复杂应用(4.0-Release)

文档环境 开发环境&#xff1a;Windows 11 编译环境&#xff1a;Ubuntu 22.04 开发板型号&#xff1a;DAYU 200&#xff08;RK3568&#xff09; 系统版本&#xff1a;OpenHarmony-4.0-Release 功能简介 在 OpenHarmony 系统中预安装应用的 hap 包会随系统编译打包到镜像中&a…

SpringBoot常用注解及其使用示例

Spring Boot是一个用于快速构建Java应用程序的框架&#xff0c;它简化了Spring应用程序的创建和部署过程。 Spring Boot提供了很多注解&#xff0c;用于简化开发过程&#xff0c;提高开发效率。本文将介绍几个Spring Boot常用注解的使用案例&#xff0c;包括Controller、Reques…