队列基础练习(C语言实现)

目录

队列基础练习

用队列实现栈

用栈实现队列

设计循环队列


队列基础练习

用队列实现栈

题目链接:225. 用队列实现栈 - 力扣(LeetCode)

请你仅使用两个队列实现一个后入先出(LIFO)的栈,并支持普通栈的全部四种操作( pushtoppopempty)。
实现 MyStack 类:
void push(int x) 将元素 x 压入栈顶。
int pop() 移除并返回栈顶元素。
int top() 返回栈顶元素。
boolean empty() 如果栈是空的,返回 true ;否则,返回 false

思路解析:

本题要求用两个队列实现一个栈,队列的入队和出队顺序为先进先出,而栈的入栈和出栈顺序为后进先出,则在设计时可以参考以下思路:

因为队列满足先进先出,所以一个队列中的数据转移到另一个队列时不改变原来队列中数据的排列顺序,但是栈的数据是后进先出,所以当非空队列向空队列转移数据时只需要保留非空队列中的最后一个数据,再让该数据出队即可,而栈和队列的添加数据顺序相同,都是放在最后一个数据后的位置,所以插入数据只需要插入到当前非空队列的尾部即可

参考答案:

/** @lc app=leetcode.cn id=225 lang=c** [225] 用队列实现栈*/// @lc code=start// 队列头文件
// 定义队列数据类型
typedef int QDataType;// 定义队列的数据节点
typedef struct QueueNode
{QDataType data;struct QueueNode *next; // 下一个数据节点的位置
} QNode;// 定义管理队列的结构
typedef struct Queue
{QNode *phead; // 队列头QNode *ptail; // 队列尾,便于找尾结点,省去每次入队都需要遍历队列int size;     // 队列的数据个数
} Queue;// 初始化队列
void QueueInit(Queue *q);
// 销毁队列
void QueueDestroy(Queue *q);
// 数据入队
void QueuePush(Queue *q, QDataType x);
// 数据出队
void QueuePop(Queue *q);
// 获取队尾数据
QDataType QueueRear(Queue *q);
// 获取队头数据
QDataType QueueFront(Queue *q);
// 判断队列是否为空
bool QueueEmpty(Queue *q);
// 获取队列元素个数
int QueueSize(Queue *q);// 队列实现
// 初始化队列
void QueueInit(Queue *q)
{// 判断是否存在队列assert(q);q->phead = q->ptail = NULL;q->size = 0;
}
// 销毁队列
void QueueDestroy(Queue *q)
{// 确保有队列的存在assert(q);// 删除队列的每一个节点// 注意循环条件不要用!QueueEmpty(q),因为如果!QueueEmpty(q)只能说明队列不为空,但是q->phead是否为空不确定while (q->phead){QNode *next = q->phead->next;free(q->phead);q->phead = next;}q->phead = q->ptail = NULL;q->size = 0;
}
// 数据入队
void QueuePush(Queue *q, QDataType x)
{// 确保存在队列assert(q);// 为数据创建节点QNode *newNode = (QNode *)malloc(sizeof(QNode));assert(newNode);newNode->data = x;newNode->next = NULL;// 插入数据// 队列为空,更新头和尾节点// 队列不为空,更新尾结点// 尾插思路if (!q->ptail){q->phead = q->ptail = newNode;}else{q->ptail->next = newNode;q->ptail = q->ptail->next; // 更新ptail到新的节点}// 注意更新sizeq->size++;
}
// 数据出队
void QueuePop(Queue *q)
{// 确保有队列存在assert(q);// 如果队列为空不执行删除assert(!QueueEmpty(q));// 头删思路if (q->phead == q->ptail){// 注意考虑到最后一个指针的ptail需要置空问题,防止野指针q->ptail = NULL;}QNode *next = q->phead->next;free(q->phead);q->phead = next;// 注意更新sizeq->size--;
}
// 获取队尾数据
QDataType QueueRear(Queue *q)
{// 确保有队列存在assert(q);// 确保队列不为空assert(!QueueEmpty(q));// 返回ptail指向的位置的值return q->ptail->data;
}
// 获取队头数据
QDataType QueueFront(Queue *q)
{// 确保有队列存在assert(q);// 确保队列不为空assert(!QueueEmpty(q));// 返回phead指向的位置的值return q->phead->data;
}
// 判断队列是否为空
bool QueueEmpty(Queue *q)
{// 确保有队列的存在assert(q);//&&只有全部满足才返回为真return q->phead == NULL && q->ptail == NULL && q->size == 0;
}
// 获取队列元素个数
int QueueSize(Queue *q)
{// 确保有队列的存在assert(q);return q->size;
}typedef struct
{// 定义两个队列结构Queue q1;Queue q2;
} MyStack;MyStack *myStackCreate()
{// 初始化队列和栈MyStack *stack = (MyStack *)malloc(sizeof(MyStack));// 初始化维护队列指针QueueInit(&(stack->q1));QueueInit(&(stack->q2));return stack;
}void myStackPush(MyStack *obj, int x)
{assert(obj);// 向非空的队列中插入数据if (QueueEmpty(&(obj->q1))){QueuePush(&(obj->q2), x);}else{QueuePush(&(obj->q1), x);}
}int myStackPop(MyStack *obj)
{assert(obj);// 向非空的队列中插入数据// 获取非空队列和空队列Queue *pNotEmpty = &(obj->q1);Queue *pEmpty = &(obj->q2);if (QueueEmpty(&(obj->q1))){pNotEmpty = &(obj->q2);pEmpty = &(obj->q1);}// 非空队列中留下一个数据,剩余数据转移到空队列while (pNotEmpty->phead != pNotEmpty->ptail){QueuePush(pEmpty, QueueFront(pNotEmpty));QueuePop(pNotEmpty);}// 也可以通过size判断// while (QueueSize(pNotEmpty) > 1)// {//     QueuePush(pEmpty, QueueFront(pNotEmpty));//     QueuePop(pNotEmpty);// }int data = pNotEmpty->ptail->data;QueuePop(pNotEmpty);return data;
}int myStackTop(MyStack *obj)
{assert(obj);// 获取非空队列的队头数据if (QueueEmpty(&(obj->q1))){return obj->q2.ptail->data;}else{return obj->q1.ptail->data;}
}bool myStackEmpty(MyStack *obj)
{assert(obj);return QueueEmpty(&(obj->q1)) && QueueEmpty(&(obj->q2));
}void myStackFree(MyStack *obj)
{assert(obj);QueueDestroy(&(obj->q1));QueueDestroy(&(obj->q2));free(obj);
}/*** Your MyStack struct will be instantiated and called as such:* MyStack* obj = myStackCreate();* myStackPush(obj, x);* int param_2 = myStackPop(obj);* int param_3 = myStackTop(obj);* bool param_4 = myStackEmpty(obj);* myStackFree(obj);
*/
// @lc code=end

用栈实现队列

题目链接:232. 用栈实现队列 - 力扣(LeetCode)

请你仅使用两个栈实现先入先出队列。队列应当支持一般队列支持的所有操作( pushpoppeekempty):
实现 MyQueue 类:
void push(int x) 将元素 x 推到队列的末尾
int pop() 从队列的开头移除并返回元素
int peek() 返回队列开头的元素
boolean empty() 如果队列为空,返回 true ;否则,返回 false
说明:
只能 使用标准的栈操作 —— 也就是只有 push to top, peek/pop from top, size, 和 is empty 操作是合法的。
你所使用的语言也许不支持栈。你可以使用 list 或者 deque(双端队列)来模拟一个栈,只要是标准的栈操作即可。

思路解析:

本题和上题思路类似,但是不建议直接照搬上一题的思路,参考以下思路:

定义两个栈,但是不同于上题的两个队列(两个队列没有区分),本题中的两个栈需要作区分,一个栈作为数据出模拟队列的栈,另一个作为数据入模拟队列的栈

因为数据出栈顺序为后进先出,所以在pushST中的数据转移到popST中后会改变原数据的顺序,而改变后的顺序中数据出栈刚好和队列中的数据出队相同,所以可以区分两个不同的栈,一个专用为存储进队列的数据,另一个专用为存储出队列的数据,当popST数据全部出完后再将pushST中数据转移到popST进行下一次的数据出队

参考答案:

/** @lc app=leetcode.cn id=232 lang=c** [232] 用栈实现队列*/// @lc code=start
// 栈的实现
typedef int STDataType;
typedef struct stack
{STDataType *data;int top;      // 栈顶位置int capacity; // 元素个数
} ST;// 栈的初始化
void STInit(ST *st);
// 栈的销毁
void STDestroy(ST *st);
// 数据入栈
void STPush(ST *st, STDataType x);
// 数据出栈
void STPop(ST *st);
// 判断栈是否为空
bool STEmpty(ST *st);
// 获取栈顶元素
STDataType STTop(ST *st);
// 获取栈内数据个数
int STSize(ST *st);// 栈的初始化
void STInit(ST *st)
{// 判断是否存在队列assert(st);// 初始化队列st->data = NULL;st->top = 0; // 栈顶指针指向存储数据的下一个位置,代表栈内无数据// st->top = -1;//栈顶指针指向存储数据的位置,代表栈内无数据st->capacity = 0;
}// 栈的销毁
void STDestroy(ST *st)
{// 确保有栈的存在assert(st);// 销毁栈free(st->data);st->data = NULL;// top和capacity更改为无数据的位置st->top = st->capacity = 0;
}// 数据入栈
void STPush(ST *st, STDataType x)
{// 确保有栈的存在assert(st);// 向top位置增加数据,并使top向后移动// 需要判断栈的容量大小if (st->top == st->capacity){// 如果栈的空间为0,则开辟四个空间,如果栈容量不为0,则扩容原来容量的2倍int newCapacity = st->capacity == 0 ? 4 : st->capacity * 2;STDataType *tmp = (STDataType *)realloc(st->data, sizeof(STDataType) * newCapacity);assert(tmp);st->data = tmp;// 注意更新容量大小st->capacity = newCapacity;}// 数据压栈并改变topst->data[st->top++] = x;
}
// 数据出栈
void STPop(ST *st)
{// 确保有栈的存在assert(st);// 确保栈不会越界assert(!STEmpty(st));// 直接移动top指针,“看不见即删除”st->top--;
}
// 判断栈是否为空
bool STEmpty(ST *st)
{// 确保有栈的存在assert(st);// 栈为空返回真,栈不为空返回假return st->top == 0; // 判断表达式返回值只有1和0,如果为真返回1(true),如果为假返回0(false)
}
// 获取栈顶元素
STDataType STTop(ST *st)
{// 确保栈存在assert(st);// 确保栈不为空assert(!STEmpty(st));// top为栈内数据的下一个位置,要获取当前位置的元素需要-1操作return st->data[st->top - 1];
}// 获取栈内数据个数
int STSize(ST *st)
{assert(st);return st->top;
}typedef struct
{ST pushST;ST popST;
} MyQueue;MyQueue *myQueueCreate()
{// 初始化栈MyQueue *Queue = (MyQueue *)malloc(sizeof(MyQueue));STInit(&(Queue->pushST));STInit(&(Queue->popST));return Queue;
}void myQueuePush(MyQueue *obj, int x)
{assert(obj);// 向pushSt栈中插入数据STPush(&(obj->pushST), x);
}int myQueuePop(MyQueue *obj)
{assert(obj);// 复用myQueuePeek函数int data = myQueuePeek(obj);STPop(&(obj->popST));return data;
}int myQueuePeek(MyQueue *obj)
{assert(obj);int data = 0;// 获取队列的头元素相当于栈的顶部元素// 如果popST不为空先执行popSTif (!STEmpty(&(obj->popST))){data = STTop(&(obj->popST));return data;}//  如果pushST中有数据并且popST为空,将数据移到popST中while (!STEmpty(&(obj->pushST))){STPush(&(obj->popST), STTop(&(obj->pushST)));STPop(&(obj->pushST));}// 从popST中出数据data = STTop(&(obj->popST));return data;
}bool myQueueEmpty(MyQueue *obj)
{assert(obj);return STEmpty(&(obj->pushST)) && STEmpty(&(obj->popST));
}void myQueueFree(MyQueue *obj)
{assert(obj);STDestroy(&(obj->pushST));STDestroy(&(obj->popST));free(obj);
}/*** Your MyQueue struct will be instantiated and called as such:* MyQueue* obj = myQueueCreate();* myQueuePush(obj, x);* int param_2 = myQueuePop(obj);* int param_3 = myQueuePeek(obj);* bool param_4 = myQueueEmpty(obj);* myQueueFree(obj);
*/
// @lc code=end

设计循环队列

题目链接:622. 设计循环队列 - 力扣(LeetCode)

设计你的循环队列实现。 循环队列是一种线性数据结构,其操作表现基于 FIFO(先进先出)原则并且队尾被连接在队首之后以形成一个循环。它也被称为“环形缓冲器”。
循环队列的一个好处是我们可以利用这个队列之前用过的空间。在一个普通队列里,一旦一个队列满了,我们就不能插入下一个元素,即使在队列前面仍有空间。但是使用循环队列,我们能使用这些空间去存储新的值。
你的实现应该支持如下操作:
MyCircularQueue(k): 构造器,设置队列长度为 k 。
Front: 从队首获取元素。如果队列为空,返回 -1 。
Rear: 获取队尾元素。如果队列为空,返回 -1 。
enQueue(value): 向循环队列插入一个元素。如果成功插入则返回真。
deQueue(): 从循环队列中删除一个元素。如果成功删除则返回真。
isEmpty(): 检查循环队列是否为空。
isFull(): 检查循环队列是否已满。

思路解析:

设计一个循环队列时需要考虑如何区分什么时候代表队列为满和队列为空,因为本题可以用数组来实现,故可以考虑当最后一个数据的位置的下一个位置为第一个元素所在的位置即为队列满状态,同样,可以定义一个记录有效数据的变量,当有效数据值为0时说明循环队列为空(注意不要使用该变量判断是否未满,因为数据在存储到数组中的最后一个有效位置时,还可以因为是循环回到数组的第一个有效位置开始继续存),下面是本题的每一个函数的基本思路:

  1. 循环队列的结构体设计

在循环队列中,需要有一个队列存在,故需要一个指向数组的指针data,另外需要一个数据的位置的下一个位置,故需要一个变量rear记录该位置,而因为需要获取队头数据,故需要一个变量front记录该位置(切忌认为数组的第一个数据即为队头数据),再者需要一个变量记录当前队列中的有效数据个数size,最后因为题目并未固定循环队列的大小,故需要一个变量k来确定数组在开辟时的大小

  1. 循环队列的初始化

在循环队列的初始化函数MyCircularQueue *myCircularQueueCreate(int k)中,函数参数为循环队列的大小,所以初始化过程中不可遗忘将该k给结构中的k,另外在初始化过程中,开辟的数组大小为k+1,但是数组的最后一个有效位置(即第k个位置)在队头指针front为数组的第一个元素的位置时不存储数据,其作用是在判断数组的下一个数据的位置时不会是因为循环回到了front的位置从而使rear == front

因为数组本身的物理结构是不可循环的(即数组下标不会在下一次访问越界时直接回到开头位置,需要人为控制),所以本题的主要思路是通过模运算来代替数组的下标,而因为当前数组的有效大小为k+1,此时数组最后一个有效数据下一个位置的下标为k(也即当前的rear位置),那么构成循环队列就是让rear指针指向的下一个有效数据位置为数组第一个元素的位置,那么因为数组实际开辟了6个空间,最后一个位置的下标为5,则有规律:小于6的数值取6的模可以得到原来被除数(即余数),大于等于6的数值取6的模可以得到被除数大于6的部分(即余数),此时直接用rear当做被除数,而k+1为除数来使下标构成循环,从而达到循环队列的目的,特殊情况例如,当rear越界为6时取6的模可以直接回到数组的第一个元素的位置,即rear % (k+1)

  1. 判断队列为空和判断队列为满

队列为空说明size == 0(或者front == rear时(注意这个判断用在开辟的空间为k+1时)); 队列为满说明front == (rear + 1) % (k + 1),即当前rear所在位置的下一个位置

  1. 数据入队和数据出队

数据入队时,首先需要判断是否队列为满,如果队列为满直接返回false,不为满时向rear%(k+1)的位置添加数据,同时更新rear = (rear + 1) % (k + 1)和size;数据出队时,需要判断队列是否为空,如果队列为空则直接放回false,不为空才可以删除数据,队列删除数据时会改变头的位置,所以需要更新front,即front = (front + 1) % (k + 1),同时需要更新size

  1. 获取队列头数据和获取队列尾数据

如果队列不为空,则队列头数据即为front所在的位置的数据,否则无数据返回-1;如果队列不为空,则队列尾数据为rear所在位置的前一个位置的数据,但是注意rear为有效数据的下一个位置,所以需要获取rear的上一个位置的下标,参考取模思路,因为数组的最后一个元素下标为k,而模为k + 1,此时被除数取k + 1的模可以得到0~k值,因为rear % (k + 1)可以取到的范围已经是0 ~ k,所以此时需要加最大模值使被除数增大才可以使模从0开始,而最大增加数为k,所以此时取(rear + k) % (k + 1)即可返回到rear上一个元素的位置

  1. 循环队列空间释放

释放空间需要先释放数组的空间,再释放循环队列结构的空间

参考答案:

/** @lc app=leetcode.cn id=622 lang=c** [622] 设计循环队列*/// @lc code=start// 数组实现
// 数组实现
typedef struct
{int *data; // 存储队列数据int k;     // 队列大小int size;  // 有效数据个数int front; // 队列头int rear;  // 队列尾
} MyCircularQueue;MyCircularQueue *myCircularQueueCreate(int k)
{MyCircularQueue *Queue = (MyCircularQueue *)malloc(sizeof(MyCircularQueue));Queue->data = (int *)malloc(sizeof(int) * (k + 1));Queue->front = Queue->rear = 0;Queue->size = 0;Queue->k = k;return Queue;
}bool myCircularQueueIsEmpty(MyCircularQueue *obj)
{assert(obj);if (obj->size == 0){return true;}else{return false;}
}bool myCircularQueueIsFull(MyCircularQueue *obj)
{assert(obj);// 当rear的下一个为front时为队列满if (obj->front == (obj->rear + 1) % (obj->k + 1)){return true;}else{return false;}
}bool myCircularQueueEnQueue(MyCircularQueue *obj, int value)
{assert(obj);if (!myCircularQueueIsFull(obj)){// 队列未满时插入数据obj->data[obj->rear % (obj->k + 1)] = value;obj->rear = (obj->rear + 1) % (obj->k + 1);obj->size++;return true;}else{return false;}
}bool myCircularQueueDeQueue(MyCircularQueue *obj)
{assert(obj);if (!myCircularQueueIsEmpty(obj)){// 队列不为空时删除数据obj->front = (obj->front + 1) % (obj->k + 1);obj->size--;return true;}else{return false;}
}int myCircularQueueFront(MyCircularQueue *obj)
{assert(obj);if (!myCircularQueueIsEmpty(obj)){return obj->data[obj->front % (obj->k + 1)];}else{return -1;}
}int myCircularQueueRear(MyCircularQueue *obj)
{assert(obj);if (!myCircularQueueIsEmpty(obj)){return obj->data[(obj->rear + obj->k) % (obj->k + 1)];}else{return -1;}
}void myCircularQueueFree(MyCircularQueue *obj)
{assert(obj);free(obj->data);free(obj);
}/*** Your MyCircularQueue struct will be instantiated and called as such:* MyCircularQueue* obj = myCircularQueueCreate(k);* bool param_1 = myCircularQueueEnQueue(obj, value);* bool param_2 = myCircularQueueDeQueue(obj);* int param_3 = myCircularQueueFront(obj);* int param_4 = myCircularQueueRear(obj);* bool param_5 = myCircularQueueIsEmpty(obj);* bool param_6 = myCircularQueueIsFull(obj);* myCircularQueueFree(obj);
*/
// @lc code=end

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

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

相关文章

高通XBL阶段读取分区

【需求】: 在某些场景下,需要在XBL阶段读取分区数据,需要验证xbl阶段方案 这里主要以裸分区为例,比如oem分区。 1、创建一个1MB大小的oem.img,写入内容“test oem partition” 创建方式: dd if/dev/null …

图片Base64编码解码的优缺点及应用场景分析

title: 图片Base64编码解码的优缺点及应用场景分析 date: 2024/2/24 14:24:37 updated: 2024/2/24 14:24:37 tags: 图片Base64编码解码HTTP请求优化网页性能加载速度安全性缓存机制 随着互联网的迅猛发展,图片在网页和移动应用中的使用越来越广泛。而图片的传输和加…

python-mysql协程并发常用操作封装

目录 前言封装代码测试代码参考 前言 协程异步操作MYSQL是常用的,博主这里在GitHub上找了两个包,databases和aiomysql,第一个包除了mysql外还支持其他的数据库,且操作MYSQL时底层也是使用的aiomysql,但文档内容比较少…

Linux使用C语言获取进程信息

Linux使用C语言获取进程信息 Author: OnceDay Date: 2024年2月22日 漫漫长路,才刚刚开始… 全系列文章可查看专栏: Linux实践记录_Once_day的博客-CSDN博客 参考文档: Linux proc目录详解_/proc/mounts-CSDN博客Linux下/proc目录介绍 - 知乎 (zhihu.com)Linux内…

深入探究Python多进程编程:Multiprocessing模块基础与实战【第98篇—Multiprocessing模块】

深入探究Python多进程编程:Multiprocessing模块基础与实战 在Python编程中,多进程处理是一项关键的技术,特别是在需要处理大规模数据或执行耗时任务时。为了充分利用多核处理器的优势,Python提供了multiprocessing模块&#xff0…

Ubuntu20.04和Windows11下配置StarCraft II环境

1.Ubuntu20.04 根据下面这篇博客就可以顺利安装: 强化学习实战(九) Linux下配置星际争霸Ⅱ环境https://blog.csdn.net/weixin_39059031/article/details/117247635?spm1001.2014.3001.5506 Ubuntu下显示游戏界面目前还没有解决掉。 大家可以根据以下链接看看能…

高速DRAM的training

随着每一代接口(Interface)和存储(memory)的频率和速率的提高,信号采样以及传输变得越来越困难,因为数据眼(data eyes)越来越小。 为了帮助高速 I/O 握手,接口和存储支持越来越多的Training Modes,系统设计人员必须将这些Trainin…

联想开天昭阳N4620Z笔记本如何恢复出厂麒麟操作系统(图解)

联想开天昭阳N4620Z笔记本简单参数: 中央处理器:KX-6640MA G2 内存:8GB 固态硬盘:512GB SSD 显示器:14.0”FHD 电池:4Cell 操作系统:麒麟KOS中文RTM(试用版) 此款笔…

黑马JavaWeb开发跟学(一)Web前端开发HTML、CSS基础

黑马JavaWeb开发一.Web前端开发HTML、CSS基础 引子、Web开发介绍传统路线本课程全新路线本课程适用人群课程收获一、什么是web开发二、网站的工作流程三、网站的开发模式四、网站的开发技术 前端开发基础一、前端开发二、HTML & CSS2.1 HTML快速入门2.1.1 操作第一步第二步…

​Sqli-labs靶场第9关详解[Sqli-labs-less-9]

Sqli-labs-Less-9 前言: SQL注入的三个条件: ①参数可控;(从参数输入就知道参数可控) ②参数过滤不彻底导致恶意代码被执行;(需要在测试过程中判断) ③参数带入数据库执行。&#…

Linux---进程间通信(下)

1、System V 共享内存 原理如下图 系统调用接口介绍 int shmget(key_t key, size_t size, int shmflg) 功能:用来创建共享内存 参数 key:这个共享内存段名字,内核用key来标识共享内存size:共享内存大小shmflg:由九个权…

AMRT3D数字孪生引擎详解

AMRT 3D数字孪生引擎介绍 AMRT3D引擎是一款融合了眸瑞科技的AMRT格式与轻量化处理技术为基础,以降本增效为目标,支持多端发布的一站式纯国产自研的CS架构项目开发引擎。 引擎包括场景搭建、UI拼搭、零代码交互事件、光影特效组件、GIS/BIM组件、实时数据…

矩阵的导数运算(理解分子布局、分母布局)

矩阵的导数运算(理解分子布局、分母布局) 1、分子布局和分母布局 请思考这样一个问题,一个维度为m的向量y对一个标量x的求导,那么结果也是一个m维的向量,那么这个结果向量是行向量,还是列向量呢? 答案是&#xff1a…

Spring及工厂模式概述

文章目录 Spring 身世什么是 Spring什么是设计模式工厂设计模式什么是工厂设计模式简单的工厂设计模式通用的工厂设计 总结 在 Spring 框架出现之前,Java 开发者使用的主要是传统的 Java EE(Java Enterprise Edition)平台。Java EE 是一套用于…

《Docker 简易速速上手小册》第3章 Dockerfile 与镜像构建(2024 最新版)

文章目录 3.1 编写 Dockerfile3.1.1 重点基础知识3.1.2 重点案例:创建简单 Python 应用的 Docker 镜像3.1.3 拓展案例 1:Dockerfile 优化3.1.4 拓展案例 2:多阶段构建 3.2 构建流程深入解析3.2.1 重点基础知识3.2.2 重点案例:构建…

港科夜闻|香港科大计划建立北部都会区卫星校园完善科大创新带,发展未来创新科技 未来医药发展及跨学科教育...

关注并星标 每周阅读港科夜闻 建立新视野 开启新思维 1、香港科大计划建立北部都会区卫星校园完善“科大创新带”,发展未来创新科技、未来医药发展及跨学科教育。香港科大校长叶玉如教授在2月22日的媒体会议上表示,香港科大将在北部都会区建立卫星校园&a…

open3d KD-Tree K近邻点搜索

open3d KD-Tree K近邻点搜索 一、算法原理1.KD-Tree 介绍2.原理 二、代码三、结果1.原点云2.k近邻点搜索后的点云 四、相关数据 一、算法原理 1.KD-Tree 介绍 kd 树或 k 维树是计算机科学中使用的一种数据结构,用于在具有 k 维的空间中组织一定数量的点。它是一个…

【Spring MVC】处理器映射器:AbstractHandlerMethodMapping源码分析

目录 一、继承体系 二、HandlerMapping 三、AbstractHandlerMapping 四、AbstractHandlerMethodMapping 4.1 成员属性 4.1.1 MappingRegistry内部类 4.2 AbstractHandlerMethodMapping的初始化 4.3 getHandlerInternal()方法:根据当前的请求url,…

从git上clone项目到本地后启动时的一种报错

当我们从git上拉项目到本地之后,先install,但启动时可能会出现报错,例如上面这种报错,这时候我们需要把package.json里的vite改一下,例如改成2.6.13,之后删掉node_modules,重新install,再启动一下,就好了。…

OT 安全解决方案:探索技术

IT 和 OT 安全的融合:更好的防御方法 OT 安全解决方案下一个时代: 为了应对不断升级的威胁形势,组织认识到迫切需要采用统一的信息技术 (IT) 和运营技术 (OT) 安全方法。IT 和 OT 安全的融合代表了一种范式转变,承认这些传统孤立领…