详解数据结构之队列、循环队列(源码)

news2024/11/14 21:33:45

详解数据结构之队列、循环队列(源码)

队列属于线性表

队列:就好比如,我们在排队买东西时排队,第一个先来的第一个买,最后一个到的最后一个买,这里的队列也是满足先进先出,后进后出的规律(First In First Out),允许插入数据的一端叫做队头简称入队列,允许删除数据的一端叫做队尾简称出队列。

队列的存储形式:

  • 顺序存储结构,实现循环队列 ,队列长度时固定的

  • 链式存储结构,实现不循环队列,队列长度理论上是无限大的

两种存储结构实现的队列复杂度:

  • 时间复杂度 O(1)
  • 空间复杂度 O(1)

队列

使用链式结构实现的队列,其基本结构类似于单链表。使用next指针将每一个节点链接。主要区别在于没有使用一个指针来指向节点,这里定义了两个指针指针单链表,一个phead指针指向单链表的头,一个ptail指针指向单链表的尾。

单链表的头为队列的队头,单链表的尾为队列的队尾。

在这里插入图片描述

有了指针指向链表的最后一个节点,就不再需要使用循环遍历到链表的最后一个节点,将入栈的时间复杂度从O(N)优化到O(1)。

typedef int QueueDataType;
typedef struct QueueNode//节点
{
	QueueDataType val;
	struct QueueNode* next;

}QueueNode;
struct Queue
{
	QueueNode* phead;//指向队头的指针
	QueueNode* ptail;//指向队尾的指针
	int size;//统计单链表的节点个数
};
typedef struct Queue Queue;

功能实现

//初始化
void QueueInit(Queue* p);
//销毁
void QueueDestory(Queue* p);
//入队列,队尾,不就是尾插
void QueuePush(Queue* p, QueueDataType x);
//出队列,队头
void QueuePop(Queue* p);
//取队头数据
QueueDataType QueueFront(Queue* p);
//取队尾数据
QueueDataType QueueBack(Queue* p);
//判空
bool QueueEmpty(Queue* p);
//获取有效数据个数
int QueueSize(Queue* p);

初始化、销毁

初始化

初始化指向队列的两个指针,和对统计节点个数大小的size,由于传递的是地址就不需要返回值。

//初始化
void QueueInit(Queue* p)
{
	assert(p);
	p->phead = p->ptail = NULL;
	p->size = 0;
}

销毁

将队列的节点一一销毁,其操作逻辑与单链表相似。

销毁链表,需要对每一个节点进行释放,而只使用一个指针pcur,释放当前的节点就找不到下一个节点了,这里需要使用两个指针。

一个指针用来释放(pcur),一个指针用来指向待释放之后的节点(next)。

当释放完pcur节点后,更新pcur的位置 pcur = next;,用来释放下一个节点,next指针也需要更新用来指向下一个节点 next = pcur->next;,用来对pcur进行更新。直到pcur指向空指针时释放完所有节点,跳出循环。而 phead和ptail指针,还没有置为空,这时候时野指针,最后一步 p->phead = p->ptail = NULL;

void QueueDestory(Queue* p)
{
	assert(p);
	QueueNode* pcur = p->phead;
	while (pcur)
	{
		QueueNode* next = pcur->next;
		free(pcur);
		pcur = next;
	}
	p->phead = p->ptail = NULL;
	p->size = 0;
}

判空

判断队列的节点是否为空并返回一个布尔值。

如上对队列的初始化,两个头尾指针指向的都为空,此时队列就是空,队列为空返回true,不为返回false。

函数起始别忘了对指针p判空,为空则说明队列不存在了。

//判空
bool QueueEmpty(Queue* p)
{
	assert(p);
	return p->ptail == NULL && p->phead == NULL;
}

入队列、出队列

入队列

想要进行尾插首先得有一个指针指向最后一个节点,然后将创建的新节点插入到该节点后面,最后更新ptail指针指向的位置
在这里插入图片描述

入队列有两种情况:

  • 队列为空

此时phead和ptail都指向空,插入一个新节点,phead和ptail均指向它。

  • 队列不为空

在ptail指针后插入一个新节点,通过节点的next指针连接,然后更新ptail指针,让其指向新的尾。
在这里插入图片描述

最后别忘了将统计节点个数的size加1

//入队列,队尾,不就是单链表的尾插
void QueuePush(Queue* p, QueueDataType x)
{
	assert(p);

	QueueNode* newnode = (QueueNode*)malloc(sizeof(QueueNode));//创建新节点
	if (newnode == NULL)//判空,有无开辟成功
	{
		perror("malloc");
		return;
	}
	newnode->val = x;//赋值
	newnode->next = NULL;
	
	if (p->phead == NULL)//phead和ptail为空时
	{
		p->phead = p->ptail = newnode;
	}
	else//两者不为空
	{
		p->ptail->next = newnode;
		p->ptail = newnode;
	}
	p->size++;//别忘了记录新加入的节点
}

出队列

出队列的逻辑并不复杂,前提是指针p不为空,为空则说明队列不存在、队列不为空,为空则说明没有节点可删,接下来就是对空指针解引用。

它同样分为两种情况:

  • 只有一个节点

即phead和ptail指向同一个节点时,将该节点释放,然后将phead和ptail指针指向空。

  • 有许多个节点

一,保存phead之后的节点 QueueNode* Next = phead->next;二,然后释放第一个节点 free(phead);三,最后将 Next 赋给 phead,更新头节点的位置。

最后将size减1
在这里插入图片描述

//出队列,队头,这不就是单链表的头删吗
void QueuePop(Queue* p)
{
	assert(p);
	assert(!QueueEmpty(p));
	if (p->phead == p->ptail)
	{
		free(p->phead);
		p->phead = p->ptail == NULL;
	}
	else
	{
		QueueNode* Next = p->phead->next;
		free(p->phead);
		p->phead = Next;
	}
	p->size--;
}

取队头数据、取队尾数据

取对头数据

取对头数据那是相当简易,只需要将头指针指向的节点的value值返回即可。需要注意的是对指针p和队列的判空,以及返回数据的类型。

//取队头数据
QueueDataType QueueFront(Queue* p)
{
	assert(p);
	assert(!QueueEmpty(p));
	return p->phead->val;
}

取队尾数据

有了之前定义的ptail指针,就不需要像单链表一个一个节点的遍历到最后一个节点,取队尾数据,只需将尾指针指向的节点的value值返回即可,它需要注意的点与取对头数据相同。

//取队尾数据
QueueDataType QueueBack(Queue* p)
{
	assert(p);
	assert(!QueueEmpty(p));
	return p->ptail->val;
}

取队列有效数据个数

将队列的size返回,返回值为int,因为它只是用来统计个数的。

//获取有效数据个数
int QueueSize(Queue* p)
{
	assert(p);
	return p->size;
}

源码

Queue.h

#pragma once
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <assert.h>

typedef int QueueDataType;
typedef struct QueueNode
{
	QueueDataType val;
	struct QueueNode* next;

}QueueNode;
struct Queue
{
	QueueNode* phead;//指向队头的指针
	QueueNode* ptail;//指向队尾的指针
	int size;
};
typedef struct Queue Queue;
 
//初始化
void QueueInit(Queue* p);
//销毁
void QueueDestory(Queue* p);
//入队列,队尾,不就是尾插
void QueuePush(Queue* p, QueueDataType x);
//出队列,队头
void QueuePop(Queue* p);
//取队头数据
QueueDataType QueueFront(Queue* p);
//取队尾数据
QueueDataType QueueBack(Queue* p);
//判空
bool QueueEmpty(Queue* p);
//获取有效数据个数
int QueueSize(Queue* p);

Queue.c

#include "Queue.h"
//初始化
void QueueInit(Queue* p)
{
	assert(p);
	p->phead = p->ptail = NULL;
	p->size = 0;
}
//判空
bool QueueEmpty(Queue* p)
{
	assert(p);
	return p->ptail == NULL && p->phead == NULL;
}
//入队列,队尾
void QueuePush(Queue* p, QueueDataType x)
{
	assert(p);
	QueueNode* newnode = (QueueNode*)malloc(sizeof(QueueNode));
	if (newnode == NULL)
	{
		perror("malloc");
		return;
	}
	newnode->val = x;
	newnode->next = NULL;
	if (p->phead == NULL)
	{
		p->phead = p->ptail = newnode;
	}
	else
	{
		p->ptail->next = newnode;
		p->ptail = newnode;
	}
	p->size++;
}
//出队列,队头
void QueuePop(Queue* p)
{
	assert(p);
	assert(!QueueEmpty(p));
	if (p->phead == p->ptail)
	{
		free(p->phead);
		p->phead = p->ptail == NULL;
	}
	else
	{
		QueueNode* Next = p->phead->next;
		free(p->phead);
		p->phead = Next;
	}
	p->size--;
}
//取队头数据
QueueDataType QueueFront(Queue* p)
{
	assert(p);
	assert(!QueueEmpty(p));
	return p->phead->val;
}
//取队尾数据
QueueDataType QueueBack(Queue* p)
{
	assert(p);
	assert(!QueueEmpty(p));
	return p->ptail->val;
}
//获取有效数据个数
int QueueSize(Queue* p)
{
	assert(p);
	return p->size;
}
//销毁
void QueueDestory(Queue* p)
{
	assert(p);
	QueueNode* pcur = p->phead;
	while (pcur)
	{
		QueueNode* next = pcur->next;
		free(pcur);
		pcur = next;
	}
	p->ptail = p->ptail = NULL;
	p->size = 0;
}

循环队列

循环队列,就类似将链表的头尾节点链接在一起了。

使用顺序存储结构的优缺点:

  • 数组支持随机访问,在O(1)时间内访问任意元素(速度)
  • 数组的操作和使用简单好理解
  • 不需要使用额外空间存储节点指针

  • 数组的大小在创建时就确定了
typedef int CQDataType;
typedef struct CircularQueue
{
	CQDataType* arr;
	int front;//指向队头元素
	int rear;//指向队尾的下一个位置
	int capacity;//空间大小
}CQueue;

在这里插入图片描述

初始情况下,front和rear指向同体块空间时,队列为空,入队列后front不变,rear向后加1,如下图。
在这里插入图片描述

当插入a5时rear将指向数组外的空间,然后在插入a6,rear继续指向数组之外的空间。纳尼??都指向数组之外的空间了,那不是越界访问了吗?

在这里插入图片描述

现在假设不存在这种问题,插入a5数据后rear指向front,此时有没有发现又乱套了。front和rear指向了同一块空间,前文以及说过当frong和rear指向同一块空间时队列为空,那这种情况又该咋办呢~。
在这里插入图片描述

为了解决以上两种情况,这里将数组空出一块空间,不插入a5此时队列就是满队列的情况。

而想要实现rear为4时在加上1能够循环到0,可以使用求模运算操作符。

在这里插入图片描述

初始条件下开辟给数组capacity+1的空间,多余的1是给rear用的,防止font和rear相等无法判断是否满队列还是空队列的情况。假设此时capacity为4,那就得开辟空间大小为5的数组,如上图。

pcq->rear + 1) % (pcq->capacity + 1) == pcq->front;如上图,此时rear为4,capacity为4,都加1后 5 % 5结果为刚好等于front此时满队列,而不是如同之前的情况,rear和front的尴尬情况。

在这里插入图片描述

实现rear加1后能够在 0 ~ 4内循环,而不造成数组越界访问使用取模操作符 ,如上图,当rear为4时加1为5,但它指向了0,根据pcq->rear = pcq->rear % pcq->capacity + 1;不能得出 此时 5 % 5的结果为0,然后将0赋给rear重置了rear的位置。

功能实现

//开辟空间,n指开辟大小
void CQCreat2(CQueue* pcq, int n);
//判断队列空否
bool CQEmpty(CQueue* pcq);
//判断队列满否
bool CQFull(CQueue* pcq);
//入队列
void CQPush(CQueue* pcq, CQDataType x);
//出队列
void CQPop(CQueue* pcq);
//取队头元素
CQDataType CQFront(CQueue* pcq);
//取队尾元素
CQDataType CQBACK(CQueue* pcq);
//销毁队列
void CQDestory(CQueue* pcq);

开辟空间、销毁队列

开辟空间、初始化

开辟大小为n + 1的空间,让后将front和rear置0,将n赋给capacity,表示了rear和front的最大取值。

void CQCreat2(CQueue* pcq, int n)
{
	pcq->arr = (CQDataType*)malloc(sizeof(CQDataType) * (n + 1));
	pcq->front = pcq->rear = 0;
	pcq->capacity = n;
}

销毁队列

销毁队列,将arr数组释放,让后置空(此时为野指针),需要注意的是对 pcq->arr,的判空,若它为空指针就不需要释放数组。

//销毁队列
void CQDestory(CQueue* pcq)
{
	assert(pcq);
    if(pcq->arr)
		free(pcq->arr);
	pcq->arr = NULL;
	pcq->front = pcq->rear = pcq->capacity = 0;
}

判断队列满否、空否

判断队列是否被放满

前文以及提过,判空后队列满返回真,队列未满返回假,使用assert断言避免pcq为空指针,从而造成对空指针的解引用。

//判断队列满否
bool CQFull(CQueue* pcq)
{
	assert(pcq);
	return (pcq->rear + 1) % (pcq->capacity + 1) == pcq->front;
}

判断队列是否为空队列

front与rear相等队列为空返回真,不相等返回假。

//判断队列空否
bool CQEmpty(CQueue* pcq)
{
	assert(pcq);
	return pcq->front == pcq->rear;//相等为空
}

入队列、出队列

入队列

入队列不难理解,只需要找到对应得数组标然后放进去即可。但需要严重关注的是在入队列前对数组是否满了进行判断,以及成功入了一个元素rear加1后,对rear重新修正大小,避免造成数组越界。

//入队列
void CQPush(CQueue* pcq, CQDataType x)
{
	assert(pcq);
	assert(!CQFull(pcq));
	pcq->arr[pcq->rear++] = x;
	pcq->rear %= pcq->capacity + 1;
}

出队列

出队列,同理出队列,想要出队列那就不可能对一个空队列出元素,那得先调用判断队列是否为空队列的函数,然后在出队列,想要实现出队列,只需要让front加1即可,前front指向的数据被放弃掉是无效的,将front加1后同rear一样需要对其重新修正大小,避免造成数组越界。

//出队列
void CQPop(CQueue* pcq)
{
	assert(pcq);
	assert(!CQEmpty(pcq));
	pcq->front++;
	pcq->front %= pcq->capacity + 1;
}

取对头数据、取队尾数据

取对头数据

只需将front指向的数据返回。

//取队头元素
CQDataType CQFront(CQueue* pcq)
{
	assert(pcq);
	assert(!CQEmpty(pcq));
	return pcq->arr[pcq->front];
}

取队尾数据

只需将rear指向的数据返回。

//取队尾元素
CQDataType CQBACK(CQueue* pcq)
{
	assert(pcq);
	assert(!CQEmpty(pcq));
	int ret = pcq->rear - 1;
	if (pcq->rear == 0)
	{
		ret = pcq->capacity;
	}
	return pcq->arr[ret];
}

源码

CircularQueue.h

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

typedef int CQDataType;
typedef struct CircularQueue
{
	CQDataType* arr;
	int front;
	int rear;
	int capacity;
}CQueue;

//开辟空间,n指开辟大小
CQueue* CQCreat(int n);
void CQCreat2(CQueue* pcq, int n);
//判断队列空否
bool CQEmpty(CQueue* pcq);
//判断队列满否
bool CQFull(CQueue* pcq);
//入队列
void CQPush(CQueue* pcq, CQDataType x);
//出队列
void CQPop(CQueue* pcq);
//取队头元素
CQDataType CQFront(CQueue* pcq);
//取队尾元素
CQDataType CQBACK(CQueue* pcq);
//销毁队列
void CQDestory(CQueue* pcq);

CircularQueue.c

#include "Queues.h"
//开辟空间,n指开辟大小
void CQCreat2(CQueue* pcq, int n)
{
	pcq->arr = (CQDataType*)malloc(sizeof(CQDataType) * (n + 1));
	pcq->front = pcq->rear = 0;
	pcq->capacity = n;
}
//判断队列空否
bool CQEmpty(CQueue* pcq)
{
	assert(pcq);
	return pcq->front == pcq->rear;//相等为空
}
//判断队列满否
bool CQFull(CQueue* pcq)
{
	assert(pcq);
	return (pcq->rear + 1) % (pcq->capacity + 1) == pcq->front;
}
//入队列
void CQPush(CQueue* pcq, CQDataType x)
{
	assert(pcq);
	assert(!CQFull(pcq));
	pcq->arr[pcq->rear++] = x;
	pcq->rear %= pcq->capacity + 1;
}
//出队列
void CQPop(CQueue* pcq)
{
	assert(pcq);
	assert(!CQEmpty(pcq));
	pcq->front++;
	pcq->front %= pcq->capacity + 1;
}
//取队头元素
CQDataType CQFront(CQueue* pcq)
{
	assert(pcq);
	assert(!CQEmpty(pcq));
	return pcq->arr[pcq->front];
}
//取队尾元素
CQDataType CQBACK(CQueue* pcq)
{
	assert(pcq);
	assert(!CQEmpty(pcq));
	int ret = pcq->rear - 1;
	if (pcq->rear == 0)
	{
		ret = pcq->capacity;
	}
	return pcq->arr[ret];
}
//销毁队列
void CQDestory(CQueue* pcq)
{
	assert(pcq);
	free(pcq->arr);
	pcq->arr = NULL;
	pcq->front = pcq->rear = pcq->capacity = 0;
}


Type x)
{
	assert(pcq);
	assert(!CQFull(pcq));
	pcq->arr[pcq->rear++] = x;
	pcq->rear %= pcq->capacity + 1;
}
//出队列
void CQPop(CQueue* pcq)
{
	assert(pcq);
	assert(!CQEmpty(pcq));
	pcq->front++;
	pcq->front %= pcq->capacity + 1;
}
//取队头元素
CQDataType CQFront(CQueue* pcq)
{
	assert(pcq);
	assert(!CQEmpty(pcq));
	return pcq->arr[pcq->front];
}
//取队尾元素
CQDataType CQBACK(CQueue* pcq)
{
	assert(pcq);
	assert(!CQEmpty(pcq));
	int ret = pcq->rear - 1;
	if (pcq->rear == 0)
	{
		ret = pcq->capacity;
	}
	return pcq->arr[ret];
}
//销毁队列
void CQDestory(CQueue* pcq)
{
	assert(pcq);
	free(pcq->arr);
	pcq->arr = NULL;
	pcq->front = pcq->rear = pcq->capacity = 0;
}

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

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

相关文章

如果用MATLAB函数delayseq可以对分数延时,但是延时后波形较原波形有幅度上的改变

&#x1f3c6;本文收录于《CSDN问答解答》专栏&#xff0c;主要记录项目实战过程中的Bug之前因后果及提供真实有效的解决方案&#xff0c;希望能够助你一臂之力&#xff0c;帮你早日登顶实现财富自由&#x1f680;&#xff1b;同时&#xff0c;欢迎大家关注&&收藏&…

Adobe国际认证详解-视频设计认证专家行业应用场景解析

在当今数字化时代&#xff0c;视频设计已成为各行各业不可或缺的一环。而视频设计认证专家&#xff0c;作为经过Adobe国际认证体系严格考核的专业人才&#xff0c;更是行业内炙手可热的存在。他们凭借深厚的视频设计理论基础和实践经验&#xff0c;为行业提供了高质量的视频设计…

ROS2中间件

ROS2 是重新设计的 Robot Operating System&#xff0c;无论从用户API接口到底层实现都进行了改进。这里主要关注ROS2 的中间件。 1. 通信模式 ROS2 使用DDS协议进行数据传输&#xff0c;并通过抽象的rmw&#xff0c;支持多个厂家的DDS实现&#xff08;FastDDS&#xff0c;Cyc…

Django 执行原生SQL

在Django中&#xff0c;你可以使用Raw SQL queries来执行原生的SQL查询。这对于需要进行复杂查询或Django的ORM无法满足的查询非常有用。 1&#xff0c;添加模型 Test/app11/models.py from django.db import modelsclass Post(models.Model):title models.CharField(max_le…

arthas:介绍

文章目录 一、Arthas&#xff08;阿尔萨斯&#xff09;能为你做什么&#xff1f;二、运行环境要求三、快速安装四、卸载五、通过浏览器连接arthas 一、Arthas&#xff08;阿尔萨斯&#xff09;能为你做什么&#xff1f; Arthas是Alibaba开源的Java诊断工具&#xff0c;深受开发…

buu--web做题(4)

目录 [BJDCTF2020]ZJCTF&#xff0c;不过如此 [BUUCTF 2018]Online Tool [BJDCTF2020]ZJCTF&#xff0c;不过如此 <?phperror_reporting(0); $text $_GET["text"]; $file $_GET["file"]; if(isset($text)&&(file_get_contents($text,r)&q…

vue3运行若依前后台项目步骤(2024-07-19)

环境配置 1、jdk > 1.8 (我的1.8&#xff09; 2、mysql >5.7 (我的5.8&#xff09; 3、navicat (数据库管理器&#xff0c;连接mysql使用 ,我的是15) 4、mysql&#xff08;数据库&#xff0c;我的5.0&#xff09; 4、npm (我的是18.20.0) 5、idea编辑器,webtorm &#x…

Unity UGUI 之 Graphic Raycaster

本文仅作学习笔记与交流&#xff0c;不作任何商业用途 本文包括但不限于unity官方手册&#xff0c;唐老狮&#xff0c;麦扣教程知识&#xff0c;引用会标记&#xff0c;如有不足还请斧正 首先手册连接如下&#xff1a; Unity - Manual: Graphic Raycaster 笔记来源于&#xff…

Mike Ferguson:我在麻省理工学院人工智能研究实验室工作一年学到了 5 件事

Mike Ferguson &#xff0c;麻省理工学院大脑和认知科学系 (MIT BCS) 担任研究软件工程师 / ML 工程师。专门研究 Brain-Score&#xff08;一种衡量类脑 AI 的工具&#xff09;。他于 2021 年春季毕业于弗吉尼亚大学&#xff0c;获得计算机科学和应用数学学士学位&#xff0c;以…

【数字电路学习新助手】掌握电路仿真软件,开启数字电路知识的新篇章

在信息科技日新月异的今天&#xff0c;数字电路知识的重要性不言而喻。无论是通信工程、计算机科学与技术&#xff0c;还是电子信息技术等领域&#xff0c;数字电路都是基础中的基础。然而&#xff0c;对于初学者来说&#xff0c;数字电路的学习往往充满了挑战。幸运的是&#…

JUC 06 锁 开始

01.volatile 02.synchronized 03.lock

深入分析 Android ContentProvider (一)

文章目录 深入分析 Android ContentProvider (一)1. Android 中的 ContentProvider 设计说明1.1. ContentProvider 的设计初衷1.2. ContentProvider 的基本结构1.3. ContentProvider 的实现示例&#xff1a;实现一个简单的 ContentProvider 1.4. ContentProvider 的使用 2. Con…

小柴带你学AutoSar系列三、标准和规范篇(1)General

flechazo 小柴冲刺嵌入式系统设计师系列总目录 小柴带你学AutoSar总目录 缘起 一个小小的介绍啦&#xff0c;逐字逐句读规范。&#x1f61c; 不求能记住多少❤️ 只是希望将知识串起来&#xff0c;用到的时候能快速找到就好啦&#xff01; 一起学习AUTOSAR的规范吧 下面呢…

matlab中plot的一些用法

文章目录 一、基本用法二、绘制多个数据集三、设置线型、颜色四、添加标题和标签五、添加图例六、设置轴范围七、绘制网格八、 在同一图中绘制多个子图九、绘制带误差条的图十、绘制半对数图和对数图十一、绘制填充区域图十二、综合案例 一、基本用法 x 0:0.1:10; y sin(x);…

主流大数据调度工具DolphinScheduler之数据采集

今天继续给大家分享主流大数据调度工具DolphinScheduler&#xff0c;以及数据的ETL流程。 一&#xff1a;调度工具DS 主流大数据调度工具DolphinScheduler&#xff0c; 其定位&#xff1a;解决数据处理流程中错综复杂的依赖关系 任务支持类型&#xff1a;支持传统的shell任…

甲骨文闲置ARM实例防回收的方法

前几日挖了个大坑&#xff0c;今天补一下&#xff0c;谈谈甲骨文闲置实例如何防止回收。 回收原则 2022年11月16日 Oracle添加声明&#xff1a; 从 2022 年 11 月 24 日开始&#xff0c;您闲置的 Always Free 计算实例可能会停止。巴拉巴拉&#xff0c;您还可以随时升级您的帐…

Java数据结构(三)——顺序表

文章目录 顺序表前置知识ArrayList的构造ArrayList的常用方法ArrayList的遍历ArrayList的扩容机制ArrayList的模拟实现ArrayList的相关练习 顺序表 前置知识 顺序表是线性表的一种&#xff08;底层是数组&#xff09;&#xff0c;另一种是链表&#xff0c;说到线性表&#xf…

Three.JS飞入定位模型的位置。

源码 flyTo(object, gltfthis) {if (object undefined || object null) {return;}const box3 new THREE.Box3();box3.expandByObject(object); // 计算模型包围盒const size new THREE.Vector3();box3.getSize(size); // 计算包围盒尺寸const center new THREE.Vector3();…

【stm32项目】基于stm32智能宠物喂养(完整工程资料源码)

基于STM32宠物喂养系统 前言&#xff1a; 随着人们生活幸福指数的提高&#xff0c;越来越多的家庭选择养宠物来为生活增添乐趣。然而&#xff0c;由于工作等原因&#xff0c;许多主人无法及时为宠物提供充足的食物与水。为了解决这一问题&#xff0c;我设计了一款便捷的宠物喂…

如何搭建一个RADIUS服务器?

1. 系统环境 1.1.操作系统 Ubuntu-20.04.1 &#xff08;kernel: 5.15.0-58-generic&#xff09; 1.2.所需软件 FreeRADIUS MariaDB 1.3.注意事项 本文提到的所有操作&#xff0c;都是以root 身份执行&#xff1b; 2. FreeRADIUS的安装 2.1. 安装FreeRADIUS服务器程序 以…