【数据结构】——栈与队列(附加oj题详解)深度理解

1.栈的定义

栈:栈是仅限与在表尾进行插入或者删除的线性表

我们把允许一端插入和删除的一端叫做栈顶,另一端叫栈底,不含任何元素的栈叫做空栈,栈又叫做后进先出的线性表,简称LIFO结构

2.栈的理解

对于定义里面的在表尾进行插入和删除,这里的表尾就是栈顶,而不是栈底,(这个理解会在用单链表实现栈的时候会着重说明一下),栈的插入叫做入栈,栈的删除叫做出栈。

这里为了更加形象的去理解栈,你可以把他当作一个装弹夹的过程,因为装弹的时候就是第一颗装进去是在最下面的,最后一颗装进去是在最上面的,所以非常符合后进先出的特点。

再者就是我们进入网页的时候,想回到上一个页面,会点击返回页面,这个操作也是栈的应用,因为返回的是最新点开的,所以可以理解为出栈的操作。

因为栈是线性表所以可以分为顺序存储结构和链式存储结构 

3.栈的顺序存储结构及实现

栈的顺序存储也就是用顺序表去实现,所以我们称为顺序栈,这里用顺序表,完美契合了栈的特点,所以非常合适。

顺序栈的实现有以下几步

1.栈的初始化

2.栈的销毁

3.栈的入栈

4.栈的出栈

首先栈的初始化,和顺序表一样,但是我们需要一个坐标去表示栈顶,在栈满的时候去判断是否会溢出,这个坐标我们设置为top,初始化的时候我们有两个选择一种是初始化为-1,一种是初始化为0,两种各有好处,前者是可以用top表示当前元素,后者更加符合更多人的认知,这里我采用的是后者

 

栈的结构定义

typedef int STDataType;//这里有可能是其他元素所以采用取别名的方式
typedef struct Stack
{STDataType* a;int top;//栈顶元素int capacity;//容量大小
}ST;

栈的初始化

void STInit(ST* pst)
{assert(pst);pst->a = NULL;pst->capacity = 0;pst->top = 0;//这里我们采用第二种方式
}

栈的入栈操作

void STPush(ST* pst, STDataType x)
{assert(pst);if (pst->top == pst->capacity)//这里无论是满还是空都成立,所以写在一起//如果top开始是-1那么这里应该top+1{int newcapacity = pst->capacity == 0 ? 4 : pst->capacity * 2;//如果是空就给一个初值 //否则直接扩容到2倍STDataType* tmp = (STDataType*)realloc(pst->a,newcapacity*sizeof(STDataType));//申 请一片空间if (tmp == NULL){perror("realloc fail");return;}else{pst->a = tmp;pst->capacity = newcapacity;}}pst->a[pst->top] = x;//申请成功,那么直接赋值,top再++pst->top++;
}

 栈的出栈操作

void STPop(ST* pst)
{assert(pst);assert(!STEmpty(pst));//如果是空就不能出栈了pst->top--;//直接--就行
}

 栈的销毁操作

void STDestory(ST* pst)
{assert(pst);free(pst->a);pst->a = NULL;pst->capacity = 0;pst->top = 0;
}

栈的判空

 

bool STEmpty(ST* pst)
{assert(pst);return pst->top == 0;
}

由于栈用顺序结构有点弊端,所以我们可以用两个栈去优化它,也就是两个相同的栈相对,这样可以让顺序栈进一步优化

但是如果两个栈都增加那么也是没效果的,这种结构适用于一个整加,一个减少,就比如买股票

有人买就有人卖出 

 4.栈的链式存储结构及实现

栈的链式存储结构简称为链栈,用链表来实现其实有很多方法,但这里还是推荐用单链表,其他的都有点不对劲,首先我们肯定需要一个栈顶指针, 这里我们有两种选择,一种是把尾结点当作栈顶,每次插入或删除都在尾结点,或者是把头节点做栈顶,每次插入或者删除在头节点,如果用尾结点做栈顶,那么我需要把指针放在尾结点的前一个,所以为了避免混淆,我们使用头插头删的方法去实现

链栈的优势是不存在栈满的情况,如果真的发生了那说明计算机已经面临奔溃了         

链栈的结构定义

typedef int STDataType;
typedef struct StackNode
{struct StackNode* next;STDataType data;
}ST;
typedef struct Stack
{ST* top;int size;
}Stack;//这里多定义一个结构体,用top指针去指向第一个结点

链栈的初始化

void StackInit(Stack* st)
{assert(st);st->top = NULL;st->size = 0;
}

链栈的销毁

 

void StackDestory(Stack* st)
{assert(st);ST* cur = st->top;while (cur){ST* next = cur->next;free(cur);cur = next;}st->top = NULL;st->size = 0;
}

链栈的入栈

void StackPush(Stack* st, STDataType x)
{assert(st);ST* newnode = (ST*)malloc(sizeof(ST));if (newnode == NULL){perror("malloc fail");return;}else {newnode->data = x;newnode->next = NULL;if (st->top == NULL){st->top = newnode;}else{newnode->next = st->top;st->top = newnode;}}st->size++;
}

链栈的出栈

void StackPop(Stack* st)
{assert(st);assert(!StackEmpty(st));ST* cur = st->top;st->top = st->top->next;free(cur);st->size--;
}

链栈的判空

bool StackEmpty(Stack* st)
{assert(st);return st->top == NULL;
}

链栈的返回栈顶元素

STDataType StackTop(Stack* st)
{assert(st);assert(!StackEmpty(st));return st->top->data;
}

队列

1.队列的定义:

队列:队列是只允许在一端进行插入操作,在另一端进行删除操作的线性表

 队列是一种先进先出的线性表,运行插入一段的叫队尾,允许出队列的叫队头

没有元素的队列叫空队列

2.队列的理解

对于队列的理解我们可以理解为一条河流或者是排队取餐,他们都是有顺序的,先来的先吃饭,后来的后吃饭,这是不是很想一些餐厅一样,他们那个系统也就是队列的应用。

 队列存储方式和栈是一样的有两种方式

1.顺序队列:顺序表实现队列

2.链队列:用链表实现队列

这两者的选择上其实用链表更加合适,顺序表不是很适合,因为用顺序表需要挪动数据非常麻烦,所以下面用链表实现,顺序表的实现就不展示了

3.队列的链式存储结构

因为队列是一个先进先出的数据结构,所以我们用链表的时候也就是头删和尾插
队列的结构定义

typedef int QDataType;
typedef struct QueueNode
{struct QueueNode* next;QDataType data;
}QNode;typedef struct Queue
{QNode* phead;//一个指向头QNode* ptail;//一个指向尾int size;
}Queue;//这里和栈的链表实现有些类似,都有两个结构体,//一个结构体表示结点,一个结构体表示位置指针

队列初始化 

void QueueInit(Queue* pq)
{assert(pq);pq->phead = NULL;pq->ptail = NULL;pq->size = 0;
}

队列的销毁 

void QueueDestory(Queue* pq)
{assert(pq);QNode* cur = pq->phead;while (cur){QNode* next = cur->next;free(cur);cur = next;}pq->phead = NULL;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;}else{newnode->data = x;newnode->next = NULL;if (pq->phead == NULL){pq->phead = pq->ptail = newnode;}else{pq->ptail->next = newnode;pq->ptail = newnode;}}pq->size++;
}

队列的出列

void QueuePop(Queue* pq)
{//头删assert(pq);assert(!QueueEmpty(pq));//一个结点//多个结点if (pq->phead->next == NULL){free(pq->phead);pq->phead = pq->ptail = NULL;}else{QNode* next = pq->phead->next;free(pq->phead);pq->phead = next;}
}

队列的获取第一个元素

QDataType QueueTop(Queue* pq)
{assert(pq);assert(!QueueEmpty(pq));return pq->phead->data;
}

 队列的判空

bool QueueEmpty(Queue* pq)
{assert(pq);return pq->phead == NULL && pq->ptail==NULL;//两个指针都有//或者写成pq->size==0
}

队列的获取尾元素

这个很多人感觉没用,但他在做一些题目的时候会有很大作用

QDataType QueueBack(Queue* pq)
{assert(pq);assert(!QueueEmpty(pq));return pq->ptail->data;
}

 说完链队列,我们来看看顺序队列,上面其实说了顺序队列的不好,但是如果我们把它改成循环队列那就会很好,如果是普通队列那么它出队的时间复杂度为O(N),循环队列为O(1),而且,普通队列会浪费很多空间,具体看下面的动图

队空的条件就是front==rear,那满就不能用这个了 ,所以我们可以多开一个空间,rear指向最后一个元素的下一个位置,这个位置没有元素是空的,当rear再走一步也就和front相等了,用这个来判断是否是满的,由于是循环的所以我们用(rear+1)%MAXSIZE==front来判断

所以我们这样做就可以把顺序队列给优化

循环队列的结构定义

typedef int QDataType;
#define MAXSIZE 50
typedef struct QueueSL
{QDataType a[MAXSIZE];//数组表示int front;//一个头int rear;//一个尾
}QL;

循环队列的初始化

 

void QLInit(QL* pq)
{assert(pq);pq->front = 0;pq->rear = 0;
}

循环队列的销毁

void QLDestory(QL* pq)
{assert(pq);free(pq->a);pq->front = 0;pq->rear = 0;
}

循环队列的入队列

void QLPush(QL* pq, QDataType x)
{assert(pq);if ((pq->rear + 1) % MAXSIZE == pq->front){return;}else{pq->a[pq->rear] = x;pq->rear = (pq->rear + 1) % MAXSIZE;//这里可以看看上面的动态图,然后自己画图//不能直接写rear++,但跑到最后一个元素的时候还要回来}
}

 循环队列的出列

void QLPop(QL* pq)
{assert(pq);assert(!QLEmpty(pq));//这里判断是否为空,空了就不能删了pq->front = (pq->front + 1) % MAXSIZE;//和上面一样
}

 循环队列判空

bool QLEmpty(QL* pq)
{assert(pq);return (pq->rear == pq->front);
}

 以上就是栈和队列的基本操作和基础知识,其实还有很多知识点,这些放在后面的文章说(需要用到c++)

有了以上的基础,下面我们写几个题目去巩固一下

oj题 

用栈实现队列

请你仅使用两个栈实现先入先出队列。队列应当支持一般队列支持的所有操作(pushpoppeekempty):

实现 MyQueue 类:

  • void push(int x) 将元素 x 推到队列的末尾
  • int pop() 从队列的开头移除并返回元素
  • int peek() 返回队列开头的元素
  • boolean empty() 如果队列为空,返回 true ;否则,返回 false

说明:

  • 你 只能 使用标准的栈操作 —— 也就是只有 push to toppeek/pop from topsize, 和 is empty 操作是合法的。
  • 你所使用的语言也许不支持栈。你可以使用 list 或者 deque(双端队列)来模拟一个栈,只要是标准的栈操作即可。
  • 示例 1:

    输入:
    ["MyQueue", "push", "push", "peek", "pop", "empty"]
    [[], [1], [2], [], [], []]
    输出:
    [null, null, null, 1, 1, false]解释:
    MyQueue myQueue = new MyQueue();
    myQueue.push(1); // queue is: [1]
    myQueue.push(2); // queue is: [1, 2] (leftmost is front of the queue)
    myQueue.peek(); // return 1
    myQueue.pop(); // return 1, queue is [2]
    myQueue.empty(); // return false
    

    提示:

  • 1 <= x <= 9
  • 最多调用 100 次 pushpoppeek 和 empty
  • 假设所有操作都是有效的 (例如,一个空的队列不会调用 pop 或者 peek 操作)
  • 进阶:

  • 你能否实现每个操作均摊时间复杂度为 O(1) 的队列?换句话说,执行 n 个操作的总时间复杂度为 O(n) ,即使其中一个操作可能花费较长时间。

 

 这道题思路就是一个栈出数据,一个栈进数据,就可以实现队列,因为队列是先进先出,栈是后进先出,所以把栈倒过来,就变成了先进先出

typedef int STDataType;
typedef struct Stack
{STDataType* a;int top;int capacity;
}ST;void STInit(ST* pst);
void STDestroy(ST* pst);
void STPush(ST* pst, STDataType x);
void STPop(ST* pst);
STDataType STTop(ST* pst);
bool STEmpty(ST* pst);
int STSize(ST* pst);void STInit(ST* pst)
{assert(pst);pst->a = NULL;//pst->top = -1;   // top 指向栈顶数据pst->top = 0;   // top 指向栈顶数据的下一个位置pst->capacity = 0;
}void STDestroy(ST* pst)
{assert(pst);free(pst->a);pst->a = NULL;pst->top = pst->capacity = 0;
}void STPush(ST* pst, STDataType x)
{if (pst->top == pst->capacity){int newCapacity = pst->capacity == 0 ? 4 : pst->capacity * 2;STDataType* tmp = (STDataType*)realloc(pst->a, newCapacity * sizeof(STDataType));if (tmp == NULL){perror("realloc fail");return;}pst->a = tmp;pst->capacity = newCapacity;}pst->a[pst->top] = x;pst->top++;
}void STPop(ST* pst)
{assert(pst);assert(!STEmpty(pst));pst->top--;
}STDataType STTop(ST* pst)
{assert(pst);assert(!STEmpty(pst));return pst->a[pst->top - 1];
}bool STEmpty(ST* pst)
{assert(pst);/*if (pst->top == 0){return true;}else{return false;}*/return pst->top == 0;
}int STSize(ST* pst)
{assert(pst);return pst->top;
}
//以上是栈的实现,可以自己写一个,因为我们用的c所以不是太方便
typedef struct {ST pushst;ST popst;//用结构体去存两个栈
} MyQueue;MyQueue* myQueueCreate() {//开辟一片空间去存,也就是创造MyQueue*obj=(MyQueue*)malloc(sizeof(MyQueue));if(obj==NULL){perror("malloc fail");return NULL;}STInit(&obj->pushst);//记得初始化STInit(&obj->popst);return obj;
}void myQueuePush(MyQueue* obj, int x) {STPush(&obj->pushst,x);//把数据全部丢进进数据的那个栈
}int myQueuePeek(MyQueue* obj) {if(STEmpty(&obj->popst))//判断是不是空,如果不是空,直接返回第一个元素就行//如果不是就需要把元素全部导进来{while(!STEmpty(&obj->pushst)){STPush(&obj->popst,STTop(&obj->pushst));STPop(&obj->pushst);//导一个元素就删一个}}return STTop(&obj->popst);
}
int myQueuePop(MyQueue* obj) {//和上面的思路很想,所以直接套过来就行,多了一个删除int front=myQueuePeek(obj);STPop(&obj->popst);return front;
}bool myQueueEmpty(MyQueue* obj) {return STEmpty(&obj->pushst)&&STEmpty(&obj->popst);
}void myQueueFree(MyQueue* obj) {STDestroy(&obj->pushst);STDestroy(&obj->popst);free(obj);}

 用队列实现栈

请你仅使用两个队列实现一个后入先出(LIFO)的栈,并支持普通栈的全部四种操作(pushtoppop 和 empty)。

实现 MyStack 类:

  • void push(int x) 将元素 x 压入栈顶。
  • int pop() 移除并返回栈顶元素。
  • int top() 返回栈顶元素。
  • boolean empty() 如果栈是空的,返回 true ;否则,返回 false 。

注意:

  • 你只能使用队列的标准操作 —— 也就是 push to backpeek/pop from frontsize 和 is empty 这些操作。
  • 你所使用的语言也许不支持队列。 你可以使用 list (列表)或者 deque(双端队列)来模拟一个队列 , 只要是标准的队列操作即可。

示例:

输入:
["MyStack", "push", "push", "top", "pop", "empty"]
[[], [1], [2], [], [], []]
输出:
[null, null, null, 2, 2, false]解释:
MyStack myStack = new MyStack();
myStack.push(1);
myStack.push(2);
myStack.top(); // 返回 2
myStack.pop(); // 返回 2
myStack.empty(); // 返回 False

提示:

  • 1 <= x <= 9
  • 最多调用100 次 pushpoptop 和 empty
  • 每次调用 pop 和 top 都保证栈不为空

进阶:你能否仅用一个队列来实现栈。

这道题的思路和上一个题有点像,但是不能完全套用,因为我们队列是先进先出,我们要实现后进先出,我们得把有数据的队列里面的前n-1个数据放到没有数据的地方,然后把最后那个元素弹出,也就是实现了后进先出,后面的没个元素操作都是这样。 


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* pq);
void QueueDestory(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 = NULL;pq->ptail = NULL;pq->size = 0;
}
void QueueDestory(Queue* pq)
{assert(pq);QNode* cur = pq->phead;while (cur){QNode* next = cur->next;free(cur);cur = next;}pq->phead = NULL;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->data = x;newnode->next = NULL;if (pq->ptail == NULL){assert(pq->phead == NULL);pq->phead = newnode;pq->ptail = newnode;}else{pq->ptail->next = newnode;pq->ptail = newnode;}pq->size++;
}
void QueuePop(Queue* pq)
{assert(pq);assert(!QueueEmpty(pq));if (pq->phead->next == NULL){free(pq->phead);pq->ptail=pq->phead = NULL;}else{QNode* next = pq->phead->next;free(pq->phead);pq->phead = next;}pq->size--;
}
QDataType QueueFront(Queue* pq)
{assert(pq);assert(!QueueEmpty(pq));return pq->phead->data;
}
QDataType QueueBack(Queue* pq)
{assert(pq);return pq->ptail->data;
}
bool QueueEmpty(Queue* pq)
{assert(pq);return pq->phead == NULL && pq->ptail == NULL;
}
int QueueSize(Queue* pq)
{assert(pq);return pq->size;
}//队列的实现typedef struct {Queue q1;Queue q2;
} MyStack;//和上个题一样的思路MyStack* myStackCreate() {MyStack *obj=(MyStack*)malloc(sizeof(MyStack));QueueInit(&obj->q1);QueueInit(&obj->q2);return obj;
}void myStackPush(MyStack* obj, int x) {if(!QueueEmpty(&obj->q1))//往没有数据的地方放数据{QueuePush(&obj->q1,x);}else{QueuePush(&obj->q2,x);}}
//导数据
int myStackPop(MyStack* obj) {Queue*pEmptyQ=&obj->q1;//因为我们不知道哪个是空,所以要把它找出来Queue*pNoEmptyQ=&obj->q2;if(!QueueEmpty(&obj->q1)){pEmptyQ=&obj->q2;pNoEmptyQ=&obj->q1;}while(QueueSize(pNoEmptyQ)>1)//找到以后就开始导数据,把最后一个留下{QueuePush(pEmptyQ,QueueFront(pNoEmptyQ));QueuePop(pNoEmptyQ);}int top=QueueFront(pNoEmptyQ);然后返回最后一个元素,这也是要导出的元素QueuePop(pNoEmptyQ);return top;
}int myStackTop(MyStack* obj) {Queue*pEmptyQ=&obj->q1;Queue*pNoEmptyQ=&obj->q2;if(!QueueEmpty(&obj->q1))//找哪个不是空{pEmptyQ=&obj->q2;pNoEmptyQ=&obj->q1;}return QueueBack(pNoEmptyQ);//这里队列的尾指针起到了作用,是不是很妙,也就不用遍历了
}bool myStackEmpty(MyStack* obj) {return QueueEmpty(&obj->q1)&&QueueEmpty(&obj->q2);
}void myStackFree(MyStack* obj) {free(obj);}

总结

 希望本文章对你有帮助,大概就是栈和队列的实现以及为什么要这样实现都在里面了,可能还有很多知识点,因为牵扯到c++所以准备往后更,里面的oj题可能很好的打磨,希望你能认真看完,👍👍

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

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

相关文章

面向对象的学习

封装 //用来描述一类事物的类&#xff0c;专业叫做&#xff1a;javabean类 //在javabean类是不写main方法的//一个java文件中可以定义多个类&#xff0c;且只能一个类是public修饰&#xff0c;而且public修饰的类名必须成为代码的文件名 ://在类中一般无需指定初始化值 存在默…

CleanMyMac X 4.15.1 for Mac 最新中文破解版 系统优化垃圾清理工具

CleanMyMac X for Mac 是一款功能更加强大的系统优化清理工具&#xff0c;相比于 CleanMyMac 4.15.1来说&#xff0c;功能增加了不少&#xff0c;此版本为4.15.1官方最新中英文正式破解版本&#xff0c;永久使用&#xff0c;解决了打开软件崩溃问题&#xff0c;最新版4.15.1版本…

MYSQL数字函数实操宝典:场景化SQL语句一网打尽

​&#x1f308; 个人主页&#xff1a;danci_ &#x1f525; 系列专栏&#xff1a;《设计模式》《MYSQL应用》 &#x1f4aa;&#x1f3fb; 制定明确可量化的目标&#xff0c;坚持默默的做事。 MYSQL数字函数&#xff1a;不可不知的数据处理利器 文章目录 Part 1: 准备 &#x…

3723. 字符串查询:做题笔记

目录 思路 代码 注意点 3723. 字符串查询 思路 这道题感觉和常见的前缀和问题不太一样&#xff0c;前缀和的另一种应用&#xff1a;可以统计次数。 这道题我们想判断一个单词的其中一段子序列A是否可以通过重新排列得到另一段子序列B。 我看到这道题的时候想着可能要判…

资讯头条P3自媒体搭建

自媒体素材管理与文章管理 一.后台搭建 1.1 搭建自媒体网关 导入网关模块>>>在网关模块的pom.xml文件中添加该子模块>>>刷新maven <modules><module>heima-leadnews-app-gateway</module><!--新增--><module>heima-leadnew…

大学生租房系统的设计与实现|Springboot+ Mysql+Java+ B/S结构(可运行源码+数据库+设计文档)

本项目包含可运行源码数据库LW&#xff0c;文末可获取本项目的所有资料。 推荐阅读100套最新项目持续更新中..... 2024年计算机毕业论文&#xff08;设计&#xff09;学生选题参考合集推荐收藏&#xff08;包含Springboot、jsp、ssmvue等技术项目合集&#xff09; 1. 系统功能…

【ppt技巧】给PPT添加打开加密密码的方法

PPT文件制作完成之后&#xff0c;为了保证内容泄露或者修改&#xff0c;我们可以给PPT文件设置一个打开密码来保护文件&#xff0c;今天分享PPT加密方法给大家。希望能够帮助大家保护好自己的PPT文件。 如果想要其他人需要输入正确的密码才能够打开文件查看并编辑&#xff0c;…

如何在CentOS使用Docker搭建Rsshub服务并实现无公网IP远程访问

文章目录 1. Docker 安装2. Docker 部署Rsshub3. 本地访问Rsshub4. Linux安装Cpolar5. 配置公网地址6. 远程访问Rsshub7. 固定Cpolar公网地址8. 固定地址访问 Rsshub是一个开源、简单易用、易于扩展的RSS生成器&#xff0c;它可以为各种内容生成RSS订阅源。 Rsshub借助于开源社…

Python-VBA编程500例-024(入门级)

字符串写入的行数(Line Count For String Writing)在实际应用中有着广泛的应用场景。常见的应用场景有&#xff1a; 1、文本编辑及处理&#xff1a;在编写或编辑文本文件时&#xff0c;如使用文本编辑器或文本处理器&#xff0c;经常需要处理字符串并确定其在文件中的行数。这…

C#开发者必备!快速掌握onnxruntime实现YOWOv2视频动作检测技术!

C#开发者必备&#xff01;快速掌握onnxruntime实现YOWOv2视频动作检测技术&#xff01; 目录 介绍 效果 模型信息 项目 代码 Form1.cs YOWOv2.cs 下载 介绍 YOWOv2: A Stronger yet Efficient Multi-level Detection Framework for Real-time Spatio-temporal Action…

持续集成流水线介绍(CI)

目录 一、概述 二、持续集成的典型操作流程 2.1 概述 2.2 持续集成的操作流程图 2.3 持续集成关键流程说明 三、构建持续集成流水线的方式 3.1 依托云厂商能力 3.2 采用开源产品 3.3 企业自研 四、构建持续化集成流水线 4.1 基于GitHub的持续集成流水线&#xff08;公…

【氮化镓】GaN器件中关态应力诱导的损伤定位

概括总结&#xff1a; 这项研究通过低频1/f噪声测量方法&#xff0c;探究了在关态&#xff08;OFF-state&#xff09;应力作用下&#xff0c;AlGaN/GaN高电子迁移率晶体管&#xff08;HEMTs&#xff09;中由应力引起的损伤的定位。研究中结合了电致发光&#xff08;EL&#xf…

如何合理利用chatgpt写高质量论文,10分钟速成(四)

演示站点&#xff1a; https://www.cnsai.net/ 论文模块 官方论坛&#xff1a; www.jingyuai.com 京娱AI 一、文章结构剖析 如果我们经常去写文章或者是去看别人的文章&#xff0c;你会发现文章分为以下几部分 标题大纲前言/导语正文&#xff08;不同的结构&#xff09;结尾呼…

Linux查看重启时间,关机时间,运行时长的指令

Linux查看重启时间&#xff0c;关机时间&#xff0c;运行时长的指令 查看上次启动时间查看系统重启时间查看关机时间查看运行时长 这里测试环境为Ubuntu 16.04 查看上次启动时间 who -b可以通过who --help查看who指令的更多功能 查看系统重启时间 可以通过下面的方式来进行…

1. Java概述

文章目录 1.Java语言概述1.1 Java介绍1.1.1 软件开发概述1.1.2 计算机语言1.1.3 Java 简史1.1.4 Java 技术体系平台1.1.5 Java在各领域的应用1.1.6 Java语言特点1.1.7 Java核心机制一-Java虚拟机1.1.8 Java核心机制二-垃圾回收1.1.9 Java开发工具 1.2 Java环境搭建1.2.1 JDK、J…

农村分散式生活污水分质处理及循环利用技术指南

标准已完成意见征集&#xff1a; 本文件给出了农村分散式生活污水分质处理及循环利用的总则、污水收集、污水分质处理、资源化利用、利用模式、运维管理等的指导。 本文件适用于农村分散式生活污水分质处理及循环利用的设施新建、扩建和改建工程的设计、施工与运维。 注:本文件…

算法系列--动态规划--回文子串系列

&#x1f495;"我们好像在池塘的水底&#xff0c;从一个月亮走向另一个月亮。。"&#x1f495; 作者&#xff1a;Mylvzi 文章主要内容&#xff1a;算法系列–动态规划–回文子串系列 今天为大家带来的是算法系列--动态规划--回文子串系列(1),本文重点掌握如何快速判…

Echarts地图之——如何给地图添加外边框轮廓

有时候我们希望给地图外围加一圈边框来增加美感 但实际情况中&#xff0c;我们需要把国界的边框和各个省份属于国界的边框相吻合&#xff0c;否则就会造成两者看起来是错位的感觉 这就需要我们把echarts registerMap的全国省份json和国界边框json的坐标相一致。 这个json我们可…

佳能机械制造将莅临2024第13届生物发酵产品与技术装备展

参展企业介绍 过滤与分离设备专业制造商 •碟式离心机及机组模块、系统 •卧式螺旋卸料沉降离心机及系统 江苏佳能机械制造有限公司位于中国“龙虾之都”——江苏盱眙&#xff0c;地处淮安西南部&#xff0c;淮河下游&#xff0c;洪泽湖南岸&#…

网络七层模型之表示层:理解网络通信的架构(六)

&#x1f90d; 前端开发工程师、技术日更博主、已过CET6 &#x1f368; 阿珊和她的猫_CSDN博客专家、23年度博客之星前端领域TOP1 &#x1f560; 牛客高级专题作者、打造专栏《前端面试必备》 、《2024面试高频手撕题》 &#x1f35a; 蓝桥云课签约作者、上架课程《Vue.js 和 E…