栈和队列OJ练习题及解答

news2024/10/5 10:24:59

前言

        上一篇博客已经讲到了栈和队列的数据结构,概括一下:栈后进先出(Last In First Out)、队列先进先出(First In First Out)。那么,接下来就来讲讲,关于栈和队列的相关练习题,进一步掌握栈和队列的使用。

一. 用队列实现栈

1. 题目描述

        请你仅使用两个队列实现一个后入先出(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 都保证栈不为空

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

2. 解题思路

        根据上述题目描述,我们需要用两个队列来模拟栈后进先出(Last In First Out),那么问题就在于达到先进后出的效果,怎么如数据和出数据。

        首先队列出数据的话是从队头出,为了达到后出的效果,需要把其他的数据暂时存储起来,这个时候我们的第二个队列的作用就出现了,可以把在其他的数据转移到第二个队列,记录第一个队列头数据,最后清空第一个队列,达到这样的效果。如图1-1所示:

图1-1 双队列模拟栈读取删除数据

        输入的话就将所有数据录入到非空的队列,确保顺序性。

        关于进阶——用一个队列模拟栈:队列里入数据还是一样入,出数据的话就先把队列中前面的数据尾插到原队列,按照这个思路,我们需要知道需要尾插多少次,就在模拟栈的结构里增加一个记录数据总数的整形变量,每次删除数据都尾插数据总数减一次。如图1-2所示:

图1-2 单队列模拟栈出数据

3. 解题代码

        解题代码采用两个队列模拟栈的思路,有兴趣的小伙伴可以尝试单队列模拟。

3.1. 基础代码

        因为需要用队列模拟栈,而C语言不像C++那样能够直接使用库中的队列,所以这里直接提供给大家队列的代码。代码如下:


typedef int QDataType;
// 链式结构:表示队列 
typedef struct QListNode 
{ 
	struct QListNode* _next; 
	QDataType _data; 
}QNode; 

// 队列的结构 
typedef struct Queue 
{ 
	QNode* _front; 
	QNode* _rear; 
}Queue; 

// 初始化队列 
void QueueInit(Queue* q)
{
    assert(q);
    q->_front = q->_rear = NULL;
}

// 检测队列是否为空,如果为空返回非零结果,如果非空返回0 
bool QueueEmpty(Queue* q)
{
    assert(q);

    return q->_front == NULL;
}

// 获取队列中有效元素个数 
int QueueSize(Queue* q)
{
    assert(q);

    if(QueueEmpty(q))
    {
        return 0;
    }
    else
    {
        QNode* cur = q->_front;
        int count = 0;
        while(cur)
        {
            ++count;
            cur = cur->_next;
        }
        return count;
    }
}


// 队尾入队列 
void QueuePush(Queue* q, QDataType data)
{
    assert(q);

    QNode* newnode = (QNode*)malloc(sizeof(QNode));
    if(newnode == NULL)
    {
        perror("QueuePush malloc fail");
        return;
    }

    newnode->_data = data;
    newnode->_next = NULL;

    if(q->_front == NULL)
    {
        q->_front = q->_rear = newnode;
    }
    else
    {
        q->_rear->_next = newnode;
        q->_rear = q->_rear->_next;
    }
}

// 队头出队列 
void QueuePop(Queue* q)
{
    assert(q);
    assert(!QueueEmpty(q));

    if(q->_front == q->_rear)
    {
        free(q->_front);
        q->_front = q->_rear = NULL;
    }
    else
    {
        QNode* next = q->_front->_next;
        free(q->_front);
        q->_front = next;
    }
}

// 获取队列头部元素 
QDataType QueueFront(Queue* q)
{
    assert(q);
    assert(!QueueEmpty(q));

    return q->_front->_data;
}

// 获取队列队尾元素 
QDataType QueueBack(Queue* q)
{
    assert(q);
    assert(!QueueEmpty(q));

    return q->_rear->_data;
}

// 销毁队列 
void QueueDestroy(Queue* q)
{
    assert(q);

    //用cur遍历链表
    QNode* cur = q->_front;
    //遍历
    while(cur)
    {
        //保存下一个位置节点
        QNode* next = cur->_next;
        free(cur);//释放内存
        //移动
        cur = next;
    }
    //队列中指针置为NULL
    q->_front = q->_rear = NULL;
}

3.2. 题目要求的函数实现

3.2.1. 栈的结构

        栈里面包含两个队列,如下所示:

typedef struct {
    Queue q1;
    Queue q2;
} MyStack;
3.2.2. 初始化栈

        为栈的结构开辟空间,并将队列初始化,代码如下:

MyStack* myStackCreate() {
    MyStack* st = (MyStack*)malloc(sizeof(MyStack));
    QueueInit(&(st->q1));
    QueueInit(&(st->q2));
    return st;
}
3.2.3. 销毁栈

        首先释放栈中队列所开辟的空间然后释放栈开辟的空间,代码如下:

void myStackFree(MyStack* obj) {
    QueueDestroy(&(obj->q1));
    QueueDestroy(&(obj->q2));
    free(obj);
}
3.2.4. 判断栈是否为空

        检查两个队列里是否存在数据,都没有栈就为空,这里直接调用队列为空的函数即可,代码如下:

bool myStackEmpty(MyStack* obj) {
    return QueueEmpty(&(obj->q1)) && QueueEmpty(&(obj->q2));
}
3.2.5. 入栈

        向非空的队列入数据,代码如下:

void myStackPush(MyStack* obj, int x) {
    assert(obj);

    //如果队列1不为空,则向队列1中录入数据
    if(!QueueEmpty(&(obj->q1)))
    {
        QueuePush(&(obj->q1), x);
    }
    else//反之就录入数据到队列2
    {
        QueuePush(&(obj->q2), x);
    }
}
3.2.6. 出栈

        根据2.解题思路,代码如下:

int myStackPop(MyStack* obj) {
    assert(obj);

    //假设非空的队列为队列2
    Queue* emp = &(obj->q1);
    Queue* noemp = &(obj->q2);
    //如果队列2为空,就交换队列指针
    if(QueueEmpty(noemp))
    {
        emp = &(obj->q2);
        noemp = &(obj->q1);
    }

    //将非空队列前面的数据储存到另一个队列
    while(QueueSize(noemp) > 1)
    {
        int x = QueueFront(noemp);
        QueuePop(noemp);

        QueuePush(emp, x);
    }
    //记录最后一个队列并输出
    int ret = QueueFront(noemp);
    QueuePop(noemp);
    return ret;
}
3.2.7. 访问栈顶数据

        向非空的队列访问最后储存的数据,代码如下:

int myStackTop(MyStack* obj) {
    assert(obj);

    //如果队列1为空就访问队列1末尾
    if(QueueEmpty(&(obj->q1)))
    {
        return QueueBack(&(obj->q2));
    }
    else//反之访问队列2末尾
    {
        return QueueBack(&(obj->q1));
    }
}

3.3. 运行结果

        判题无误:

图1-3 队列模拟栈题解结果

二. 用栈实现队列

1. 题目描述

        请你仅使用两个栈实现先入先出队列。队列应当支持一般队列支持的所有操作(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) ,即使其中一个操作可能花费较长时间。

2. 解题思路

        用两个栈模拟队列的先进先出(First In First Out),因为栈只能从末尾读取数据,如果要像队列那样保持数据进入的顺序就需要找到队头数据,问题就相当于有两个杯子怎么喝到水杯底部的水。

        所以我们将栈分为入数据的栈和出数据的栈,需要入数据的时候就把出数据的栈的数据放到入数据的栈中然后入数据,反之亦然。如图2-1所示:

图2-1 栈模拟队列1

        这样每次进入数据都需要倒弄栈中的数据时间复杂度为O(N),那么如何降低时间复杂度呢?其实我们不难发现,没必要一直倒弄两个栈中的数据,如果出队列的时候出数据的栈没有数据在将数据倒入出栈栈即可。这样,入队列不需要把出栈的数据倒回去了。如图2-2所示:

图2-2 栈模拟队列2

3. 解题代码

        本题解法直接采用进阶解法。

3.1. 基础代码

        因为需要使用栈的结构,所以这里提供栈的相关代码:

#define INIT 4

// 支持动态增长的栈
typedef int STDataType;
typedef struct Stack
{
	STDataType* _a;
	int _top;		// 栈顶
	int _capacity;  // 容量 
}Stack;

// 初始化栈 
void StackInit(Stack* ps); 
// 入栈 
void StackPush(Stack* ps, STDataType data); 
// 出栈 
void StackPop(Stack* ps); 
// 获取栈顶元素 
STDataType StackTop(Stack* ps); 
// 获取栈中有效元素个数 
int StackSize(Stack* ps); 
// 检测栈是否为空,如果为空返回非零结果,如果不为空返回0 
bool StackEmpty(Stack* ps); 
// 销毁栈 
void StackDestroy(Stack* ps); 

// 初始化栈 
void StackInit(Stack* ps)
{
    assert(ps);
    STDataType* newnode = (STDataType*)malloc(sizeof(STDataType) * INIT);
    if(newnode == NULL)
    {
        perror("StackInit malloc fail");
        exit(1);
    }

    ps->_a = newnode;
    ps->_top = 0;
    ps->_capacity = INIT;
}

// 入栈 
void StackPush(Stack* ps, STDataType data)
{
    assert(ps);
    //容量不足扩容
    if(ps->_top == ps->_capacity)
    {
        STDataType* newnode = (STDataType*)realloc(ps->_a, sizeof(STDataType) * ps->_capacity * 2);
        if(newnode == NULL)
        {
            perror("StackInit malloc fail");
            exit(1);
        }

        ps->_a = newnode;
        ps->_capacity *= 2;
    }
    //入栈
    ps->_a[ps->_top] = data;
    ++ps->_top;
}

// 出栈 
void StackPop(Stack* ps)
{
    assert(ps);

    if(!StackEmpty(ps))
    {
        --ps->_top;
    }
}

// 获取栈顶元素 
STDataType StackTop(Stack* ps)
{
    assert(ps);

    return ps->_a[ps->_top - 1];//栈顶元素在top的上一位
}

// 获取栈中有效元素个数 
int StackSize(Stack* ps)
{
    return ps->_top;
}

// 检测栈是否为空,如果为空返回非零结果,如果不为空返回0 
bool StackEmpty(Stack* ps)
{
    assert(ps);

    return ps->_top == 0;
}

// 销毁栈 
void StackDestroy(Stack* ps)
{
    assert(ps);
    free(ps->_a);
    ps->_a = NULL;
    ps->_capacity = ps->_top = 0;
}

3.2. 题目要求的函数实现

3.2.1. 队列结构
typedef struct {
    Stack st_push;
    Stack st_pop;
} MyQueue;

3.2.2. 队列初始化

MyQueue* myQueueCreate() {
    //开辟队列结构的空间
    MyQueue* qu = (MyQueue*)malloc(sizeof(MyQueue));
    if(qu == NULL)
    {
        perror("malloc fail");
        return NULL;
    }
    //初始化两个栈
    StackInit(&(qu->st_pop));
    StackInit(&(qu->st_push));
    //返回队列空间指针
    return qu;
}
3.2.3. 销毁队列
void myQueueFree(MyQueue* obj) {
    //分别释放栈开辟的空间
    StackDestroy(&(obj->st_pop));
    StackDestroy(&(obj->st_push));
    //释放队列的空间
    free(obj);
}
3.2.4. 队列判空
bool myQueueEmpty(MyQueue* obj) {
    //两个栈都没数据,队列才为空
    return StackEmpty(&(obj->st_pop)) &&  StackEmpty(&(obj->st_push));
}
3.2.5. 队列入数据
void myQueuePush(MyQueue* obj, int x) {
    assert(obj);

    //记录入队列的栈指针,也可以不计,这里方便读者理解简化了
    Stack* _push = &(obj->st_push);
    //将数据录入入栈
    StackPush(_push, x);
}
3.2.6. 队列出数据
int myQueuePop(MyQueue* obj) {
    //记录入队列的栈指针,也可以不计,这里方便读者理解简化了
    Stack* _pop = &(obj->st_pop);
    Stack* _push = &(obj->st_push);

    //如果出数据的栈为空,就将入数据的栈中数据导入到出数据的栈
    if(StackEmpty(_pop))
    {
        while(!StackEmpty(_push))
        {
            int tmp = StackTop(_push);
            StackPop(_push);

            StackPush(_pop, tmp);
        }
    }
    //记录需要出队列的数据,删除并输出
    int ret = StackTop(_pop);
    StackPop(_pop);
    return ret;
}
3.2.7.  队列获取头数据

        直接从出数据的栈中获取栈顶元素,没有元素就将入数据栈中元素导入,代码如下:

int myQueuePeek(MyQueue* obj) {
    Stack* _pop = &(obj->st_pop);
    Stack* _push = &(obj->st_push);
    //如果出数据的栈为空,就将入数据的栈中数据导入到出数据的栈
    if(StackEmpty(_pop))
    {
        while(!StackEmpty(_push))
        {
            int tmp = StackTop(_push);
            StackPop(_push);

            StackPush(_pop, tmp);
        }
    }
    //输出出数据栈头数据
    int ret = StackTop(_pop);
    return ret;
}

3.3. 运行结果

        结果无误:

图2-3 栈模拟队列的结果

三. 设计循环队列

1. 题目描述

        设计你的循环队列实现。 循环队列是一种线性数据结构,其操作表现基于 FIFO(先进先出)原则并且队尾被连接在队首之后以形成一个循环。它也被称为“环形缓冲器”。

        循环队列的一个好处是我们可以利用这个队列之前用过的空间。在一个普通队列里,一旦一个队列满了,我们就不能插入下一个元素,即使在队列前面仍有空间。但是使用循环队列,我们能使用这些空间去存储新的值。

你的实现应该支持如下操作:

  • MyCircularQueue(k): 构造器,设置队列长度为 k 。
  • Front: 从队首获取元素。如果队列为空,返回 -1 。
  • Rear: 获取队尾元素。如果队列为空,返回 -1 。
  • enQueue(value): 向循环队列插入一个元素。如果成功插入则返回真。
  • deQueue(): 从循环队列中删除一个元素。如果成功删除则返回真。
  • isEmpty(): 检查循环队列是否为空。
  • isFull(): 检查循环队列是否已满。

示例:

MyCircularQueue circularQueue = new MyCircularQueue(3); // 设置长度为 3
circularQueue.enQueue(1);  // 返回 true
circularQueue.enQueue(2);  // 返回 true
circularQueue.enQueue(3);  // 返回 true
circularQueue.enQueue(4);  // 返回 false,队列已满
circularQueue.Rear();  // 返回 3
circularQueue.isFull();  // 返回 true
circularQueue.deQueue();  // 返回 true
circularQueue.enQueue(4);  // 返回 true
circularQueue.Rear();  // 返回 4

提示:

  • 所有的值都在 0 至 1000 的范围内;
  • 操作数将在 1 至 1000 的范围内;
  • 请不要使用内置的队列库。

2. 解题思路

2.1. 顺序表模拟

        如果用循序表模拟循环队列,则需要两个指针,指针一指向队列的头,一个指向数组的尾部。入数据从数组尾部进入,队列头用来删除数据,数组开辟的大小为顺序链表的容量。如果循环队列悟空用两个指针指向同一位置来表示,那么想要表示队列为满有两种方式:(1)在队列中增加一个变量记录数组中存在的数据个数。(2)开辟数组大小的时候多开一个空出的空间,那么数组为满的表示为尾指针加一等于头指针。

图3-1 顺序表模拟循环队列

2.2. 链表模拟

        如果用链表模拟就比较麻烦,需要先将链表的空间全部开好,那么剩下的各种操作与顺序表模拟循环队列相同。相比较起来,单向链表模拟如果需要读取队尾数据会比较麻烦,需要将尾指针遍历到尾指针之前的节点,所以使用双向链表模拟会更好,但是那从空间上来说不如顺序表模拟。如果找一个变量记录数据个数,插入的时候按照双向链表尾插,只是限制最后插入的节点个数未必不可行。

3. 解题代码

3.1. 题目要求的函数实现

        根据2.1.的解题思路。

3.1.1. 循环队列的结构
//定义存储数据的类型
typedef int QueueDataType;

typedef struct {
    QueueDataType* a; //顺序表位置
    int pcur;  //头指针
    int ptail; //尾指针
    int size;  //限制的循环队列大小
} MyCircularQueue;
3.1.2. 循环队列初始化

        包括开辟空间,各项指针置为0,记录队列容量,代码如下:

MyCircularQueue* myCircularQueueCreate(int k) {
    MyCircularQueue* cq = (MyCircularQueue*)malloc(sizeof(MyCircularQueue));
    if(cq == NULL)
    {
        perror("malloc fail");
        return NULL;
    }

    cq->a = (QueueDataType*)malloc(sizeof(QueueDataType) * (k + 1));
    cq->pcur = cq->ptail = 0;
    cq->size = k;
    return cq;
}
3.1.3. 判断队列是否为空
bool myCircularQueueIsEmpty(MyCircularQueue* obj) {
    assert(obj);
    return obj->ptail == obj->pcur;
}
3.1.4. 判断队列中数据是否满了

        向这总增加的都需要用总容量取模,防止溢出。

bool myCircularQueueIsFull(MyCircularQueue* obj) {
    assert(obj);
    return (obj->ptail + 1) % (obj->size + 1) == obj->pcur;
}
3.1.5. 向队列中增加数据
bool myCircularQueueEnQueue(MyCircularQueue* obj, int value) {
    assert(obj);
    //队列满员了就无法添加
    if(myCircularQueueIsFull(obj))
    {
        return false;
    }
    else
    {
        obj->a[obj->ptail++] = value;
        obj->ptail %= (obj->size + 1);
        return true;
    }
}
3.1.6. 从队列中删除数据
bool myCircularQueueDeQueue(MyCircularQueue* obj) {
    assert(obj);
    //如果队列为空则删除失败
    if(myCircularQueueIsEmpty(obj))
    {
        return false;
    }
    else
    {
        ++obj->pcur;
        obj->pcur %= (obj->size + 1);
        return true;
    }
}
3.1.7. 从队头获取数据
int myCircularQueueFront(MyCircularQueue* obj) {
    assert(obj);
    //队列为空返回-1
    if(myCircularQueueIsEmpty(obj))
    {
        return -1;
    }
    else//反之返回数据
    {
        return obj->a[obj->pcur];
    }
}
3.1.8. 从队尾获取数据
int myCircularQueueRear(MyCircularQueue* obj) {
    assert(obj);
    //为空返回-1
    if(myCircularQueueIsEmpty(obj))
    {
        return -1;
    }
    else//队尾指针-1+k+1最后取模得到后一位的地址
    {
        return obj->a[(obj->ptail + obj->size) % (obj->size + 1)];
    }
}

3.2. 运行结果

        结果无误:

图3-2 

作者结语

        虽然说代码能够解开谜题,但是用文本的方式真的很难把题目短时间说清楚。具体细节还需要读者自己体会,这里最多算是抛了一个砖。

        感谢大家看到这里,那也说明写博客的时间没有白费。

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

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

相关文章

蓝桥杯-线性动态规划问题背包问题进阶策略详解-

题目&#xff1a;蓝桥云课-青蛙吃虫 解题代码&#xff1a; #include <iostream> #include<cstring> #include<algorithm> using namespace std;const int N106;int f[N][N]; int a[N]; int t,l,r,k,n;int main() {cin>>t;while(t--){scanf("%d%…

FANUC机器人初始化系统的基本方法和步骤

FANUC机器人初始化系统的基本方法和步骤 首先,在做系统初始化之前,必须做好系统的备份,这里做个镜像备份,更详细的镜像备份步骤可参考以下链接中的内容: FANUC机器人进行全部备份和镜像备份以及加载备份文件的具体操作(图文) 如下图所示,在示教器右边的USB接口上插个…

Android finishInputEvent 流程分析

InputDispatcher将事件分发给应用程序后&#xff0c;将该event放入connection的wq队列中&#xff0c;APP处理完之后&#xff0c;需要发送一个完成的信号给InputDispatcher&#xff0c;以供InputDispatcher来将该event从wq队列中移除。我们来分析这个过程。 我们知道&#xff0…

图文详解:synchronized关键字 及其底层原理

目录 一.线程安全问题 二.synchronized关键字 ▐ synchronized图解 ▐ 可重入锁及图解 ▐ synchronized用于方法上 三.Java标准库中synchronized的使用 四.synchronized的底层实现原理 一.线程安全问题 线程安全是指在多线程环境下&#xff0c;对共享资源的访问不会导致…

【数轮】数论、质数、最大公约数、菲蜀定理

数学 唯一分解定理 n>2都可以表示为质因数的乘方。 令 n a1b1a2b2 … \dots … a1,b1 … \dots …都是质因数&#xff0c;b1,b2 … \dots …是对应质因数的数量。 调和级数 11/2 1/3 1/4 ⋯ \cdots ⋯ 1/ n 约等于 logn。 证明过程&#xff1a; 1/3 1/4 < (1/2) …

程序员最趁手的SVM算法,学完你会哭着感谢努力的自己!下篇.

支持向量机上篇内容更重要。 上篇地址&#xff1a;程序员最趁手的SVM算法&#xff0c;学完你会哭着感谢努力的自己&#xff01;上篇。-CSDN博客 废话不说直接进入主题&#xff1a; 6核贝叶斯支持向量机 核贝叶斯支持向量机通过学习一些已知的例子&#xff0c;并找到一个特殊…

【0DAY】湖南建研工程质量检测系统Download接口处存在任意文件读取漏洞

免责声明&#xff1a;文章来源互联网收集整理&#xff0c;请勿利用文章内的相关技术从事非法测试&#xff0c;由于传播、利用此文所提供的信息或者工具而造成的任何直接或者间接的后果及损失&#xff0c;均由使用者本人负责&#xff0c;所产生的一切不良后果与文章作者无关。该…

赋能数据库智能托管,Akamai 发布首款云计算业务线产品!

为了尽可能地简化数据库管理的复杂性&#xff0c;降低数据库成本&#xff0c;Akamai 在近期推出了首款 DBaaS&#xff08;数据库即服务&#xff09;产品——Linode Managed Database。这一数据库产品是 Akamai 自3月份收购 Linode 后发布的首款计算业务线产品。 一、更易用的数…

ipa 分区算法分析,图解

参考 Room Segmentation: Survey, Implementation, and Analysis. 分区算法调查&#xff0c;实现以及评估对比 相关论文 分区算法 New Brooms Sweep Clean - An Autonomous Robotic Cleaning Assistant for Professional Office Cleaning 形态分割 Interactive SLAM using …

EPICS database练习

给定一个以下的数据库&#xff1a; # 指定Limit的上限&#xff0c;初始为10&#xff0c;可以通过通道访问进行设置&#xff0c;上限为100 record(ao, "$(P)Limit") { field(DRVH, "100") field(DOL, "10") field(PINI, "YES") }# 一个…

vue3中的computed

一.computed用法 computed 计算属性就是当依赖的属性的值发生变化的时候&#xff0c;才会触发他的更改&#xff1b;如果依赖的值&#xff0c;不发生变化的时候&#xff0c;使用的是缓存中的属性值。 computed 属性是 Vue3 中的一个响应式计算属性&#xff0c;它可以根据其他响应…

谷歌Flank潜藏3年的Github Action供应链攻击

01 简 介 Flank [1] 是谷歌 Firebase Test lab 开源在 Github 的一个项目&#xff0c;用于同时对多个安卓和IOS设备进行测试。2024年4月15号 AWS 安全工程师 Adnan Khan 公布了关于该项目代码仓库 Github Action CI/CD 存在漏洞的细节[2]&#xff0c;漏洞在2020年于此 代码合…

LabVIEW二维码生成与识别

LabVIEW二维码生成与识别 随着数字化时代的快速发展&#xff0c;QR二维码作为一种高效的信息传递和识别手段&#xff0c;已广泛应用于各行各业。利用LabVIEW软件及其NI视觉开发模块(VDM)来实现一个高效的QR二维码生成与识别系统。该系统不仅能够快速生成带有自定义信息的二维码…

未授权访问:VNC未授权访问

目录 1、漏洞原理 2、环境搭建 3、未授权访问 防御手段 今天继续学习各种未授权访问的知识和相关的实操实验&#xff0c;一共有好多篇&#xff0c;内容主要是参考先知社区的一位大佬的关于未授权访问的好文章&#xff0c;还有其他大佬总结好的文章&#xff1a; 这里附上大…

C++的数据结构(五):树和存储结构及示例

在计算机科学中&#xff0c;树是一种抽象数据类型&#xff08;ADT&#xff09;或是实现这种抽象数据类型的数据结构&#xff0c;用来模拟具有树状结构性质的数据集合。这种数据结构以一系列连接的节点来形成树形结构。在C中&#xff0c;树的概念和存储结构是实现各种复杂算法和…

如何利用AI提高内容生产效率与AIGC典型案例分析

❤️❤️❤️ 欢迎来到我的博客。希望您能在这里找到既有价值又有趣的内容&#xff0c;和我一起探索、学习和成长。欢迎评论区畅所欲言、享受知识的乐趣&#xff01; 推荐&#xff1a;数据分析螺丝钉的首页 格物致知 终身学习 期待您的关注 导航&#xff1a; LeetCode解锁100…

DI-engine强化学习入门(八)如何高效构建决策环境

本文章将介绍 DI-engine 中用于高效构建和标准化不同类型决策环境的系列工具&#xff0c;从而方便我们将各式各样的原始决策问题转化为适合使用强化学习方法解决的形式。 前言 对于“决策环境复杂性”的问题&#xff0c;这里描述的是在强化学习&#xff08;RL&#xff09;领域…

torch 单机 多卡 训练(二)

pytorch.distributed.launch和torchrun的对比 多卡训练 真的烦 并行训练最大的好处&#xff0c;在于GPU内存变大&#xff0c;不是变快 torch.distributed.launch CUDA_VISIBLE_DEVICES0,1,2,3 python -m torch.distributed.launch --nproc_per_node4 --nnodes1 --use_env k…

获取Linux上的Redis的用户名、密码、端口、host等信息

目录 进入redis-cli的目录 启动./redis-cli服务 查询密码 查询用户名 查询端口 查询host 参考文章&#xff1a;解决redis-cli连接时出现Could not connect to Redis at 127.0.0.1:6379: Connection refused-阿里云开发者社区 (aliyun.com) linux查看redis用户和密码_mo…

最新版★重大升级★神点云连锁餐饮V2独立版点餐系统★公众号/h5/小程序前后端全套源码

提醒&#xff1a; 市场上流通很多老版本代码&#xff0c;一大堆问题且无法保证售后的源码&#xff0c;请各位买家一定要睁大眼睛&#xff0c;以防上当受骗&#xff01;&#xff01;&#xff01;本系统源码全是经本人亲自测试与修复的完好版本&#xff0c;且本人用此版本源码已…