队列的实现和OJ练习

目录

概念

队列的实现

利用结构体存放队列结构

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

初始化队列

小提示:

队尾入队列

队头出队列

获取队头元素

获取队尾元素

获取队列中有效元素个数

检测队列是否为空

销毁队列

最终代码

循环队列 

队列的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/152590.shtml

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

相关文章

MobaXterm如何连接CentOS7的Linux虚拟机?Redis可视化客户端工具如何连接Linux版Redis?

一、打开Lunix虚拟机,进入虚拟机中,在终端中输入ifconfig,得到以下信息&#xff0c;红框中为ip地址 二、打开MobaXterm&#xff0c;点击session 选择SSH&#xff0c;在Remote host中输入linux得到的IP地址&#xff0c;Specify username中可起一个任意的连接名称。 输入密码 四、…

【洛谷 P3743】kotori的设备 题解(二分答案+递归)

kotori的设备 题目背景 kotori 有 n n n 个可同时使用的设备。 题目描述 第 i i i 个设备每秒消耗 a i a_i ai​ 个单位能量。能量的使用是连续的&#xff0c;也就是说能量不是某时刻突然消耗的&#xff0c;而是匀速消耗。也就是说&#xff0c;对于任意实数&#xff0c;…

60 权限提升-MYMSORA等SQL数据库提权

目录 数据库应用提权在权限提升中的意义WEB或本地环境如何探针数据库应用数据库提权权限用户密码收集等方法目前数据库提权对应的技术及方法等 演示案例Mysql数据库提权演示-脚本&MSF1.UDF提权知识点: (基于MYSQL调用命令执行函数&#xff09;读取数据库存储或备份文件 (了…

GaussDB新特性Ustore存储引擎介绍

1、 Ustore和Astore存储引擎介绍 Ustore存储引擎&#xff0c;又名In-place Update存储引擎&#xff08;原地更新&#xff09;&#xff0c;是openGauss 内核新增的一种存储模式。此前的版本使用的行存储引擎是Append Update&#xff08;追加更新&#xff09;模式。相比于Append…

在网络攻击之前、期间和之后应采取的步骤

在当今复杂的威胁形势下&#xff0c;网络攻击是不可避免的。 恶意行为者变得越来越复杂&#xff0c;出于经济动机的攻击变得越来越普遍&#xff0c;并且每天都会发现新的恶意软件系列。 这使得对于各种规模和跨行业的组织来说&#xff0c;制定适当的攻击计划变得更加重要。 …

【Linux】进程间通信 -- 管道

对于进程间通信的理解 首先&#xff0c;进程间通信的本质是&#xff0c;让不同的进程看到同一份资源&#xff08;这份资源不能隶属于任何一个进程&#xff0c;即应该是共享的&#xff09;。而进程间通信的目的是为了实现多进程之间的协同。 但由于进程运行具有独立性&#xff…

密码加密解密之路

1.背景 做数据采集&#xff0c;客户需要把他们那边的数据库连接信息存到我们系统里&#xff0c;那我们系统就要尽可能的保证这部分数据安全&#xff0c;不被盗。 2.我的思路 1.需要加密的地方有两处&#xff0c;一个是新增的时候前端传给后端的时候&#xff0c;一个是存到数…

异步爬取+多线程+redis构建一个运转丝滑且免费http-ip代理池 (三)

内容提要: 如果说,爬取网页数据的时候,我们使用了异步,那么将数据放入redis里面,其实也需要进行异步;当然,如果使用多线程或者redis线程池技术也是可以的,但那会造成冗余; 因此,在测试完多线程redis搭配异步爬虫的时候,我发现效率直接在redis这里被无限拉低下来! 因此: 最终的r…

从0开始学习JavaScript--JavaScript中的集合类

JavaScript中的集合类是处理数据的关键&#xff0c;涵盖了数组、Set、Map等多种数据结构。本文将深入研究这些集合类的创建、操作&#xff0c;以及实际应用场景&#xff0c;并通过丰富的示例代码&#xff0c;帮助大家更全面地了解和应用这些概念。 数组&#xff08;Array&…

SystemVerilog学习 (11)——覆盖率

目录 一、概述 二、覆盖率的种类 1、概述 2、分类 三、代码覆盖率 四、功能覆盖率 五、从功能描述到覆盖率 一、概述 “验证如果没有量化&#xff0c;那么就意味着没有尽头。” 伴随着复杂SoC系统的验证难度系数成倍增加&#xff0c;无论是定向测试还是随机测试&#xff…

安全框架springSecurity+Jwt+Vue-1(vue环境搭建、动态路由、动态标签页)

一、安装vue环境&#xff0c;并新建Vue项目 ①&#xff1a;安装node.js 官网(https://nodejs.org/zh-cn/) 2.安装完成之后检查下版本信息&#xff1a; ②&#xff1a;创建vue项目 1.接下来&#xff0c;我们安装vue的环境 # 安装淘宝npm npm install -g cnpm --registryhttps:/…

软件测试/测试开发/人工智能丨基于Spark的分布式造数工具:加速大规模测试数据构建

随着软件开发规模的扩大&#xff0c;测试数据的构建变得越来越复杂&#xff0c;传统的造数方法难以应对大规模数据需求。本文将介绍如何使用Apache Spark构建分布式造数工具&#xff0c;以提升测试数据构建的效率和规模。 为什么选择Spark&#xff1f; 分布式计算&#xff1a;…

easyExcel注解详情

前言11个注解字段注解 类注解基础综合示例补充颜色总结 11个注解 ExcelProperty ColumnWith 列宽 ContentFontStyle 文本字体样式 ContentLoopMerge 文本合并 ContentRowHeight 文本行高度 ContentStyle 文本样式 HeadFontStyle 标题字体样式 HeadRowHeight 标题高度 HeadStyle…

Python将原始数据集和标注文件进行数据增强(随机仿射变换),并生成随机仿射变换的数据集和标注文件

Python将原始数据集和标注文件进行数据增强&#xff08;随机仿射变换&#xff09;&#xff0c;并生成随机仿射变换的数据集和标注文件 前言前提条件相关介绍实验环境生成随机仿射变换的数据集和标注文件代码实现输出结果 前言 由于本人水平有限&#xff0c;难免出现错漏&#x…

OpenCV快速入门:图像滤波与边缘检测

文章目录 前言一、噪声种类与生成1.1 椒盐噪声1.2 高斯噪声1.3 彩色噪声 二、卷积操作2.1 卷积基本原理2.2 卷积操作代码实现 三、线性滤波3.1 均值滤波均值滤波原理均值滤波公式均值滤波代码实现 3.2 方框滤波方框滤波原理方框滤波公式方框滤波代码实现 3.3 高斯滤波高斯滤波原…

redis非关系型数据库(缓存型数据库)——中间件

【重点】redis为什么这么快&#xff1f;&#xff08;应届&#xff09; ①redis是纯内存结构&#xff0c;避免磁盘I/O的耗时 ②redis核心模块是一个单进程&#xff0c;减少线程切换和回收线程资源时间 ③redis采用的是I/O的多路复用机制&#xff08;每一个执行线路可以同时完…

npm install 下载不下来依赖解决方案

背景 最近在构建 前端自动化部署 的方案中发现了一个问题&#xff0c;就是我在npm install的时候&#xff0c;有时候成功&#xff0c;有时候不成功&#xff0c;而且什么代码也没发生更改&#xff0c;报错也就是那么几个错&#xff0c;所以在此也整理了一下遇到这种情况&#xf…

如何使用 WPF 应用程序连接 FastReport报表

随着期待已久的FastReport WPF的发布&#xff0c;您不再需要使用 FastReport .NET 来处理基于 WPF 的项目。 不久前&#xff0c;在 FastReport .NET 中使用 WPF 还相当不方便。并非一切都进展顺利&#xff1b;连接 FastReport.dll 和许多其他问题存在问题。我们重新思考了该方…

2023年中职“网络安全“—Web 渗透测试①

2023年中职"网络安全"—Web 渗透测试① Web 渗透测试任务环境说明&#xff1a;1.访问地址http://靶机IP/task1&#xff0c;分析页面内容&#xff0c;获取flag值&#xff0c;Flag格式为flag{xxx}&#xff1b;2.访问地址http://靶机IP/task2&#xff0c;访问登录页面。…

面试题c/c++--语言基础

一 、语言基础 1.1 指针 野指针&#xff1a;指针指向的位置是不可知的 悬空指针&#xff1a;指针最初指向的内存已经被释放了的一种指针 两种指针都指向无效内存空间&#xff0c; 即不安全不可控 。需要在定义指针后且在使用之前完成初始化或者使用 智能指针来避免 智能指针 智…