队列的实现和OJ练习(c语言)

目录

概念

队列的实现

利用结构体存放队列结构

为什么单链表不使用这种方法?

初始化队列

小提示:

队尾入队列

队头出队列

获取队头元素

获取队尾元素

获取队列中有效元素个数

检测队列是否为空

销毁队列

最终代码

循环队列 

队列的OJ题

用队列实现栈

用栈实现队列


概念

只允许在一端进行插入数据操作,在另一端进行删除数据操作的特殊线性表,队列具有先进先出FIFO(First In First Out) 的特性,进行插入操作的一端称为队尾,进行删除操作的一端称为队头

队列的实现

tip:队列也可以数组和链表的结构实现,使用链表的结构实现更优一些,因为如果使用数组的结构,出队列在数组头上出数据,效率会比较低。

利用结构体存放队列结构

        我们之前在实现单链表的时候使用到了二级指针来达到修改头尾结点的效果,这样会增加代码复杂性和理解难度......

#pragma once
#include<stdio.h>
#include<assert.h>
#include<stdlib.h>
#include<stdbool.h>//链式结构:表示队列
typedef int QDataType;
typedef struct QueueNode
{QDataType val;struct QueueNode* next;
}QNode;//队列的结构(使用结构体避免了二级指针的使用)
typedef struct Queue
{QNode* phead;QNode* ptail;int size;        //存放队列大小
}Queue;

        现在我们依然选择用单链表实现队列,但是我们将指向链表的头尾结点的指针信息都存放在一个结构体中,这样就起到了简化参数传递的作用。即在初始化队列时只需分配一个包含头尾节点、队列大小等信息的结构对象,并将其作为参数传递给相关函数。这样就可以直接通过访问该结构对象中的相应成员变量来修改或获取所需信息

为什么单链表不使用这种方法?

        这是因为在单链表中,使用结构体来表示整个单链表可能会带来一些不必要的复杂性,并且没有明显的好处,相比于这种方法使用二级指针会有以下有点:

1. 简化插入和删除操作:由于插入或删除操作需要调整前后两个节点之间的连接关系(而队列不需要考虑在指定位置插入的问题),将头尾结点分别存放在结构体中可能需要更多额外处理步骤才能保持正确连接关系。

2. 节省内存空间:如果每个节点都包含了头尾信息,则会导致额外占用内存空间,并且增加了维护数据一致性所需付出成本。

3. 降低复杂度:通过仅保存对首元素(即头部)进行引用,在大多数情况下足以满足对单链表进行各种操作所需求。这样可以简化代码逻辑并提高代码可读性与可维护性。

初始化队列

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

实现步骤: 

1、利用断言检测队列指针的有效性

2、有效则将队列初始化为空队列,即将指向队头元素和队尾元素的指针及队列元素个数都置为空

小提示:

这个看不看都行

队尾入队列

//队尾入队列
void QueuePush(Queue* pq, QDataType x)
{assert(pq);QNode* newnode = (QNode*)malloc(sizeof(QNode));if (newnode == NULL){perror("malloc fail");return;}newnode->val = x;newnode->next = NULL;if (pq->ptail == NULL){pq->ptail = pq->phead = newnode;}else{pq->ptail->next = newnode;pq->ptail = newnode;}pq->size++;
}

实现步骤: 

1、利用断言检测队列指针的有效性

2、malloc申请新的结点空间,并进行开辟失败的判断

3、若开辟成功则向链表结点中插入有效数据,以及下一个结点的置空

4、检测队列是否为空,若为空则将新申请的结点作为队列的第一个元素,令指向队头和队尾的指针指向该元素

5、若不为空,则将指向队尾元素的指针指向新元素,同时将指向队尾的指针向后移动指向该元素

6、完成一次队尾入队操作后,将队列元素个数加一

队头出队列

// 对头出队列
void QueuePop(Queue* pq)
{assert(pq);assert(pq->phead);QNode* del = pq->phead;pq->phead = pq->phead->next;free(del);del = NULL;if (pq->phead == NULL)pq->ptail = NULL;pq->size--;
}

实现步骤: 

1、利用断言检测队列指针的有效性

2、利用断言检测队列头元素不为空

3、利用临时指针变量删除队头结点,并将指向队头结点指针向后移动,最后释放该指针并置空

4、队头元素出队列后,若头指针变为空,则将尾指针也变为空

获取队头元素

//获取队头元素
QDataType QueueFront(Queue* pq)
{assert(pq);// assert(pq->phead);return pq->phead->val;
}

实现步骤: 

1、利用断言检测队列指针的有效性

2、利用断言检测队列头元素不为空

3、返回此时队头元素的值

获取队尾元素

//获取队头元素
QDataType QueueFront(Queue* pq)
{assert(pq);// assert(pq->phead);return pq->phead->val;
}

实现步骤: 

1、利用断言检测队列指针的有效性

2、利用断言检测队列头元素不为空

3、返回此时队尾元素的值

获取队列中有效元素个数

//获取队列中有效元素个数
int QueueSize(Queue* pq)
{assert(pq);return pq->size;
}

实现步骤: 

1、利用断言检测队列指针的有效性

2、返回结构体中的size值

检测队列是否为空

//检测队列是否为空
bool QueueEmpty(Queue* pq)
{assert(pq);return pq->phead == NULL;
}

实现步骤: 

1、利用断言检测队列指针的有效性

2、返回对pq->phead == NULL的判断结果,返回结果为真则队列为空,为假则队列非空

销毁队列

//销毁队列
void QueueDestroy(Queue* pq)
{assert(pq);QNode* cur = pq->phead;while (cur){QNode* next = cur->next;free(cur);cur = next;}pq->phead = pq->ptail = NULL;pq->size = 0;
}

实现步骤: 

1、利用断言检测队列指针的有效性

2、遍历每一个队头元素并销毁,最后将头尾指针及队列元素数量均置为空

最终代码

Queue.h文件

#pragma once
#include<stdio.h>
#include<assert.h>
#include<stdlib.h>
#include<stdbool.h>//链式结构:表示队列
typedef int QDataType;
typedef struct QueueNode
{QDataType val;struct QueueNode* next;
}QNode;//队列的结构(使用结构体避免了二级指针的使用)
typedef struct Queue
{QNode* phead;QNode* ptail;int size;
}Queue;//初始化队列
void QueueInit(Queue* pq);//队尾入队列
void QueueDestroy(Queue* pq);//队头出队列
void QueuePush(Queue* pq, QDataType x);//获取队头元素
void QueuePop(Queue* pq);//获取队尾元素
QDataType QueueFront(Queue* pq);//获取队列中有效元素个数
QDataType QueueBack(Queue* pq);//检测队列是否为空
bool QueueEmpty(Queue* pq);//销毁队列
int QueueSize(Queue* pq);

Queue.c文件

#include"Queue.h"//初始化队列
void QueueInit(Queue* pq)
{assert(pq);pq->phead = pq->ptail = NULL;pq->size = 0;
}//销毁队列
void QueueDestroy(Queue* pq)
{assert(pq);QNode* cur = pq->phead;while (cur){QNode* next = cur->next;free(cur);cur = next;}pq->phead = pq->ptail = NULL;pq->size = 0;
}//队尾入队列
void QueuePush(Queue* pq, QDataType x)
{assert(pq);QNode* newnode = (QNode*)malloc(sizeof(QNode));if (newnode == NULL){perror("malloc fail");return;}newnode->val = x;newnode->next = NULL;if (pq->ptail == NULL){pq->ptail = pq->phead = newnode;}else{pq->ptail->next = newnode;pq->ptail = newnode;}pq->size++;
}// 对头出队列
void QueuePop(Queue* pq)
{assert(pq);// assert(pq->phead);QNode* del = pq->phead;pq->phead = pq->phead->next;free(del);del = NULL;if (pq->phead == NULL)pq->ptail = NULL;pq->size--;
}//获取队头元素
QDataType QueueFront(Queue* pq)
{assert(pq);// assert(pq->phead);return pq->phead->val;
}//获取队尾元素
QDataType QueueBack(Queue* pq)
{assert(pq);// assert(pq->ptail);return pq->ptail->val;
}//检测队列是否为空
bool QueueEmpty(Queue* pq)
{assert(pq);return pq->phead == NULL;
}//获取队列中有效元素个数
int QueueSize(Queue* pq)
{assert(pq);return pq->size;
}

test.c文件

#include "Queue.h"int main()
{Queue q;QueueInit(&q);QueuePush(&q, 1);QueuePush(&q, 2);QueuePush(&q, 3);printf("%d ", QueueFront(&q));QueuePop(&q);printf("%d ", QueueFront(&q));QueuePop(&q);QueuePush(&q, 4);QueuePush(&q, 5);while (!QueueEmpty(&q)){printf("%d ", QueueFront(&q));QueuePop(&q);}QueueDestroy(&q);return 0;
}

循环队列 

概念:循环队列是一种特殊的队列数据结构,它通过使用固定大小的数组来实现。与普通队列不同的是,在循环队列中,当尾指针(rear)达到数组末尾时,会从数组开头重新开始存储元素

优点:充分利用出队操作后释放出来的空间,避免频繁地移动元素

适用场景:循环队列常用于需要高效处理连续输入输出流数据的场景,如缓冲区、任务调度等

关于循环队列的实现放在下一篇文章......

队列的OJ题

用队列实现栈

225. 用队列实现栈 - 力扣(LeetCode)

具体解题思路如下:

1、题目要求使用两个队列,但队列的基本功能需要自己实现

2、利用栈的结构体存储两个队列的头尾指针及队列元素个数的信息

3、为队列申请结点空间并利用QueueInit函数初始化队列

4、 入栈时,利用if判断谁为非空队列后,将要入栈的元素尾插进非空队列中(QueueBack函数),出栈的大体过程如下图所示:

5、出栈时,为了将队列的最后一个元素先排出,就需要让原来存储有效数据的队列的前N-1个元素放入空的队列中,然后再将元队列中的最后一个元素排出,两个队列的作用是来回切换的需要利用if语句判断队列的空与非空后在进行操作,出栈的大体过程如下图所示:

6、获取栈顶元素时,只需要判断两个队列谁不为空,将不为空的队列的队尾元素返回即可

7、判断栈是否为空时,当两个队列均为空时栈才能为空,所以需要用&&

8、销毁栈时、不仅要释放掉malloc申请的内存空间,还要将两个队列一同销毁

#include<stdio.h>
#include<assert.h>
#include<stdlib.h>
#include<stdbool.h>//链式结构:表示队列
typedef int QDataType;
typedef struct QueueNode
{QDataType val;struct QueueNode* next;
}QNode;//队列的结构(使用结构体避免了二级指针的使用)
typedef struct Queue
{QNode* phead;QNode* ptail;int size;
}Queue;//初始化队列
void QueueInit(Queue* pq);//队尾入队列
void QueueDestroy(Queue* pq);//队头出队列
void QueuePush(Queue* pq, QDataType x);//获取队头元素
void QueuePop(Queue* pq);//获取队尾元素
QDataType QueueFront(Queue* pq);//获取队列中有效元素个数
QDataType QueueBack(Queue* pq);//检测队列是否为空
bool QueueEmpty(Queue* pq);//销毁队列
int QueueSize(Queue* pq);//初始化队列
void QueueInit(Queue* pq)
{assert(pq);pq->phead = pq->ptail = NULL;pq->size = 0;
}//销毁队列
void QueueDestroy(Queue* pq)
{assert(pq);QNode* cur = pq->phead;while (cur){QNode* next = cur->next;free(cur);cur = next;}pq->phead = pq->ptail = NULL;pq->size = 0;
}//队尾入队列
void QueuePush(Queue* pq, QDataType x)
{assert(pq);QNode* newnode = (QNode*)malloc(sizeof(QNode));if (newnode == NULL){perror("malloc fail");return;}newnode->val = x;newnode->next = NULL;if (pq->ptail == NULL){pq->ptail = pq->phead = newnode;}else{pq->ptail->next = newnode;pq->ptail = newnode;}pq->size++;
}// 对头出队列
void QueuePop(Queue* pq)
{assert(pq);// assert(pq->phead);QNode* del = pq->phead;pq->phead = pq->phead->next;free(del);del = NULL;if (pq->phead == NULL)pq->ptail = NULL;pq->size--;
}//获取队头元素
QDataType QueueFront(Queue* pq)
{assert(pq);assert(pq->phead);return pq->phead->val;
}//获取队尾元素
QDataType QueueBack(Queue* pq)
{assert(pq);assert(pq->ptail);return pq->ptail->val;
}//检测队列是否为空
bool QueueEmpty(Queue* pq)
{assert(pq);return pq->phead == NULL;
}//获取队列中有效元素个数
int QueueSize(Queue* pq)
{assert(pq);return pq->size;
}typedef struct {Queue q1;Queue q2;  
} MyStack;//初始化栈
MyStack* myStackCreate() {//申请结点空间MyStack* pst = (MyStack*)malloc(sizeof(MyStack));//取地址后就可以操作栈结构体中p1和p2中的内容QueueInit(&pst->q1);       //->的优先级大于&QueueInit(&pst->q2);       //->的优先级大于&return pst;
}//入栈
void myStackPush(MyStack* obj, int x) {//如果q1队列不为空则q1队列用于存放导出的数据if(!QueueEmpty(&obj->q1)){QueuePush(&obj->q1,x);}//如果q1队列为空则q2队列用于存放导出的数据else{QueuePush(&obj->q2,x);}
}//出栈
int myStackPop(MyStack* obj) {//起始假设q1为空,q2不为空,empty指针指向空队列,noempty指向非空队列Queue* empty = &obj->q1;Queue* noempty = &obj->q2;//如果我们假设失败则证明q1不为空,q2为空,交换标志if(!QueueEmpty(&obj->q1)){empty = &obj->q2;noempty = &obj->q1;}//然后将队列中的前N-1个元素导入空队列,所以循环结束的条件就是队列中元素等于1(这个剩下的就是要出栈的元素)while(QueueSize(noempty) > 1){QueuePush(empty,QueueFront(noempty));QueuePop(noempty);}//将队列中前N-1个元素导出后剩余的就是要出栈的元素,将该元素存储进整型变量top中int top = QueueFront(noempty);//存储完成后将该元素也进行出队列操作QueuePop(noempty);//最后返回要出栈的元素return top;
}//获取栈顶元素
int myStackTop(MyStack* obj) {//谁不为空就获取谁的队尾元素if(!QueueEmpty(&obj->q1)){return QueueBack(&obj->q1);}//如果q1队列为空则q2队列用于存放导出的数据else{return QueueBack(&obj->q2);}
}//判断栈是否为空
bool myStackEmpty(MyStack* obj) {//只有当两个队列均为空的时候,该栈才不会有有效数据return QueueEmpty(&obj->q1) && QueueEmpty(&obj->q2);
}//销毁栈
void myStackFree(MyStack* obj) {//初始化时除了malloc了一个结点,还初始化了两个队列,所以除了要将申请的结点释放还要将申请的两个队列销毁QueueDestroy(&obj->q1);QueueDestroy(&obj->q2);free(obj);
}

关于&pst->q1的解释:

为了操作队列,我们在初始化栈时需要将队列对象作为参数传递给函数,即&pst->q1,表示获取指针 pst 所指向的结构体中成员变量 q1 的地址(可以理解为队列q1的地址),而pst是一个指向MyStack结构体的指针,所以说就是获取MyStack结构体中成员变量的地址。

用栈实现队列

232. 用栈实现队列 - 力扣(LeetCode)

具体解题思路如下:

1、题目要求使用两个栈,但栈的基本功能需要自己实现

2、利用栈的结构体存储两个队列的头尾指针及队列元素个数的信息

3、为栈申请结点空间并利用STInit函数初始化栈

4、入队时,直接利用STPush函数进行入栈即可

5、先返回队头元素然后再出队,先判断用于出数据的popst栈是否为空,如果为空则将pushst栈中的数据倒顺序后放入popst栈中,利用STPush函数将pushst栈的栈顶元素放入空的popst栈中

6、出队时,用临时变量front接收返回的队头元素,然后利用STPop函数将该元素出队,最后返回该元素的值

7、判断队列是否为空时,当两个栈均为空时队列才能为空,所以需要用&&

8、销毁栈时、不仅要释放掉malloc申请的内存空间,还要将两个栈一同销毁

#include <stdio.h>
#include <assert.h>
#include <stdlib.h>//支持动态增长的栈
typedef int STDataType;
typedef struct Stack
{STDataType* a;int top;	  //表示栈顶位置int capacity; //栈的容量
}ST;// 初始化栈
void STInit(ST* ps);// 销毁栈
void STDestroy(ST* ps);// 入栈
void STPush(ST* ps, STDataType data);// 出栈
void STPop(ST* ps);// 获取栈顶元素
STDataType STTop(ST* ps);// 获取栈中有效元素个数
int STSize(ST* ps);// 检测栈是否为空,如果为空返回非零结果,如果不为空返回0 
int STEmpty(ST* ps);// 初始化栈
void STInit(ST* pst)
{//首先要指向一个栈assert(pst);pst->a = NULL;pst->capacity = 0;pst->top = 0;    //令pop表示栈顶元素的下一个元素的下标
}// 销毁栈
void STDestroy(ST* pst)
{//首先要指向一个栈assert(pst);//正常操作不再过多复述free(pst->a);pst->a = NULL;pst->top = pst->capacity = 0;
}//入栈
void STPush(ST* pst, STDataType x)
{//首先要指向一个栈assert(pst);//判断栈是否已满,如果栈满则申请新的内存空间if (pst->top == pst->capacity){int newCapacity = pst->capacity == 0 ? 4 : pst->capacity * 2;STDataType* tmp = (STDataType*)realloc(pst->a, sizeof(STDataType) * newCapacity);if (tmp == NULL){perror("realloc fail");return;}pst->a = tmp;pst->capacity = newCapacity;}//如果栈未满则进行入栈操作(若初始化时pop=-1,则下面两行代码交换执行顺序)pst->a[pst->top] = x;    //此时pop表示的是栈顶元素的下一个元素的下标 pst->top++;              //top表示的下标数++
}//出栈
void STPop(ST* pst)
{//首先要指向一个栈assert(pst);//top<0表示栈为空,top=0表示没有元素入栈,存在这两种情况就不能执行出栈操作(可以提供的图理解)assert(pst->top > 0);//直接对top执行减减操作以获取实际数组元素下标pst->top--;
}// 获取栈顶元素
STDataType STTop(ST* pst)
{//首先要指向一个栈assert(pst);//top<0表示栈为空,top=0表示没有元素入栈,存在这两种情况就不能执行出栈操作(可以提供的图理解)assert(pst->top > 0);//当初始化top=0时,top的值与实际数组元素下标的值之间的关系是:实际下标 = top-1//所以这里要进行减一操作得到实际的数组元素下标后再输出return pst->a[pst->top - 1];
}//获取栈中有效元素个数
int STSize(ST* pst)
{//首先要指向一个栈assert(pst);//初始化top=0,则top等于多少栈中就有多少个元素return pst->top;
}//检测栈是否为空,如果为空返回非零结果,如果不为空返回0 
int STEmpty(ST* pst)
{//首先要指向一个栈assert(pst);//如果pst->top不为空则返回结果为真,为空则返回假return pst->top == NULL;
}typedef struct {ST pushst;ST popst;    
} MyQueue;//初始化栈
MyQueue* myQueueCreate() {MyQueue* obj = (MyQueue*)malloc(sizeof(MyQueue));STInit(&obj->pushst);STInit(&obj->popst);return obj;
}//入队
void myQueuePush(MyQueue* obj, int x) {STPush(&obj->pushst,x);
}//出队
int myQueuePop(MyQueue* obj) {int front = myQueuePeek(obj);STPop(&obj->popst);return front;
}//返回队头元素
int myQueuePeek(MyQueue* obj) {//栈不为空就倒数据if(STEmpty(&obj->popst)){//将pusust里面的数据倒转顺序后传递给popstwhile(!STEmpty(&obj->pushst)){STPush(&obj->popst, STTop(&obj->pushst));STPop(&obj->pushst);}}return STTop(&obj->popst);
}//判断是否为空
bool myQueueEmpty(MyQueue* obj) {return STEmpty(&obj->popst) && STEmpty(&obj->pushst);
}//销毁队
void myQueueFree(MyQueue* obj) {STDestroy(&obj->popst);STDestroy(&obj->pushst);
}/*** 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);
*/

关于&pst->pushst和&pst->popst的解释:

~over~ 

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

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

相关文章

元素清空操作clear与选择操作check

元素清空操作clear与选择操作check clear() 作用 清空输入框的所有内容.clear() 等价于 .type("{selectall}{backspace}") 语法 .clear() .clear(options)option选项 元素选中操作check与uncheck check 语法 // 所有匹配到的选择框都会被选中一遍 .check()/…

三、防火墙-源NAT

学习防火墙之前&#xff0c;对路由交换应要有一定的认识 源NAT基本原理1.1.NAT No-PAT1.2.NAPT1.3.出接口地址方式&#xff08;Easy IP&#xff09;1.4.Smart NAT1.5.三元组 NAT1.6.多出口场景下的源NAT 总结延伸 ——————————————————————————————…

部署你的第一个应用

&#x1f5d3;️实验环境 OS名称Microsoft Windows 11 家庭中文版系统类型x64-based PCDocker版本Docker version 24.0.6, build ed223bcminikube版本v1.32.0 &#x1f913;FastAPI 构建应用 #基于fastapi快速创建一个项目 rkun1LAPTOP-TUS5FU0D MINGW64 / $ mkdir k8s-appr…

数学建模之拟合及其代码

发现新天地&#xff0c;欢迎访问Cr不是铬的个人网站 引言 与插值问题不同&#xff0c;在拟合问题中不需要曲线一定经过给定的点。拟合问题的目标是寻求一个函数&#xff08;曲线&#xff09;&#xff0c;使得该曲线在某种准则下与所有的数据点最为接近&#xff0c;即曲线拟合…

基于跳蛛算法优化概率神经网络PNN的分类预测 - 附代码

基于跳蛛算法优化概率神经网络PNN的分类预测 - 附代码 文章目录 基于跳蛛算法优化概率神经网络PNN的分类预测 - 附代码1.PNN网络概述2.变压器故障诊街系统相关背景2.1 模型建立 3.基于跳蛛优化的PNN网络5.测试结果6.参考文献7.Matlab代码 摘要&#xff1a;针对PNN神经网络的光滑…

数据结构学习笔记——多维数组、矩阵与广义表

目录 一、多维数组&#xff08;一&#xff09;数组的定义&#xff08;二&#xff09;二维数组&#xff08;三&#xff09;多维数组的存储&#xff08;四&#xff09;多维数组的下标的相关计算 二、矩阵&#xff08;一&#xff09;特殊矩阵和稀疏矩阵&#xff08;二&#xff09;…

hp惠普Victus Gaming Laptop 15-fa1025TX/fa1005tx原装出厂Win11系统ISO镜像

光影精灵9笔记本电脑原厂W11系统22H2恢复出厂时开箱状态一模一样 适用型号&#xff1a;15-fa1003TX&#xff0c;15-fa1005TX&#xff0c;15-fa1007TX&#xff0c;15-fa1025TX 链接&#xff1a;https://pan.baidu.com/s/1fBPjed1bhOS_crGIo2tP1w?pwduzvz 提取码&#xff1a…

解决vue中引入天地图显示不全问题,设置setTimeout即可解决!

index.html中引入天地图api <script type"text/javascript" src"https://api.tianditu.gov.cn/api?v4.0&tk你的key"></script>map.vue中初始化天地图 //初始化天地图 initTMap() {const T window.T;// 3.初始化地图对象this.tMap new…

LeetCode 2304. 网格中的最小路径代价:DP

【LetMeFly】2304.网格中的最小路径代价&#xff1a;DP 力扣题目链接&#xff1a;https://leetcode.cn/problems/minimum-path-cost-in-a-grid/ 给你一个下标从 0 开始的整数矩阵 grid &#xff0c;矩阵大小为 m x n &#xff0c;由从 0 到 m * n - 1 的不同整数组成。你可以…

redis五种基本数据类型

redis存储任何类型的数据都是以key-value形式保存&#xff0c;并且所有的key都是字符串&#xff0c;所以讨论基础数据结构都是基于value的数据类型 常见的5种数据类型是&#xff1a;String、List、Set、Zset、Hash 一) 字符串(String) String是redis最基本的类型&#xff0c;v…

地图导航测试用例,你get了吗?

地图导航是我们经常使用的工具&#xff0c;能帮助我们指引前进的方向。 接下来&#xff0c;会从功能测试、UI测试、兼容测试、安全测试、网络测试、性能测试、易用性测试、文档和国际化语言测试8个方面来编写地图导航测试用例。 一 功能测试 输入起点和终点&#xff0c;验证…

优先级队列(priority_queue)

文章目录 优先级队列的定义定义&#xff1a;接口头文件优先队列和堆的关系使用&#xff1a;排序的规则容器 仿函数应用 队列存指针问题&#xff1a; 优先级队列的定义 定义&#xff1a; 黄色部分是仿函数 接口 头文件 这里不需要包含其他的头文件只需要使用队列的头文件就可以…

LeetCode算法题解(动态规划)|LeetCode343. 整数拆分、LeetCode96. 不同的二叉搜索树

一、LeetCode343. 整数拆分 题目链接&#xff1a;343. 整数拆分 题目描述&#xff1a; 给定一个正整数 n &#xff0c;将其拆分为 k 个 正整数 的和&#xff08; k > 2 &#xff09;&#xff0c;并使这些整数的乘积最大化。 返回 你可以获得的最大乘积 。 示例 1: 输入…

​极氪,中国传统汽车品牌电动化的样板间

这篇文章早就想写了&#xff0c;因为太忙的原因就一直跳票&#xff0c;正好最近两件事的出现&#xff0c;又触发了想写这篇文章的冲动。 两件事主要是&#xff1a; 一&#xff0c;10 月份各家陆续公布了单月销量以及累计销量&#xff1b; 二&#xff0c;极氪在北京正式发布了 …

【GUI】-- 10 贪吃蛇小游戏之静态面板绘制

GUI编程 04 贪吃蛇小游戏 4.1 第一步&#xff1a;先绘制一个静态的面板 首先&#xff0c;需要新建两个类&#xff0c;一个StartGame类作为游戏的主启动类&#xff1b;一个GamePanel类作为游戏的面板类。此外&#xff0c;再新建一个Data类作为数据中心(存放了小蛇各部分图像的…

微信朋友圈全新玩法,轻松互动,引爆你的社交圈

随着社交媒体的普及&#xff0c;越来越多的人开始利用朋友圈来展示自己的生活和与朋友互动。而在这个数字时代&#xff0c;定时发圈、跟圈和朋友圈互动已经成为了一种社交习惯。本文将介绍这些功能的概念和一键转发朋友圈的实现方法。 什么是定时发圈、跟圈、朋友圈互动和一键转…

Embedding技术与应用(4): Embedding应用工程探析

编者按&#xff1a;随着互联网内容数量的急剧增长&#xff0c;个性化推荐已成为各大科技公司的核心竞争力之一。那么&#xff0c;如何构建一个可靠、高效的基于嵌入技术的推荐系统&#xff0c;使其能够在实际生产环境中正常运行呢&#xff1f;这是所有从业者都关心的问题。 本文…

git的实验:cherry-pick,github对比代码的两种方式

某个commit&#xff0c;比如 c1&#xff0c;&#xff0c;最早是在a分支做的&#xff0c;当被cherry-pick到b分之后&#xff0c;还是一样的revision吗&#xff1f; 实验1&#xff1a;c1被cherry-pick到别的分支后&#xff0c;revision不变对吗&#xff1f;&#xff08;答案是变…

druid keepAlive 导致数据库连接数飙升

一.背景 应用在执行完某个复杂业务&#xff0c;主要包含20几个查询SQL的操作后&#xff0c;会导致数据库连接池一直升高 druid版本&#xff1a;1.2.11 druid配置文件&#xff1a; spring.datasource.druid.maxActive100 spring.datasource.druid.initialSize20 spring.datas…

python解决登录图形验证码

摘要:测试过程中经常遇到图片验证码,以下主要是调用百度OCR图片识别获取验证码,实现登录 1、百度云申请创建应用